~ubuntu-branches/debian/stretch/alpine/stretch

« back to all changes in this revision

Viewing changes to pico/composer.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: composer.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
 * Program:     Pine composer routines
 
18
 *
 
19
 * NOTES:
 
20
 *
 
21
 *  - composer.c is the composer for the PINE mail system
 
22
 *
 
23
 *  - tabled 01/19/90
 
24
 *
 
25
 *  Notes: These routines aren't incorporated yet, because the composer as
 
26
 *         a whole still needs development.  These are ideas that should
 
27
 *         be implemented in later releases of PINE.  See the notes in 
 
28
 *         pico.c concerning what needs to be done ....
 
29
 *
 
30
 *  - untabled 01/30/90
 
31
 *
 
32
 *  Notes: Installed header line editing, with wrapping and unwrapping, 
 
33
 *         context sensitive help, and other mail header editing features.
 
34
 *
 
35
 *  - finalish code cleanup 07/15/91
 
36
 * 
 
37
 *  Notes: Killed/yanked header lines use emacs kill buffer.
 
38
 *         Arbitrarily large headers are handled gracefully.
 
39
 *         All formatting handled by FormatLines.
 
40
 *
 
41
 *  - Work done to optimize display painting 06/26/92
 
42
 *         Not as clean as it should be, needs more thought 
 
43
 *
 
44
 */
 
45
#include "headers.h"
 
46
 
 
47
#include "osdep/terminal.h"
 
48
 
 
49
int              InitEntryText(char *, struct headerentry *);
 
50
int              HeaderOffset(int);
 
51
int              HeaderFocus(int, int);
 
52
UCS              LineEdit(int);
 
53
int              header_downline(int, int);
 
54
int              header_upline(int);
 
55
int              FormatLines(struct hdr_line *, char *, int, int, int);
 
56
int              FormatSyncAttach(void);
 
57
UCS             *ucs4_strqchr(UCS *, UCS, int *, int);
 
58
int              ComposerHelp(int);
 
59
void             NewTop(int);
 
60
void             display_delimiter(int);
 
61
void             zotentry(struct hdr_line *);
 
62
int              InvertPrompt(int, int);
 
63
int              partial_entries(void);
 
64
int              physical_line(struct hdr_line *);
 
65
int              strend(UCS *, UCS);
 
66
int              KillHeaderLine(struct hdr_line *, int);
 
67
int              SaveHeaderLines(void);
 
68
UCS             *break_point(UCS *, int, UCS, int *);
 
69
int              hldelete(struct hdr_line *);
 
70
int              is_blank(int, int, int);
 
71
int              zotcomma(UCS *);
 
72
struct hdr_line *first_hline(int *);
 
73
struct hdr_line *first_sel_hline(int *);
 
74
struct hdr_line *next_hline(int *, struct hdr_line *);
 
75
struct hdr_line *next_sel_hline(int *, struct hdr_line *);
 
76
struct hdr_line *prev_hline(int *, struct hdr_line *);
 
77
struct hdr_line *prev_sel_hline(int *, struct hdr_line *);
 
78
struct hdr_line *first_requested_hline(int *);
 
79
void             fix_mangle_and_err(int *, char **, char *);
 
80
 
 
81
 
 
82
/*
 
83
 * definition header field array, structures defined in pico.h
 
84
 */
 
85
struct headerentry *headents;
 
86
 
 
87
 
 
88
/*
 
89
 * structure that keeps track of the range of header lines that are
 
90
 * to be displayed and other fun stuff about the header
 
91
 */
 
92
struct on_display ods;                          /* global on_display struct */
 
93
 
 
94
 
 
95
/*
 
96
 * useful macros
 
97
 */
 
98
#define HALLOC()        (struct hdr_line *)malloc(sizeof(struct hdr_line))
 
99
#define LINEWID()       (term.t_ncol - headents[ods.cur_e].prwid)
 
100
#define BOTTOM()        (term.t_nrow - term.t_mrow)
 
101
#define FULL_SCR()      (BOTTOM() - 3)
 
102
#define HALF_SCR()      (FULL_SCR()/2)
 
103
 
 
104
#ifdef  MOUSE
 
105
/*
 
106
 * Redefine HeaderEditor to install wrapper required for mouse event
 
107
 * handling...
 
108
 */
 
109
#define HeaderEditor    HeaderEditorWork
 
110
#endif /* MOUSE */
 
111
 
 
112
#define HDR_DELIM       "----- Message Text -----"
 
113
 
 
114
/*
 
115
 * useful declarations
 
116
 */
 
117
static short delim_ps  = 0;             /* previous state */
 
118
static short invert_ps = 0;             /* previous state */
 
119
 
 
120
 
 
121
static KEYMENU menu_header[] = {
 
122
    /* TRANSLATORS: command key labels, Send means send the message
 
123
       we are currently working on. */
 
124
    {"^G", N_("Get Help"), KS_SCREENHELP},      {"^X", N_("Send"), KS_SEND},
 
125
    /* TRANSLATORS: Rich Headers is a command to display more headers. It
 
126
       is triggered with the ^R key. PrvPg stands for Previous Page. */
 
127
    {"^R", N_("Rich Hdr"), KS_RICHHDR}, {"^Y", N_("PrvPg/Top"), KS_PREVPAGE},
 
128
    /* TRANSLATORS: Cut Line means remove a line. Postpone means to save
 
129
       a message being composed so that it can be worked on later. */
 
130
    {"^K", N_("Cut Line"), KS_CURPOSITION},     {"^O", N_("Postpone"), KS_POSTPONE},
 
131
    /* TRANSLATORS: Del Char is Delete Character */
 
132
    {"^C", N_("Cancel"), KS_CANCEL},    {"^D", N_("Del Char"), KS_NONE},
 
133
    /* TRANSLATORS: Next Page */
 
134
    {"^J", N_("Attach"), KS_ATTACH},    {"^V", N_("NxtPg/End"), KS_NEXTPAGE},
 
135
    /* TRANSLATORS: Undelete a line that was just deleted */
 
136
    {"^U", N_("UnDel Line"), KS_NONE},  {NULL, NULL}
 
137
};
 
138
#define SEND_KEY        1
 
139
#define RICH_KEY        2
 
140
#define CUT_KEY         4
 
141
#define PONE_KEY        5
 
142
#define DEL_KEY         7
 
143
#define ATT_KEY         8
 
144
#define UDEL_KEY        10
 
145
#define TO_KEY          11
 
146
 
 
147
 
 
148
/*
 
149
 * function key mappings for header editor
 
150
 */
 
151
static UCS ckm[12][2] = {
 
152
    { F1,  (CTRL|'G')},
 
153
    { F2,  (CTRL|'C')},
 
154
    { F3,  (CTRL|'X')},
 
155
    { F4,  (CTRL|'D')},
 
156
    { F5,  (CTRL|'R')},
 
157
    { F6,  (CTRL|'J')},
 
158
    { F7,  0 },
 
159
    { F8,  0 },
 
160
    { F9,  (CTRL|'K')},
 
161
    { F10, (CTRL|'U')},
 
162
    { F11, (CTRL|'O')},
 
163
    { F12, (CTRL|'T')}
 
164
};
 
165
 
 
166
 
 
167
/*
 
168
 * InitMailHeader - initialize header array, and set beginning editor row 
 
169
 *                  range.  The header entry structure should look just like 
 
170
 *                  what is written on the screen, the vector 
 
171
 *                  (entry, line, offset) will describe the current cursor 
 
172
 *                  position in the header.
 
173
 *
 
174
 *         Returns: TRUE if special header handling was requested,
 
175
 *                  FALSE under standard default behavior.
 
176
 */
 
177
int
 
178
InitMailHeader(PICO *mp)
 
179
{
 
180
    char               *addrbuf;
 
181
    struct headerentry *he;
 
182
    int                 rv;
 
183
 
 
184
    if(!mp->headents){
 
185
        headents = NULL;
 
186
        return(FALSE);
 
187
    }
 
188
 
 
189
    /*
 
190
     * initialize some of on_display structure, others below...
 
191
     */
 
192
    ods.p_ind  = 0;
 
193
    ods.p_line = COMPOSER_TOP_LINE;
 
194
    ods.top_l = ods.cur_l = NULL;
 
195
 
 
196
    headents = mp->headents;
 
197
    /*--- initialize the fields in the headerent structure ----*/
 
198
    for(he = headents; he->name != NULL; he++){
 
199
        he->hd_text    = NULL;
 
200
        he->display_it = he->display_it ? he->display_it : !he->rich_header;
 
201
        if(he->is_attach) {
 
202
            /*--- A lot of work to do since attachments are special ---*/
 
203
            he->maxlen = 0;
 
204
            if(mp->attachments != NULL){
 
205
                char   buf[NLINE];
 
206
                int    attno = 0;
 
207
                int    l1, ofp, ofp1, ofp2;  /* OverFlowProtection */
 
208
                size_t addrbuflen = 4 * NLINE; /* malloc()ed size of addrbuf */
 
209
                PATMT *ap = mp->attachments;
 
210
 
 
211
                ofp = NLINE - 35;
 
212
 
 
213
                addrbuf = (char *)malloc(addrbuflen);
 
214
                addrbuf[0] = '\0';
 
215
                buf[0] = '\0';
 
216
                while(ap){
 
217
                  if((l1 = strlen(ap->filename)) <= ofp){
 
218
                      ofp1 = l1;
 
219
                      ofp2 = ofp - l1;
 
220
                  }
 
221
                  else{
 
222
                      ofp1 = ofp;
 
223
                      ofp2 = 0;
 
224
                  }
 
225
 
 
226
                  if(ap->filename){
 
227
                     snprintf(buf, sizeof(buf), "%d. %.*s%s %s%s%s\"",
 
228
                             ++attno,
 
229
                             ofp1,
 
230
                             ap->filename,
 
231
                             (l1 > ofp) ? "...]" : "",
 
232
                             ap->size ? "(" : "",
 
233
                             ap->size ? ap->size : "",
 
234
                             ap->size ? ") " : "");
 
235
 
 
236
                     /* append description, escaping quotes */
 
237
                     if(ap->description){
 
238
                         char *dp = ap->description, *bufp = &buf[strlen(buf)];
 
239
                         int   escaped = 0;
 
240
 
 
241
                         do
 
242
                           if(*dp == '\"' && !escaped){
 
243
                               *bufp++ = '\\';
 
244
                               ofp2--;
 
245
                           }
 
246
                           else if(escaped){
 
247
                               *bufp++ = '\\';
 
248
                               escaped = 0;
 
249
                           }
 
250
                         while(--ofp2 > 0 && (*bufp++ = *dp++));
 
251
 
 
252
                         *bufp = '\0';
 
253
                     }
 
254
 
 
255
                     snprintf(buf + strlen(buf), sizeof(buf)-strlen(buf), "\"%s", ap->next ? "," : "");
 
256
 
 
257
                     if(strlen(addrbuf) + strlen(buf) >= addrbuflen){
 
258
                         addrbuflen += NLINE * 4;
 
259
                         if(!(addrbuf = (char *)realloc(addrbuf, addrbuflen))){
 
260
                             emlwrite("\007Can't realloc addrbuf to %d bytes",
 
261
                                      (void *) addrbuflen);
 
262
                             return(ABORT);
 
263
                         }
 
264
                     }
 
265
 
 
266
                     strncat(addrbuf, buf, addrbuflen-strlen(addrbuf));
 
267
                     addrbuf[addrbuflen-1] = '\0';
 
268
                 }
 
269
                 ap = ap->next;
 
270
                }
 
271
                InitEntryText(addrbuf, he);
 
272
                free((char *)addrbuf);
 
273
            } else {
 
274
                InitEntryText("", he);
 
275
            }
 
276
            he->realaddr = NULL;
 
277
        } else {
 
278
            if(!he->blank)
 
279
              addrbuf = *(he->realaddr);
 
280
            else
 
281
              addrbuf = "";
 
282
 
 
283
            InitEntryText(addrbuf, he);
 
284
        }
 
285
    }
 
286
 
 
287
    /*
 
288
     * finish initialization and then figure out display layout.
 
289
     * first, look for any field the caller requested we start in,
 
290
     * and set the offset into that field.
 
291
     */
 
292
    if(ods.cur_l = first_requested_hline(&ods.cur_e)){
 
293
        ods.top_e = 0;                          /* init top_e */
 
294
        ods.top_l = first_hline(&ods.top_e);
 
295
        if(!HeaderFocus(ods.cur_e, Pmaster ? Pmaster->edit_offset : 0))
 
296
          HeaderFocus(ods.cur_e, 0);
 
297
 
 
298
        rv = TRUE;
 
299
    }
 
300
    else{
 
301
        ods.top_l = first_hline(&ods.cur_e);
 
302
        ods.cur_l = first_sel_hline(&ods.cur_e);
 
303
        ods.top_e = ods.cur_e;
 
304
        rv = 0;
 
305
    }
 
306
 
 
307
    UpdateHeader(0);
 
308
    return(rv);
 
309
}
 
310
 
 
311
 
 
312
 
 
313
/*
 
314
 * InitEntryText - Add the given header text into the header entry 
 
315
 *                 line structure.
 
316
 */
 
317
int
 
318
InitEntryText(char *utf8text, struct headerentry *e)
 
319
{
 
320
    struct  hdr_line    *curline;
 
321
    register  int       longest;
 
322
 
 
323
    /*
 
324
     * get first chunk of memory, and tie it to structure...
 
325
     */
 
326
    if((curline = HALLOC()) == NULL){
 
327
        emlwrite("Unable to make room for full Header.", NULL);
 
328
        return(FALSE);
 
329
    }
 
330
 
 
331
    longest = term.t_ncol - e->prwid - 1;
 
332
    curline->text[0] = '\0';
 
333
    curline->next = NULL;
 
334
    curline->prev = NULL;
 
335
    e->hd_text = curline;               /* tie it into the list */
 
336
 
 
337
    if(FormatLines(curline, utf8text, longest, e->break_on_comma, 0) == -1)
 
338
      return(FALSE);
 
339
    else
 
340
      return(TRUE);
 
341
}
 
342
 
 
343
 
 
344
 
 
345
/*
 
346
 *  ResizeHeader - Handle resizing display when SIGWINCH received.
 
347
 *
 
348
 *      notes:
 
349
 *              works OK, but needs thorough testing
 
350
 *                
 
351
 */
 
352
int
 
353
ResizeHeader(void)
 
354
{
 
355
    register struct headerentry *i;
 
356
    register int offset;
 
357
 
 
358
    if(!headents)
 
359
      return(TRUE);
 
360
 
 
361
    offset = (ComposerEditing) ? HeaderOffset(ods.cur_e) : 0;
 
362
 
 
363
    for(i=headents; i->name; i++){              /* format each entry */
 
364
        if(FormatLines(i->hd_text, "", (term.t_ncol - i->prwid),
 
365
                       i->break_on_comma, 0) == -1){
 
366
            return(-1);
 
367
        }
 
368
    }
 
369
 
 
370
    if(ComposerEditing)                         /* restart at the top */
 
371
      HeaderFocus(ods.cur_e, offset);           /* fix cur_l and p_ind */
 
372
    else {
 
373
      struct hdr_line *l;
 
374
      int              e;
 
375
 
 
376
      for(i = headents; i->name != NULL; i++);  /* Find last line */
 
377
      i--;
 
378
      e = i - headents;
 
379
      l = headents[e].hd_text;
 
380
      if(!headents[e].display_it || headents[e].blank)
 
381
        l = prev_sel_hline(&e, l);              /* last selectable line */
 
382
 
 
383
      if(!l){
 
384
          e = i - headents;
 
385
          l = headents[e].hd_text;
 
386
      }
 
387
 
 
388
      HeaderFocus(e, -1);               /* put focus on last line */
 
389
    }
 
390
 
 
391
    if(ComposerTopLine != COMPOSER_TOP_LINE)
 
392
      UpdateHeader(0);
 
393
 
 
394
    PaintBody(0);
 
395
 
 
396
    if(ComposerEditing)
 
397
      movecursor(ods.p_line, ods.p_ind+headents[ods.cur_e].prwid);
 
398
 
 
399
    (*term.t_flush)();
 
400
    return(TRUE);
 
401
}
 
402
 
 
403
 
 
404
 
 
405
/*
 
406
 * HeaderOffset - return the character offset into the given header
 
407
 */
 
408
int
 
409
HeaderOffset(int h)
 
410
{
 
411
    register struct hdr_line *l;
 
412
    int      i = 0;
 
413
 
 
414
    l = headents[h].hd_text;
 
415
 
 
416
    while(l != ods.cur_l){
 
417
        i += ucs4_strlen(l->text);
 
418
        l = l->next;
 
419
    }
 
420
    return(i+ods.p_ind);
 
421
}
 
422
 
 
423
 
 
424
 
 
425
/*
 
426
 * HeaderFocus - put the dot at the given offset into the given header
 
427
 */
 
428
int
 
429
HeaderFocus(int h, int offset)
 
430
{
 
431
    register struct hdr_line *l;
 
432
    register int    i;
 
433
    int      last = 0;
 
434
 
 
435
    if(offset == -1)                            /* focus on last line */
 
436
      last = 1;
 
437
 
 
438
    l = headents[h].hd_text;
 
439
    while(1){
 
440
        if(last && l->next == NULL){
 
441
            break;
 
442
        }
 
443
        else{
 
444
            if((i=ucs4_strlen(l->text)) >= offset)
 
445
              break;
 
446
            else
 
447
              offset -= i;
 
448
        }
 
449
        if((l = l->next) == NULL)
 
450
          return(FALSE);
 
451
    }
 
452
 
 
453
    ods.cur_l = l;
 
454
    ods.p_len = ucs4_strlen(l->text);
 
455
    ods.p_ind = (last) ? 0 : offset;
 
456
 
 
457
    return(TRUE);
 
458
}
 
459
 
 
460
 
 
461
 
 
462
/*
 
463
 * HeaderEditor() - edit the mail header field by field, trapping 
 
464
 *                  important key sequences, hand the hard work off
 
465
 *                  to LineEdit().  
 
466
 *      returns:
 
467
 *              -3    if we drop out bottom *and* want to process mouse event
 
468
 *              -1    if we drop out the bottom 
 
469
 *              FALSE if editing is cancelled
 
470
 *              TRUE  if editing is finished
 
471
 */
 
472
int
 
473
HeaderEditor(int f, int n)
 
474
{
 
475
    register  int       i;
 
476
    UCS                 ch;
 
477
    register  char      *bufp;
 
478
    struct headerentry *h;
 
479
    int                 cur_e, mangled, retval = -1,
 
480
                        hdr_only = (gmode & MDHDRONLY) ? 1 : 0;
 
481
    char               *errmss, *err;
 
482
#ifdef MOUSE
 
483
    MOUSEPRESS          mp;
 
484
#endif
 
485
 
 
486
    if(!headents)
 
487
      return(TRUE);                             /* nothing to edit! */
 
488
 
 
489
    ComposerEditing = TRUE;
 
490
    display_delimiter(0);                       /* provide feedback */
 
491
 
 
492
#ifdef  _WINDOWS
 
493
    mswin_setscrollrange (0, 0);
 
494
#endif /* _WINDOWS */
 
495
 
 
496
    /* 
 
497
     * Decide where to begin editing.  if f == TRUE begin editing
 
498
     * at the bottom.  this case results from the cursor backing
 
499
     * into the editor from the bottom.  otherwise, the user explicitly
 
500
     * requested editing the header, and we begin at the top.
 
501
     * 
 
502
     * further, if f == 1, we moved into the header by hitting the up arrow
 
503
     * in the message text, else if f == 2, we moved into the header by
 
504
     * moving past the left edge of the top line in the message.  so, make 
 
505
     * the end of the last line of the last entry the current cursor position
 
506
     * lastly, if f == 3, we moved into the header by hitting backpage() on
 
507
     * the top line of the message, so scroll a page back.  
 
508
     */
 
509
    if(f){
 
510
        if(f == 2){                             /* 2 leaves cursor at end  */
 
511
            struct hdr_line *l = ods.cur_l;
 
512
            int              e = ods.cur_e;
 
513
 
 
514
            /*--- make sure on last field ---*/
 
515
            while(l = next_sel_hline(&e, l))
 
516
              if(headents[ods.cur_e].display_it){
 
517
                  ods.cur_l = l;
 
518
                  ods.cur_e = e;
 
519
              }
 
520
 
 
521
            ods.p_ind = 1000;                   /* and make sure at EOL    */
 
522
        }
 
523
        else{
 
524
            /*
 
525
             * note: assumes that ods.cur_e and ods.cur_l haven't changed
 
526
             *       since we left...
 
527
             */
 
528
 
 
529
            /* fix postition */
 
530
            if(curwp->w_doto < headents[ods.cur_e].prwid)
 
531
              ods.p_ind = 0;
 
532
            else if(curwp->w_doto < ods.p_ind + headents[ods.cur_e].prwid)
 
533
              ods.p_ind = curwp->w_doto - headents[ods.cur_e].prwid;
 
534
            else
 
535
              ods.p_ind = 1000;
 
536
 
 
537
            /* and scroll back if needed */
 
538
            if(f == 3)
 
539
              for(i = 0; header_upline(0) && i <= FULL_SCR(); i++)
 
540
                ;
 
541
        }
 
542
 
 
543
        ods.p_line = ComposerTopLine - 2;
 
544
    }
 
545
    /* else just trust what ods contains */
 
546
 
 
547
    InvertPrompt(ods.cur_e, TRUE);              /* highlight header field */
 
548
    sgarbk = 1;
 
549
 
 
550
    do{
 
551
        if(km_popped){
 
552
            km_popped--;
 
553
            if(km_popped == 0)
 
554
              sgarbk = 1;
 
555
        }
 
556
 
 
557
        if(sgarbk){
 
558
            if(km_popped){  /* temporarily change to cause menu to paint */
 
559
                term.t_mrow = 2;
 
560
                curwp->w_ntrows -= 2;
 
561
                movecursor(term.t_nrow-2, 0); /* clear status line, too */
 
562
                peeol();
 
563
            }
 
564
            else if(term.t_mrow == 0)
 
565
              PaintBody(1);
 
566
 
 
567
            ShowPrompt();                       /* display correct options */
 
568
            sgarbk = 0;
 
569
            if(km_popped){
 
570
                term.t_mrow = 0;
 
571
                curwp->w_ntrows += 2;
 
572
            }
 
573
        }
 
574
 
 
575
        ch = LineEdit(!(gmode&MDVIEW));         /* work on the current line */
 
576
 
 
577
        if(km_popped)
 
578
          switch(ch){
 
579
            case NODATA:
 
580
            case (CTRL|'L'):
 
581
              km_popped++;
 
582
              break;
 
583
            
 
584
            default:
 
585
              movecursor(term.t_nrow-2, 0);
 
586
              peeol();
 
587
              movecursor(term.t_nrow-1, 0);
 
588
              peeol();
 
589
              movecursor(term.t_nrow, 0);
 
590
              peeol();
 
591
              break;
 
592
          }
 
593
 
 
594
        switch (ch){
 
595
          case (CTRL|'R') :                     /* Toggle header display */
 
596
            if(Pmaster->pine_flags & MDHDRONLY){
 
597
                if(Pmaster->expander){
 
598
                    packheader();
 
599
                    call_expander();
 
600
                    PaintBody(0);
 
601
                    break;
 
602
                }
 
603
                else
 
604
                  goto bleep;
 
605
            }
 
606
 
 
607
            /*---- Are there any headers to expand above us? ---*/
 
608
            for(h = headents; h != &headents[ods.cur_e]; h++)
 
609
              if(h->rich_header)
 
610
                break;
 
611
            if(h->rich_header)
 
612
              InvertPrompt(ods.cur_e, FALSE);   /* Yes, don't leave inverted */
 
613
 
 
614
            mangled = 0;
 
615
            err = NULL;
 
616
            if(partial_entries()){
 
617
                /*--- Just turned off all rich headers --*/
 
618
                if(headents[ods.cur_e].rich_header){
 
619
                    /*-- current header got turned off too --*/
 
620
#ifdef  ATTACHMENTS
 
621
                    if(headents[ods.cur_e].is_attach){
 
622
                        /* verify the attachments */
 
623
                        if((i = FormatSyncAttach()) != 0){
 
624
                            FormatLines(headents[ods.cur_e].hd_text, "",
 
625
                                        term.t_ncol - headents[ods.cur_e].prwid,
 
626
                                        headents[ods.cur_e].break_on_comma, 0);
 
627
                        }
 
628
                    }
 
629
#endif
 
630
                    if(headents[ods.cur_e].builder)     /* verify text */
 
631
                      i = call_builder(&headents[ods.cur_e], &mangled, &err)>0;
 
632
                    /* Check below */
 
633
                    for(cur_e =ods.cur_e; headents[cur_e].name!=NULL; cur_e++)
 
634
                      if(!headents[cur_e].rich_header)
 
635
                        break;
 
636
                    if(headents[cur_e].name == NULL) {
 
637
                        /* didn't find one, check above */
 
638
                        for(cur_e =ods.cur_e; headents[cur_e].name!=NULL;
 
639
                            cur_e--)
 
640
                          if(!headents[cur_e].rich_header)
 
641
                            break;
 
642
 
 
643
                    }
 
644
                    ods.p_ind = 0;
 
645
                    ods.cur_e = cur_e;
 
646
                    ods.cur_l = headents[ods.cur_e].hd_text;
 
647
                }
 
648
            }
 
649
 
 
650
            ods.p_line = 0;                     /* force update */
 
651
            UpdateHeader(0);
 
652
            PaintHeader(COMPOSER_TOP_LINE, FALSE);
 
653
            PaintBody(1);
 
654
            fix_mangle_and_err(&mangled, &err, headents[ods.cur_e].name);
 
655
            break;
 
656
 
 
657
          case (CTRL|'C') :                     /* bag whole thing ?*/
 
658
            if(abort_composer(1, 0) == TRUE)
 
659
              return(FALSE);
 
660
 
 
661
            break;
 
662
 
 
663
          case (CTRL|'X') :                     /* Done. Send it. */
 
664
            i = 0;
 
665
#ifdef  ATTACHMENTS
 
666
            if(headents[ods.cur_e].is_attach){
 
667
                /* verify the attachments, and pretty things up in case
 
668
                 * we come back to the composer due to error...
 
669
                 */
 
670
                if((i = FormatSyncAttach()) != 0){
 
671
                    sleep(2);           /* give time for error to absorb */
 
672
                    FormatLines(headents[ods.cur_e].hd_text, "",
 
673
                                term.t_ncol - headents[ods.cur_e].prwid,
 
674
                                headents[ods.cur_e].break_on_comma, 0);
 
675
                }
 
676
            }
 
677
            else
 
678
#endif
 
679
            mangled = 0;
 
680
            err = NULL;
 
681
            if(headents[ods.cur_e].builder)     /* verify text? */
 
682
              i = call_builder(&headents[ods.cur_e], &mangled, &err);
 
683
 
 
684
            if(i < 0){                  /* don't leave without a valid addr */
 
685
                fix_mangle_and_err(&mangled, &err, headents[ods.cur_e].name);
 
686
                break;
 
687
            }
 
688
            else if(i > 0){
 
689
                ods.cur_l = headents[ods.cur_e].hd_text; /* attach cur_l */
 
690
                ods.p_ind = 0;
 
691
                ods.p_line = 0;                 /* force realignment */
 
692
                fix_mangle_and_err(&mangled, &err, headents[ods.cur_e].name);
 
693
                NewTop(0);
 
694
            }
 
695
 
 
696
            fix_mangle_and_err(&mangled, &err, headents[ods.cur_e].name);
 
697
 
 
698
            if(wquit(1,0) == TRUE)
 
699
              return(TRUE);
 
700
 
 
701
            if(i > 0){
 
702
                /*
 
703
                 * need to be careful here because pointers might be messed up.
 
704
                 * also, could do a better job of finding the right place to
 
705
                 * put the dot back (i.e., the addr/list that was expanded).
 
706
                 */
 
707
                UpdateHeader(0);
 
708
                PaintHeader(COMPOSER_TOP_LINE, FALSE);
 
709
                PaintBody(1);
 
710
            }
 
711
            break;
 
712
 
 
713
          case (CTRL|'Z') :                     /* Suspend compose */
 
714
            if(gmode&MDSSPD){                   /* is it allowed? */
 
715
                bktoshell();
 
716
                PaintBody(0);
 
717
            }
 
718
            else{
 
719
                (*term.t_beep)();
 
720
                emlwrite(_("Unknown Command: ^Z"), NULL);
 
721
            }
 
722
            break;
 
723
 
 
724
          case (CTRL|'O') :                     /* Suspend message */
 
725
            if(Pmaster->pine_flags & MDHDRONLY)
 
726
              goto bleep;
 
727
 
 
728
            i = 0;
 
729
            mangled = 0;
 
730
            err = NULL;
 
731
            if(headents[ods.cur_e].is_attach){
 
732
                if(FormatSyncAttach() < 0){
 
733
                    if(mlyesno_utf8(_("Problem with attachments. Postpone anyway?"),
 
734
                               FALSE) != TRUE){
 
735
                        if(FormatLines(headents[ods.cur_e].hd_text, "",
 
736
                                       term.t_ncol - headents[ods.cur_e].prwid,
 
737
                                       headents[ods.cur_e].break_on_comma, 0) == -1)
 
738
                          emlwrite("\007Format lines failed!", NULL);
 
739
                        UpdateHeader(0);
 
740
                        PaintHeader(COMPOSER_TOP_LINE, FALSE);
 
741
                        PaintBody(1);
 
742
                        continue;
 
743
                    }
 
744
                }
 
745
            }
 
746
            else if(headents[ods.cur_e].builder)
 
747
              i = call_builder(&headents[ods.cur_e], &mangled, &err);
 
748
 
 
749
            fix_mangle_and_err(&mangled, &err, headents[ods.cur_e].name);
 
750
 
 
751
            if(i < 0)                   /* don't leave without a valid addr */
 
752
              break;
 
753
 
 
754
            suspend_composer(1, 0);
 
755
            return(TRUE);
 
756
 
 
757
#ifdef  ATTACHMENTS
 
758
          case (CTRL|'J') :                     /* handle attachments */
 
759
            if(Pmaster->pine_flags & MDHDRONLY)
 
760
              goto bleep;
 
761
 
 
762
            { char    cmt[NLINE];
 
763
              LMLIST *lm = NULL, *lmp;
 
764
              char buf[NLINE], *bfp;
 
765
              int saved_km_popped;
 
766
              size_t len;
 
767
 
 
768
              /*
 
769
               * Attachment questions mess with km_popped and assume
 
770
               * it is zero to start with.  If we don't set it to zero
 
771
               * on entry, the message about mime type will be erased
 
772
               * by PaintBody.  If we don't reset it when we come back,
 
773
               * the bottom three lines may be messed up.
 
774
               */
 
775
              saved_km_popped = km_popped;
 
776
              km_popped = 0;
 
777
 
 
778
              if(AskAttach(cmt, sizeof(cmt), &lm)){
 
779
 
 
780
                for(lmp = lm; lmp; lmp = lmp->next){
 
781
                    size_t space;
 
782
 
 
783
                    len = lmp->dir ? strlen(lmp->dir)+1 : 0;
 
784
                    len += lmp->fname ? strlen(lmp->fname) : 0;
 
785
 
 
786
                    if(len+3 > sizeof(buf)){
 
787
                        bfp = malloc(len+3);
 
788
                        space = len+3;
 
789
                        if((bfp=malloc(len+3)) == NULL){
 
790
                            emlwrite("\007Can't malloc space for filename",
 
791
                                     NULL);
 
792
                            continue;
 
793
                        }
 
794
                    }
 
795
                    else{
 
796
                        bfp = buf;
 
797
                        space = sizeof(buf);
 
798
                    }
 
799
 
 
800
                    if(lmp->dir && lmp->dir[0])
 
801
                      snprintf(bfp, space, "%s%c%s", lmp->dir, C_FILESEP,
 
802
                              lmp->fname ? lmp->fname : "");
 
803
                    else
 
804
                      snprintf(bfp, space, "%s", lmp->fname ? lmp->fname : "");
 
805
 
 
806
                    (void) QuoteAttach(bfp, space);
 
807
 
 
808
                    (void) AppendAttachment(bfp, lm->size, cmt);
 
809
 
 
810
                    if(bfp != buf)
 
811
                      free(bfp);
 
812
                }
 
813
 
 
814
                zotlmlist(lm);
 
815
              }
 
816
 
 
817
              km_popped = saved_km_popped;
 
818
              sgarbk = 1;                       /* clean up prompt */
 
819
            }
 
820
            break;
 
821
#endif
 
822
 
 
823
          case (CTRL|'I') :                     /* tab */
 
824
            ods.p_ind = 0;                      /* fall through... */
 
825
 
 
826
          case (CTRL|'N') :
 
827
          case KEY_DOWN :
 
828
            header_downline(!hdr_only, hdr_only);
 
829
            break;
 
830
 
 
831
          case (CTRL|'P') :
 
832
          case KEY_UP :
 
833
            header_upline(1);
 
834
            break;
 
835
 
 
836
          case (CTRL|'V') :                     /* down a page */
 
837
          case KEY_PGDN :
 
838
            cur_e = ods.cur_e;
 
839
            if(!next_sel_hline(&cur_e, ods.cur_l)){
 
840
                header_downline(!hdr_only, hdr_only);
 
841
                if(!(gmode & MDHDRONLY))
 
842
                  retval = -1;                  /* tell caller we fell out */
 
843
            }
 
844
            else{
 
845
                int move_down, bot_pline;
 
846
                struct hdr_line *new_cur_l, *line, *next_line, *prev_line;
 
847
 
 
848
                move_down = BOTTOM() - 2 - ods.p_line;
 
849
                if(move_down < 0)
 
850
                  move_down = 0;
 
851
 
 
852
                /*
 
853
                 * Count down move_down lines to find the pointer to the line
 
854
                 * that we want to become the current line.
 
855
                 */
 
856
                new_cur_l = ods.cur_l;
 
857
                cur_e = ods.cur_e;
 
858
                for(i = 0; i < move_down; i++){
 
859
                    next_line = next_hline(&cur_e, new_cur_l);
 
860
                    if(!next_line)
 
861
                      break;
 
862
 
 
863
                    new_cur_l = next_line;
 
864
                }
 
865
 
 
866
                if(headents[cur_e].blank){
 
867
                    next_line = next_sel_hline(&cur_e, new_cur_l);
 
868
                    if(!next_line)
 
869
                      break;
 
870
 
 
871
                    new_cur_l = next_line;
 
872
                }
 
873
 
 
874
                /*
 
875
                 * Now call header_downline until we get down to the
 
876
                 * new current line, so that the builders all get called.
 
877
                 * New_cur_l will remain valid since we won't be calling
 
878
                 * a builder for it during this loop.
 
879
                 */
 
880
                while(ods.cur_l != new_cur_l && header_downline(0, 0))
 
881
                  ;
 
882
                
 
883
                /*
 
884
                 * Count back up, if we're at the bottom, to find the new
 
885
                 * top line.
 
886
                 */
 
887
                cur_e = ods.cur_e;
 
888
                if(next_hline(&cur_e, ods.cur_l) == NULL){
 
889
                    /*
 
890
                     * Cursor stops at bottom of headers, which is where
 
891
                     * we are right now.  Put as much of headers on
 
892
                     * screen as will fit.  Count up to figure
 
893
                     * out which line is top_l and which p_line cursor is on.
 
894
                     */
 
895
                    cur_e = ods.cur_e;
 
896
                    line = ods.cur_l;
 
897
                    /* leave delimiter on screen, too */
 
898
                    bot_pline = BOTTOM() - 1 - ((gmode & MDHDRONLY) ? 0 : 1);
 
899
                    for(i = COMPOSER_TOP_LINE; i < bot_pline; i++){
 
900
                        prev_line = prev_hline(&cur_e, line);
 
901
                        if(!prev_line)
 
902
                          break;
 
903
                        
 
904
                        line = prev_line;
 
905
                    }
 
906
 
 
907
                    ods.top_l = line;
 
908
                    ods.top_e = cur_e;
 
909
                    ods.p_line = i;
 
910
                      
 
911
                }
 
912
                else{
 
913
                    ods.top_l = ods.cur_l;
 
914
                    ods.top_e = ods.cur_e;
 
915
                    /*
 
916
                     * We don't want to scroll down further than the
 
917
                     * delimiter, so check to see if that is the case.
 
918
                     * If it is, we move the p_line down the screen
 
919
                     * until the bottom line is where we want it.
 
920
                     */
 
921
                    bot_pline = BOTTOM() - 1 - ((gmode & MDHDRONLY) ? 0 : 1);
 
922
                    cur_e = ods.cur_e;
 
923
                    line = ods.cur_l;
 
924
                    for(i = bot_pline; i > COMPOSER_TOP_LINE; i--){
 
925
                        next_line = next_hline(&cur_e, line);
 
926
                        if(!next_line)
 
927
                          break;
 
928
 
 
929
                        line = next_line;
 
930
                    }
 
931
 
 
932
                    /*
 
933
                     * i is the desired value of p_line.
 
934
                     * If it is greater than COMPOSER_TOP_LINE, then
 
935
                     * we need to adjust top_l.
 
936
                     */
 
937
                    ods.p_line = i;
 
938
                    line = ods.top_l;
 
939
                    cur_e = ods.top_e;
 
940
                    for(; i > COMPOSER_TOP_LINE; i--){
 
941
                        prev_line = prev_hline(&cur_e, line);
 
942
                        if(!prev_line)
 
943
                          break;
 
944
                        
 
945
                        line = prev_line;
 
946
                    }
 
947
 
 
948
                    ods.top_l = line;
 
949
                    ods.top_e = cur_e;
 
950
 
 
951
                    /*
 
952
                     * Special case.  If p_line is within one of the bottom,
 
953
                     * move it to the bottom.
 
954
                     */
 
955
                    if(ods.p_line == bot_pline - 1){
 
956
                        header_downline(0, 0);
 
957
                        /* but put these back where we want them */
 
958
                        ods.p_line = bot_pline;
 
959
                        ods.top_l = line;
 
960
                        ods.top_e = cur_e;
 
961
                    }
 
962
                }
 
963
 
 
964
                UpdateHeader(0);
 
965
                PaintHeader(COMPOSER_TOP_LINE, FALSE);
 
966
                PaintBody(1);
 
967
            }
 
968
 
 
969
            break;
 
970
 
 
971
          case (CTRL|'Y') :                     /* up a page */
 
972
          case KEY_PGUP :
 
973
            for(i = 0; header_upline(0) && i <= FULL_SCR(); i++)
 
974
              if(i < 0)
 
975
                break;
 
976
 
 
977
            break;
 
978
 
 
979
#ifdef  MOUSE
 
980
          case KEY_MOUSE:
 
981
            mouse_get_last (NULL, &mp);
 
982
            switch(mp.button){
 
983
              case M_BUTTON_LEFT :
 
984
                if (!mp.doubleclick) {
 
985
                    if (mp.row < ods.p_line) {
 
986
                        for (i = ods.p_line - mp.row;
 
987
                             i > 0 && header_upline(0); 
 
988
                             --i)
 
989
                          ;
 
990
                    }
 
991
                    else {
 
992
                        for (i = mp.row-ods.p_line;
 
993
                             i > 0 && header_downline(!hdr_only, 0);
 
994
                             --i)
 
995
                          ;
 
996
                    }
 
997
 
 
998
                    if((ods.p_ind = mp.col - headents[ods.cur_e].prwid) <= 0)
 
999
                      ods.p_ind = 0;
 
1000
 
 
1001
                    /* -3 is returned  if we drop out bottom
 
1002
                     * *and* want to process a mousepress.  The Headereditor
 
1003
                     * wrapper should make sense of this return code.
 
1004
                     */
 
1005
                    if (ods.p_line >= ComposerTopLine)
 
1006
                      retval = -3;
 
1007
                }
 
1008
 
 
1009
                break;
 
1010
 
 
1011
              case M_BUTTON_RIGHT :
 
1012
#ifdef  _WINDOWS
 
1013
                pico_popup();
 
1014
#endif
 
1015
              case M_BUTTON_MIDDLE :
 
1016
              default : /* NOOP */
 
1017
                break;
 
1018
            }
 
1019
 
 
1020
            break;
 
1021
#endif /* MOUSE */
 
1022
 
 
1023
          case (CTRL|'T') :                     /* Call field selector */
 
1024
            errmss = NULL;
 
1025
            if(headents[ods.cur_e].is_attach) {
 
1026
                /*--- selector for attachments ----*/
 
1027
                char dir[NLINE], fn[NLINE], sz[NLINE];
 
1028
                LMLIST *lm = NULL, *lmp;
 
1029
 
 
1030
                strncpy(dir, (gmode & MDCURDIR)
 
1031
                       ? (browse_dir[0] ? browse_dir : ".")
 
1032
                       : ((gmode & MDTREE) || opertree[0])
 
1033
                       ? opertree
 
1034
                       : (browse_dir[0] ? browse_dir
 
1035
                          : gethomedir(NULL)), sizeof(dir));
 
1036
                dir[sizeof(dir)-1] = '\0';
 
1037
                fn[0] = sz[0] = '\0';
 
1038
                if(FileBrowse(dir, sizeof(dir), fn, sizeof(fn), sz, sizeof(sz),
 
1039
                              FB_READ | FB_ATTACH | FB_LMODEPOS, &lm) == 1){
 
1040
                    char buf[NLINE], *bfp;
 
1041
                    size_t len;
 
1042
 
 
1043
                    for(lmp = lm; lmp; lmp = lmp->next){
 
1044
                        size_t space;
 
1045
 
 
1046
                        len = lmp->dir ? strlen(lmp->dir)+1 : 0;
 
1047
                        len += lmp->fname ? strlen(lmp->fname) : 0;
 
1048
                        len += 7;
 
1049
                        len += strlen(lmp->size);
 
1050
 
 
1051
                        if(len+3 > sizeof(buf)){
 
1052
                            bfp = malloc(len+3);
 
1053
                            space = len+3;
 
1054
                            if((bfp=malloc(len+3)) == NULL){
 
1055
                                emlwrite("\007Can't malloc space for filename",
 
1056
                                         NULL);
 
1057
                                continue;
 
1058
                            }
 
1059
                        }
 
1060
                        else{
 
1061
                            bfp = buf;
 
1062
                            space = sizeof(buf);
 
1063
                        }
 
1064
 
 
1065
                        if(lmp->dir && lmp->dir[0])
 
1066
                          snprintf(bfp, space, "%s%c%s", lmp->dir, C_FILESEP,
 
1067
                                  lmp->fname ? lmp->fname : "");
 
1068
                        else
 
1069
                          snprintf(bfp, space, "%s", lmp->fname ? lmp->fname : "");
 
1070
 
 
1071
                        (void) QuoteAttach(bfp, space);
 
1072
 
 
1073
                        snprintf(bfp + strlen(bfp), space-strlen(bfp), " (%s) \"\"%s", lmp->size,
 
1074
                            (!headents[ods.cur_e].hd_text->text[0]) ? "":",");
 
1075
 
 
1076
                        if(FormatLines(headents[ods.cur_e].hd_text, bfp,
 
1077
                                     term.t_ncol - headents[ods.cur_e].prwid,
 
1078
                                     headents[ods.cur_e].break_on_comma,0)==-1){
 
1079
                            emlwrite("\007Format lines failed!", NULL);
 
1080
                        }
 
1081
 
 
1082
                        if(bfp != buf)
 
1083
                          free(bfp);
 
1084
 
 
1085
                        UpdateHeader(0);
 
1086
                    }
 
1087
 
 
1088
                    zotlmlist(lm);
 
1089
                }                               /* else, nothing of interest */
 
1090
            } else if (headents[ods.cur_e].selector != NULL) {
 
1091
                VARS_TO_SAVE *saved_state;
 
1092
 
 
1093
                /*---- General selector for non-attachments -----*/
 
1094
 
 
1095
                /*
 
1096
                 * Since the selector may make a new call back to pico()
 
1097
                 * we need to save and restore the pico state here.
 
1098
                 */
 
1099
                if((saved_state = save_pico_state()) != NULL){
 
1100
                    bufp = (*(headents[ods.cur_e].selector))(&errmss);
 
1101
                    restore_pico_state(saved_state);
 
1102
                    free_pico_state(saved_state);
 
1103
                    ttresize();                 /* fixup screen bufs */
 
1104
                    picosigs();                 /* restore altered signals */
 
1105
                }
 
1106
                else{
 
1107
                    char *s = "Not enough memory";
 
1108
                    size_t len;
 
1109
 
 
1110
                    len = strlen(s);
 
1111
                    errmss = (char *)malloc((len+1) * sizeof(char));
 
1112
                    strncpy(errmss, s, len+1);
 
1113
                    errmss[len] = '\0';
 
1114
                    bufp = NULL;
 
1115
                }
 
1116
 
 
1117
                if(bufp != NULL) {
 
1118
                    mangled = 0;
 
1119
                    err = NULL;
 
1120
                    if(headents[ods.cur_e].break_on_comma) {
 
1121
                        /*--- Must be an address ---*/
 
1122
                        if(ods.cur_l->text[0] != '\0'){
 
1123
                            struct hdr_line *h, *hh;
 
1124
                            int             q = 0;
 
1125
                            
 
1126
                            /*--- Check for continuation of previous line ---*/
 
1127
                            for(hh = h = headents[ods.cur_e].hd_text; 
 
1128
                                h && h->next != ods.cur_l; h = h->next){
 
1129
                                if(ucs4_strqchr(h->text, ',', &q, -1)){
 
1130
                                    hh = h->next;
 
1131
                                }
 
1132
                            }
 
1133
                            if(hh && hh != ods.cur_l){
 
1134
                                /*--- Looks like a continuation ---*/
 
1135
                                ods.cur_l = hh;
 
1136
                                ods.p_len = ucs4_strlen(hh->text);
 
1137
                            }
 
1138
                            for(i = ++ods.p_len; i; i--)
 
1139
                              ods.cur_l->text[i] = ods.cur_l->text[i-1];
 
1140
 
 
1141
                            ods.cur_l->text[0] = ',';
 
1142
                        }
 
1143
 
 
1144
                        if(FormatLines(ods.cur_l, bufp,
 
1145
                                      (term.t_ncol-headents[ods.cur_e].prwid), 
 
1146
                                      headents[ods.cur_e].break_on_comma, 0) == -1){
 
1147
                            emlwrite("Problem adding address to header !",
 
1148
                                     NULL);
 
1149
                            (*term.t_beep)();
 
1150
                            break;
 
1151
                        }
 
1152
 
 
1153
                        /*
 
1154
                         * If the "selector" has a "builder" as well, pass
 
1155
                         * what was just selected thru the builder...
 
1156
                         */
 
1157
                        if(headents[ods.cur_e].builder){
 
1158
                            struct hdr_line *l;
 
1159
                            int              cur_row, top_too = 0;
 
1160
 
 
1161
                            for(l = headents[ods.cur_e].hd_text, cur_row = 0;
 
1162
                                l && l != ods.cur_l;
 
1163
                                l = l->next, cur_row++)
 
1164
                              ;
 
1165
 
 
1166
                            top_too = headents[ods.cur_e].hd_text == ods.top_l;
 
1167
 
 
1168
                            if(call_builder(&headents[ods.cur_e], &mangled,
 
1169
                                            &err) < 0){
 
1170
                                fix_mangle_and_err(&mangled, &err,
 
1171
                                                   headents[ods.cur_e].name);
 
1172
                            }
 
1173
 
 
1174
                            for(ods.cur_l = headents[ods.cur_e].hd_text;
 
1175
                                ods.cur_l->next && cur_row;
 
1176
                                ods.cur_l = ods.cur_l->next, cur_row--)
 
1177
                              ;
 
1178
 
 
1179
                            if(top_too)
 
1180
                              ods.top_l = headents[ods.cur_e].hd_text;
 
1181
                        }
 
1182
 
 
1183
                        UpdateHeader(0);
 
1184
                    } else {
 
1185
                        UCS *u;
 
1186
 
 
1187
                        u = utf8_to_ucs4_cpystr(bufp);
 
1188
                        if(u){
 
1189
                          ucs4_strncpy(headents[ods.cur_e].hd_text->text, u, HLSZ);
 
1190
                          headents[ods.cur_e].hd_text->text[HLSZ-1] = '\0';
 
1191
                          fs_give((void **) &u);
 
1192
                        }
 
1193
                    }
 
1194
 
 
1195
                    free(bufp);
 
1196
                    /* mark this entry dirty */
 
1197
                    headents[ods.cur_e].sticky = 1;
 
1198
                    headents[ods.cur_e].dirty  = 1;
 
1199
                    fix_mangle_and_err(&mangled,&err,headents[ods.cur_e].name);
 
1200
                }
 
1201
            } else {
 
1202
                /*----- No selector -----*/
 
1203
                (*term.t_beep)();
 
1204
                continue;
 
1205
            }
 
1206
 
 
1207
            PaintBody(0);
 
1208
            if(errmss != NULL) {
 
1209
                (*term.t_beep)();
 
1210
                emlwrite(errmss, NULL);
 
1211
                free(errmss);
 
1212
                errmss = NULL;
 
1213
            }
 
1214
            continue;
 
1215
 
 
1216
          case (CTRL|'G'):                      /* HELP */
 
1217
            if(term.t_mrow == 0){
 
1218
                if(km_popped == 0){
 
1219
                    km_popped = 2;
 
1220
                    sgarbk = 1;                 /* bring up menu */
 
1221
                    break;
 
1222
                }
 
1223
            }
 
1224
 
 
1225
            if(!ComposerHelp(ods.cur_e))
 
1226
              break;                            /* else, fall through... */
 
1227
 
 
1228
          case (CTRL|'L'):                      /* redraw requested */
 
1229
            PaintBody(0);
 
1230
            break;
 
1231
 
 
1232
          case (CTRL|'_'):                      /* file editor */
 
1233
            if(headents[ods.cur_e].fileedit != NULL){
 
1234
                struct headerentry *e;
 
1235
                struct hdr_line    *line;
 
1236
                int                 sz = 0;
 
1237
                char               *filename = NULL;
 
1238
                VARS_TO_SAVE       *saved_state;
 
1239
 
 
1240
                /*
 
1241
                 * Since the fileedit will make a new call back to pico()
 
1242
                 * we need to save and restore the pico state here.
 
1243
                 */
 
1244
                if((saved_state = save_pico_state()) != NULL){
 
1245
                    UCS *u;
 
1246
 
 
1247
                    e = &headents[ods.cur_e];
 
1248
 
 
1249
                    for(line = e->hd_text; line != NULL; line = line->next)
 
1250
                      sz += ucs4_strlen(line->text);
 
1251
 
 
1252
                    u = (UCS *)malloc((sz+1) * sizeof(*u));
 
1253
                    if(u){
 
1254
                        u[0] = '\0';
 
1255
                        for(line = e->hd_text; line != NULL; line = line->next)
 
1256
                          ucs4_strncat(u, line->text, sz+1-ucs4_strlen(u));
 
1257
                    
 
1258
                        filename = ucs4_to_utf8_cpystr(u);
 
1259
                        free(u);
 
1260
                    }
 
1261
 
 
1262
                    errmss = (*(headents[ods.cur_e].fileedit))(filename);
 
1263
 
 
1264
                    if(filename)
 
1265
                      free(filename);
 
1266
 
 
1267
                    restore_pico_state(saved_state);
 
1268
                    free_pico_state(saved_state);
 
1269
                    ttresize();                 /* fixup screen bufs */
 
1270
                    picosigs();                 /* restore altered signals */
 
1271
                }
 
1272
                else{
 
1273
                    char *s = "Not enough memory";
 
1274
                    size_t len;
 
1275
 
 
1276
                    len = strlen(s);
 
1277
                    errmss = (char *)malloc((len+1) * sizeof(char));
 
1278
                    strncpy(errmss, s, len+1);
 
1279
                    errmss[len] = '\0';
 
1280
                }
 
1281
 
 
1282
                PaintBody(0);
 
1283
 
 
1284
                if(errmss != NULL) {
 
1285
                    (*term.t_beep)();
 
1286
                    emlwrite(errmss, NULL);
 
1287
                    free(errmss);
 
1288
                    errmss = NULL;
 
1289
                }
 
1290
 
 
1291
                continue;
 
1292
            }
 
1293
            else
 
1294
              goto bleep;
 
1295
 
 
1296
            break;
 
1297
 
 
1298
          default :                             /* huh? */
 
1299
bleep:
 
1300
            if(ch&CTRL && (ch & ~CTRL) < 0xff)
 
1301
              emlwrite(_("\007Unknown command: ^%c"), (void *)(ch&0xff));
 
1302
            else
 
1303
          case BADESC:
 
1304
              emlwrite(_("\007Unknown command"), NULL);
 
1305
 
 
1306
          case NODATA:
 
1307
            break;
 
1308
        }
 
1309
    }
 
1310
    while (ods.p_line < ComposerTopLine);
 
1311
 
 
1312
    display_delimiter(1);
 
1313
    curwp->w_flag |= WFMODE;
 
1314
    movecursor(currow, curcol);
 
1315
    ComposerEditing = FALSE;
 
1316
    if (ComposerTopLine == BOTTOM()){
 
1317
        UpdateHeader(0);
 
1318
        PaintHeader(COMPOSER_TOP_LINE, FALSE);
 
1319
        PaintBody(1);
 
1320
    }
 
1321
    
 
1322
    return(retval);
 
1323
}
 
1324
 
 
1325
 
 
1326
/*
 
1327
 *
 
1328
 */
 
1329
int
 
1330
header_downline(int beyond, int gripe)
 
1331
{
 
1332
    struct hdr_line *new_l, *l;
 
1333
    int    new_e, status, fullpaint, len, e, incr = 0;
 
1334
 
 
1335
    /* calculate the next line: physical *and* logical */
 
1336
    status    = 0;
 
1337
    new_e     = ods.cur_e;
 
1338
    if((new_l = next_sel_hline(&new_e, ods.cur_l)) == NULL && !beyond){
 
1339
 
 
1340
        if(gripe){
 
1341
            char xx[81];
 
1342
 
 
1343
            strncpy(xx, "Can't move down. Use ^X to ", sizeof(xx));
 
1344
            xx[sizeof(xx)-1] = '\0';
 
1345
            strncat(xx, (Pmaster && Pmaster->exit_label)
 
1346
                            ? Pmaster->exit_label
 
1347
                            : (gmode & MDHDRONLY)
 
1348
                              ? "eXit/Save"
 
1349
                              : (gmode & MDVIEW)
 
1350
                                ? "eXit"
 
1351
                                : "Send", sizeof(xx)-strlen(xx));
 
1352
            xx[sizeof(xx)-1] = '\0';
 
1353
            strncat(xx, ".", sizeof(xx)-strlen(xx));
 
1354
            xx[sizeof(xx)-1] = '\0';
 
1355
            emlwrite(xx, NULL);
 
1356
        }
 
1357
 
 
1358
        return(0);
 
1359
    }
 
1360
 
 
1361
    /*
 
1362
     * Because of blank header lines the cursor may need to move down
 
1363
     * more than one line. Figure out how far.
 
1364
     */
 
1365
    e = ods.cur_e;
 
1366
    l = ods.cur_l;
 
1367
    while(l != new_l){
 
1368
        if((l = next_hline(&e, l)) != NULL)
 
1369
          incr++;
 
1370
        else
 
1371
          break;  /* can't happen */
 
1372
    }
 
1373
 
 
1374
    ods.p_line += incr;
 
1375
    fullpaint = ods.p_line >= BOTTOM(); /* force full redraw?       */
 
1376
 
 
1377
    /* expand what needs expanding */
 
1378
    if(new_e != ods.cur_e || !new_l){           /* new (or last) field !    */
 
1379
        if(new_l)
 
1380
          InvertPrompt(ods.cur_e, FALSE);       /* turn off current entry   */
 
1381
 
 
1382
        if(headents[ods.cur_e].is_attach) {     /* verify data ?            */
 
1383
            if(status = FormatSyncAttach()){    /* fixup if 1 or -1         */
 
1384
                headents[ods.cur_e].rich_header = 0;
 
1385
                if(FormatLines(headents[ods.cur_e].hd_text, "",
 
1386
                               term.t_ncol-headents[new_e].prwid,
 
1387
                               headents[ods.cur_e].break_on_comma, 0) == -1)
 
1388
                  emlwrite("\007Format lines failed!", NULL);
 
1389
            }
 
1390
        } else if(headents[ods.cur_e].builder) { /* expand addresses        */
 
1391
            int mangled = 0;
 
1392
            char *err = NULL;
 
1393
 
 
1394
            if((status = call_builder(&headents[ods.cur_e], &mangled, &err))>0){
 
1395
                struct hdr_line *l;             /* fixup ods.cur_l */
 
1396
                ods.p_line = 0;                 /* force top line recalc */
 
1397
                for(l = headents[ods.cur_e].hd_text; l; l = l->next)
 
1398
                  ods.cur_l = l;
 
1399
 
 
1400
                if(new_l)                       /* if new_l, force validity */
 
1401
                  new_l = headents[new_e].hd_text;
 
1402
 
 
1403
                NewTop(0);                      /* get new top_l */
 
1404
            }
 
1405
            else if(status < 0){                /* bad addr? no leave! */
 
1406
                --ods.p_line;
 
1407
                fix_mangle_and_err(&mangled, &err, headents[ods.cur_e].name);
 
1408
                InvertPrompt(ods.cur_e, TRUE);
 
1409
                return(0);
 
1410
            }
 
1411
 
 
1412
            fix_mangle_and_err(&mangled, &err, headents[ods.cur_e].name);
 
1413
        }
 
1414
 
 
1415
        if(new_l){                              /* if one below, turn it on */
 
1416
            InvertPrompt(new_e, TRUE);
 
1417
            sgarbk = 1;                         /* paint keymenu too        */
 
1418
        }
 
1419
    }
 
1420
 
 
1421
    if(new_l){                                  /* fixup new pointers       */
 
1422
        ods.cur_l = (ods.cur_e != new_e) ? headents[new_e].hd_text : new_l;
 
1423
        ods.cur_e = new_e;
 
1424
        if(ods.p_ind > (len = ucs4_strlen(ods.cur_l->text)))
 
1425
          ods.p_ind = len;
 
1426
    }
 
1427
 
 
1428
    if(!new_l || status || fullpaint){          /* handle big screen paint  */
 
1429
        UpdateHeader(0);
 
1430
        PaintHeader(COMPOSER_TOP_LINE, FALSE);
 
1431
        PaintBody(1);
 
1432
 
 
1433
        if(!new_l){                             /* make sure we're done     */
 
1434
            ods.p_line = ComposerTopLine;
 
1435
            InvertPrompt(ods.cur_e, FALSE);     /* turn off current entry   */
 
1436
        }
 
1437
    }
 
1438
 
 
1439
    return(new_l ? 1 : 0);
 
1440
}
 
1441
 
 
1442
 
 
1443
/*
 
1444
 *
 
1445
 */
 
1446
int
 
1447
header_upline(int gripe)
 
1448
{
 
1449
    struct hdr_line *new_l, *l;
 
1450
    int    new_e, status, fullpaint, len, e, incr = 0;
 
1451
 
 
1452
    /* calculate the next line: physical *and* logical */
 
1453
    status    = 0;
 
1454
    new_e     = ods.cur_e;
 
1455
    if(!(new_l = prev_sel_hline(&new_e, ods.cur_l))){   /* all the way up! */
 
1456
        ods.p_line = COMPOSER_TOP_LINE;
 
1457
        if(gripe)
 
1458
          emlwrite(_("Can't move beyond top of %s"),
 
1459
              (Pmaster->pine_flags & MDHDRONLY) ? "entry" : "header");
 
1460
 
 
1461
        return(0);
 
1462
    }
 
1463
    
 
1464
    /*
 
1465
     * Because of blank header lines the cursor may need to move up
 
1466
     * more than one line. Figure out how far.
 
1467
     */
 
1468
    e = ods.cur_e;
 
1469
    l = ods.cur_l;
 
1470
    while(l != new_l){
 
1471
        if((l = prev_hline(&e, l)) != NULL)
 
1472
          incr++;
 
1473
        else
 
1474
          break;  /* can't happen */
 
1475
    }
 
1476
 
 
1477
    ods.p_line -= incr;
 
1478
    fullpaint = ods.p_line <= COMPOSER_TOP_LINE;
 
1479
 
 
1480
    if(new_e != ods.cur_e){                     /* new field ! */
 
1481
        InvertPrompt(ods.cur_e, FALSE);
 
1482
        if(headents[ods.cur_e].is_attach){
 
1483
            if(status = FormatSyncAttach()){   /* non-zero ? reformat field */
 
1484
                headents[ods.cur_e].rich_header = 0;
 
1485
                if(FormatLines(headents[ods.cur_e].hd_text, "",
 
1486
                               term.t_ncol - headents[ods.cur_e].prwid,
 
1487
                               headents[ods.cur_e].break_on_comma,0) == -1)
 
1488
                  emlwrite("\007Format lines failed!", NULL);
 
1489
            }
 
1490
        }
 
1491
        else if(headents[ods.cur_e].builder){
 
1492
            int mangled = 0;
 
1493
            char *err = NULL;
 
1494
 
 
1495
            if((status = call_builder(&headents[ods.cur_e], &mangled,
 
1496
                                      &err)) >= 0){
 
1497
                /* repair new_l */
 
1498
                for(new_l = headents[new_e].hd_text;
 
1499
                    new_l->next;
 
1500
                    new_l=new_l->next)
 
1501
                  ;
 
1502
 
 
1503
                /* and cur_l (required in fix_and... */
 
1504
                ods.cur_l = new_l;
 
1505
            }
 
1506
            else{
 
1507
                ++ods.p_line;
 
1508
                fix_mangle_and_err(&mangled, &err, headents[ods.cur_e].name);
 
1509
                InvertPrompt(ods.cur_e, TRUE);
 
1510
                return(0);
 
1511
            }
 
1512
 
 
1513
            fix_mangle_and_err(&mangled, &err, headents[ods.cur_e].name);
 
1514
        }
 
1515
 
 
1516
        InvertPrompt(new_e, TRUE);
 
1517
        sgarbk = 1;
 
1518
    }
 
1519
 
 
1520
    ods.cur_e = new_e;                          /* update pointers */
 
1521
    ods.cur_l = new_l;
 
1522
    if(ods.p_ind > (len = ucs4_strlen(ods.cur_l->text)))
 
1523
      ods.p_ind = len;
 
1524
 
 
1525
    if(status > 0 || fullpaint){
 
1526
        UpdateHeader(0);
 
1527
        PaintHeader(COMPOSER_TOP_LINE, FALSE);
 
1528
        PaintBody(1);
 
1529
    }
 
1530
 
 
1531
    return(1);
 
1532
}
 
1533
 
 
1534
 
 
1535
/*
 
1536
 * 
 
1537
 */
 
1538
int
 
1539
AppendAttachment(char *fn, char *sz, char *cmt)
 
1540
{
 
1541
    int  a_e, status, spaces;
 
1542
    struct hdr_line *lp;
 
1543
    char b[256];
 
1544
    UCS *u;
 
1545
 
 
1546
    /*--- Find headerentry that is attachments (only first) --*/
 
1547
    for(a_e = 0; headents[a_e].name != NULL; a_e++ )
 
1548
      if(headents[a_e].is_attach){
 
1549
          /* make sure field stays displayed */
 
1550
          headents[a_e].rich_header = 0;
 
1551
          headents[a_e].display_it = 1;
 
1552
          break;
 
1553
      }
 
1554
 
 
1555
    /* append new attachment line */
 
1556
    for(lp = headents[a_e].hd_text; lp->next; lp=lp->next)
 
1557
      ;
 
1558
 
 
1559
    /* build new attachment line */
 
1560
    if(lp->text[0]){            /* adding a line? */
 
1561
        UCS comma[2];
 
1562
 
 
1563
        comma[0] = ',';
 
1564
        comma[1] = '\0';
 
1565
        ucs4_strncat(lp->text, comma, HLSZ-ucs4_strlen(lp->text));      /* append delimiter */
 
1566
        if(lp->next = HALLOC()){        /* allocate new line */
 
1567
            lp->next->prev = lp;
 
1568
            lp->next->next = NULL;
 
1569
            lp = lp->next;
 
1570
        }
 
1571
        else{
 
1572
            emlwrite("\007Can't allocate line for new attachment!", NULL);
 
1573
            return(0);
 
1574
        }
 
1575
    }
 
1576
 
 
1577
    
 
1578
    spaces = (*fn == '\"') ? 0 : (strpbrk(fn, "(), \t") != NULL);
 
1579
    snprintf(b, sizeof(b), "%s%s%s (%s) \"%.*s\"",
 
1580
            spaces ? "\"" : "", fn, spaces ? "\"" : "",
 
1581
            sz ? sz : "", 80, cmt ? cmt : "");
 
1582
    u = utf8_to_ucs4_cpystr(b);
 
1583
    if(u){
 
1584
        ucs4_strncpy(lp->text, u, HLSZ); 
 
1585
        lp->text[HLSZ-1] = '\0';
 
1586
        fs_give((void **) &u);
 
1587
    }
 
1588
 
 
1589
    /* validate the new attachment, and reformat if needed */
 
1590
    if(status = SyncAttach()){
 
1591
        if(status < 0)
 
1592
          emlwrite("\007Problem attaching: %s", fn);
 
1593
 
 
1594
        if(FormatLines(headents[a_e].hd_text, "",
 
1595
                       term.t_ncol - headents[a_e].prwid,
 
1596
                       headents[a_e].break_on_comma, 0) == -1){
 
1597
            emlwrite("\007Format lines failed!", NULL);
 
1598
            return(0);
 
1599
        }
 
1600
    }
 
1601
 
 
1602
    UpdateHeader(0);
 
1603
    PaintHeader(COMPOSER_TOP_LINE, status != 0);
 
1604
    PaintBody(1);
 
1605
    return(status != 0);
 
1606
}
 
1607
 
 
1608
 
 
1609
 
 
1610
 
 
1611
/*
 
1612
 * LineEdit - the idea is to manage 7 bit ascii character only input.
 
1613
 *            Always use insert mode and handle line wrapping
 
1614
 *
 
1615
 *      returns:
 
1616
 *              Any characters typed in that aren't printable 
 
1617
 *              (i.e. commands)
 
1618
 *
 
1619
 *      notes: 
 
1620
 *              Assume we are guaranteed that there is sufficiently 
 
1621
 *              more buffer space in a line than screen width (just one 
 
1622
 *              less thing to worry about).  If you want to change this,
 
1623
 *              then pputc will have to be taught to check the line buffer
 
1624
 *              length, and HALLOC() will probably have to become a func.
 
1625
 */
 
1626
UCS
 
1627
LineEdit(int allowedit)
 
1628
{
 
1629
    register struct     hdr_line   *lp;         /* temporary line pointer    */
 
1630
    register int        i;
 
1631
    UCS                 ch = 0;
 
1632
    register int        status;                 /* various func's return val */
 
1633
    UCS                *tbufp;                  /* temporary buffer pointers */
 
1634
    int                 skipmove = 0;
 
1635
    UCS                *strng;
 
1636
    UCS                 last_key;               /* last keystroke  */
 
1637
 
 
1638
    strng   = ods.cur_l->text;                  /* initialize offsets */
 
1639
    ods.p_len = MIN(ucs4_strlen(strng), HLSZ);
 
1640
    if(ods.p_ind < 0)                           /* offset within range? */
 
1641
      ods.p_ind = 0;
 
1642
    else if(ods.p_ind > ods.p_len)
 
1643
      ods.p_ind = ods.p_len;
 
1644
    else if(ucs4_str_width_ptr_to_ptr(&strng[0], &strng[ods.p_ind]) > LINEWID()){
 
1645
        UCS *u;
 
1646
 
 
1647
        u = ucs4_particular_width(strng, LINEWID());
 
1648
        ods.p_ind = u - strng;
 
1649
    }
 
1650
 
 
1651
    while(1){                                   /* edit the line... */
 
1652
 
 
1653
        if(skipmove)
 
1654
          skipmove = 0;
 
1655
        else
 
1656
          HeaderPaintCursor();
 
1657
 
 
1658
        last_key = ch;
 
1659
 
 
1660
        (*term.t_flush)();                      /* get everything out */
 
1661
 
 
1662
#ifdef MOUSE
 
1663
        mouse_in_content(KEY_MOUSE, -1, -1, 0, 0);
 
1664
        register_mfunc(mouse_in_content,2,0,term.t_nrow-(term.t_mrow+1),
 
1665
                       term.t_ncol);
 
1666
#endif
 
1667
#ifdef  _WINDOWS
 
1668
        mswin_setdndcallback (composer_file_drop);
 
1669
        mswin_mousetrackcallback(pico_cursor);
 
1670
#endif
 
1671
 
 
1672
        ch = GetKey();
 
1673
        
 
1674
        if (term.t_nrow < 6 && ch != NODATA){
 
1675
            (*term.t_beep)();
 
1676
            emlwrite(_("Please make the screen larger."), NULL);
 
1677
            continue;
 
1678
        }
 
1679
 
 
1680
#ifdef  MOUSE
 
1681
        clear_mfunc(mouse_in_content);
 
1682
#endif
 
1683
#ifdef  _WINDOWS
 
1684
        mswin_cleardndcallback ();
 
1685
        mswin_mousetrackcallback(NULL);
 
1686
#endif
 
1687
 
 
1688
        switch(ch){
 
1689
          case DEL :
 
1690
            if(gmode & P_DELRUBS)
 
1691
              ch = KEY_DEL;
 
1692
 
 
1693
          default :
 
1694
            (*Pmaster->keybinput)();
 
1695
            if(!time_to_check())
 
1696
              break;
 
1697
 
 
1698
          case NODATA :                 /* new mail ? */
 
1699
            if((*Pmaster->newmail)(ch == NODATA ? 0 : 2, 1) >= 0){
 
1700
                int rv;
 
1701
                
 
1702
                if(km_popped){
 
1703
                    term.t_mrow = 2;
 
1704
                    curwp->w_ntrows -= 2;
 
1705
                }
 
1706
 
 
1707
                clearcursor();
 
1708
                mlerase();
 
1709
                rv = (*Pmaster->showmsg)(ch);
 
1710
                ttresize();
 
1711
                picosigs();
 
1712
                if(rv)          /* Did showmsg corrupt the display? */
 
1713
                  PaintBody(0); /* Yes, repaint */
 
1714
 
 
1715
                mpresf = 1;
 
1716
                if(km_popped){
 
1717
                    term.t_mrow = 0;
 
1718
                    curwp->w_ntrows += 2;
 
1719
                }
 
1720
            }
 
1721
 
 
1722
            clearcursor();
 
1723
            movecursor(ods.p_line,
 
1724
                ucs4_str_width_ptr_to_ptr(strng, &strng[ods.p_ind])+headents[ods.cur_e].prwid);
 
1725
            if(ch == NODATA)                    /* GetKey timed out */
 
1726
              continue;
 
1727
 
 
1728
            break;
 
1729
        }
 
1730
 
 
1731
        if(mpresf){                             /* blast old messages */
 
1732
            if(mpresf++ > NMMESSDELAY){         /* every few keystrokes */
 
1733
                mlerase();
 
1734
                movecursor(ods.p_line,
 
1735
                    ucs4_str_width_ptr_to_ptr(strng, &strng[ods.p_ind])+headents[ods.cur_e].prwid);
 
1736
            }
 
1737
        }
 
1738
 
 
1739
        tbufp = &strng[ods.p_len];
 
1740
 
 
1741
        if(VALID_KEY(ch)){                      /* char input */
 
1742
            /*
 
1743
             * if we are allowing editing, insert the new char
 
1744
             * end up leaving tbufp pointing to newly
 
1745
             * inserted character in string, and offset to the
 
1746
             * index of the character after the inserted ch ...
 
1747
             */
 
1748
            if(allowedit){
 
1749
                if(headents[ods.cur_e].is_attach && intag(strng,ods.p_ind)){
 
1750
                    emlwrite(_("\007Can't edit attachment number!"), NULL);
 
1751
                    continue;
 
1752
                }
 
1753
 
 
1754
                if(headents[ods.cur_e].single_space){
 
1755
                    if(ch == ' ' 
 
1756
                       && (strng[ods.p_ind]==' ' || strng[ods.p_ind-1]==' '))
 
1757
                      continue;
 
1758
                }
 
1759
 
 
1760
                /*
 
1761
                 * go ahead and add the character...
 
1762
                 */
 
1763
                if(ods.p_len < HLSZ){
 
1764
                    tbufp = &strng[++ods.p_len];        /* find the end */
 
1765
                    do{
 
1766
                        *tbufp = tbufp[-1];
 
1767
                    } while(--tbufp > &strng[ods.p_ind]);       /* shift right */
 
1768
                    strng[ods.p_ind++] = ch;    /* add char to str */
 
1769
                }
 
1770
 
 
1771
                /* mark this entry dirty */
 
1772
                headents[ods.cur_e].sticky = 1;
 
1773
                headents[ods.cur_e].dirty  = 1;
 
1774
 
 
1775
                /*
 
1776
                 * then find out where things fit...
 
1777
                 */
 
1778
                if(ucs4_str_width_ptr_to_ptr(&strng[0], &strng[ods.p_len]) < LINEWID()){
 
1779
                    CELL c;
 
1780
 
 
1781
                    c.c = ch & CELLMASK;
 
1782
                    c.a = 0;
 
1783
                    if(pinsert(c)){             /* add char to str */
 
1784
                        skipmove++;             /* must'a been optimal */
 
1785
                        continue;               /* on to the next! */
 
1786
                    }
 
1787
                }
 
1788
                else{
 
1789
                    if((status = FormatLines(ods.cur_l, "", LINEWID(), 
 
1790
                                headents[ods.cur_e].break_on_comma,0)) == -1){
 
1791
                        (*term.t_beep)();
 
1792
                        continue;
 
1793
                    }
 
1794
                    else{
 
1795
                        /*
 
1796
                         * during the format, the dot may have moved
 
1797
                         * down to the next line...
 
1798
                         */
 
1799
                        if(ods.p_ind >= ucs4_strlen(strng)){
 
1800
                            ods.p_line++;
 
1801
                            ods.p_ind -= ucs4_strlen(strng);
 
1802
                            ods.cur_l = ods.cur_l->next;
 
1803
                            strng = ods.cur_l->text;
 
1804
                        }
 
1805
 
 
1806
                        ods.p_len = ucs4_strlen(strng);
 
1807
                    }
 
1808
 
 
1809
                    UpdateHeader(0);
 
1810
                    PaintHeader(COMPOSER_TOP_LINE, FALSE);
 
1811
                    PaintBody(1);
 
1812
                    continue;
 
1813
                }
 
1814
            }
 
1815
            else{  
 
1816
                rdonly();
 
1817
                continue;
 
1818
            } 
 
1819
        }
 
1820
        else {                                  /* interpret ch as a command */
 
1821
            switch (ch = normalize_cmd(ch, ckm, 2)) {
 
1822
              case (CTRL|'@') :         /* word skip */
 
1823
                while(ucs4_isalnum(strng[ods.p_ind]))
 
1824
                  ods.p_ind++;          /* skip any text we're in */
 
1825
 
 
1826
                while(strng[ods.p_ind] && !ucs4_isalnum(strng[ods.p_ind]))
 
1827
                  ods.p_ind++;          /* skip any whitespace after it */
 
1828
 
 
1829
                if(strng[ods.p_ind] == '\0'){
 
1830
                    ods.p_ind = 0;      /* end of line, let caller handle it */
 
1831
                    return(KEY_DOWN);
 
1832
                }
 
1833
 
 
1834
                continue;
 
1835
 
 
1836
              case (CTRL|'K') :                 /* kill line cursor's on */
 
1837
                if(!allowedit){
 
1838
                    rdonly();
 
1839
                    continue;
 
1840
                }
 
1841
 
 
1842
                lp = ods.cur_l;
 
1843
                if (!(gmode & MDDTKILL))
 
1844
                  ods.p_ind = 0;
 
1845
 
 
1846
                if(KillHeaderLine(lp, (last_key == (CTRL|'K')))){
 
1847
                    if(TERM_OPTIMIZE && 
 
1848
                       !(ods.cur_l->prev==NULL && ods.cur_l->next==NULL)) 
 
1849
                      scrollup(wheadp, ods.p_line, 1);
 
1850
 
 
1851
                    if(ods.cur_l->next == NULL)
 
1852
                      if(zotcomma(ods.cur_l->text)){
 
1853
                          if(ods.p_ind > 0)
 
1854
                            ods.p_ind = ucs4_strlen(ods.cur_l->text);
 
1855
                      }
 
1856
                    
 
1857
                    i = (ods.p_line == COMPOSER_TOP_LINE);
 
1858
                    UpdateHeader(0);
 
1859
                    PaintHeader(COMPOSER_TOP_LINE, TRUE);
 
1860
 
 
1861
                    if(km_popped){
 
1862
                        km_popped--;
 
1863
                        movecursor(term.t_nrow, 0);
 
1864
                        peeol();
 
1865
                    }
 
1866
 
 
1867
                    PaintBody(1);
 
1868
 
 
1869
                }
 
1870
                strng = ods.cur_l->text;
 
1871
                ods.p_len = ucs4_strlen(strng);
 
1872
                headents[ods.cur_e].sticky = 0;
 
1873
                headents[ods.cur_e].dirty  = 1;
 
1874
                continue;
 
1875
 
 
1876
              case (CTRL|'U') :                 /* un-delete deleted lines */
 
1877
                if(!allowedit){
 
1878
                    rdonly();
 
1879
                    continue;
 
1880
                }
 
1881
 
 
1882
                if(SaveHeaderLines()){
 
1883
                    UpdateHeader(0);
 
1884
                    PaintHeader(COMPOSER_TOP_LINE, FALSE);
 
1885
                    if(km_popped){
 
1886
                        km_popped--;
 
1887
                        movecursor(term.t_nrow, 0);
 
1888
                        peeol();
 
1889
                    }
 
1890
 
 
1891
                    PaintBody(1);
 
1892
                    strng = ods.cur_l->text;
 
1893
                    ods.p_len = ucs4_strlen(strng);
 
1894
                    headents[ods.cur_e].sticky = 1;
 
1895
                    headents[ods.cur_e].dirty  = 1;
 
1896
                }
 
1897
                else
 
1898
                  /* TRANSLATORS: Killing text is deleting it and
 
1899
                     Unkilling text is undeleting killed text. */
 
1900
                  emlwrite(_("Problem Unkilling text"), NULL);
 
1901
                continue;
 
1902
 
 
1903
              case (CTRL|'F') :
 
1904
              case KEY_RIGHT:                   /* move character right */
 
1905
                if(ods.p_ind < ods.p_len){
 
1906
                    ods.p_ind++;
 
1907
                    continue;
 
1908
                }
 
1909
                else if(gmode & MDHDRONLY)
 
1910
                  continue;
 
1911
 
 
1912
                ods.p_ind = 0;
 
1913
                return(KEY_DOWN);
 
1914
 
 
1915
              case (CTRL|'B') :
 
1916
              case KEY_LEFT     :               /* move character left */
 
1917
                if(ods.p_ind > 0){
 
1918
                    ods.p_ind--;
 
1919
                    continue;
 
1920
                }
 
1921
                if(ods.p_line != COMPOSER_TOP_LINE)
 
1922
                  ods.p_ind = 1000;             /* put cursor at end of line */
 
1923
                return(KEY_UP);
 
1924
 
 
1925
              case (CTRL|'M') :                 /* goto next field */
 
1926
                ods.p_ind = 0;
 
1927
                return(KEY_DOWN);
 
1928
 
 
1929
              case KEY_HOME :
 
1930
              case (CTRL|'A') :                 /* goto beginning of line */
 
1931
                ods.p_ind = 0;
 
1932
                continue;
 
1933
 
 
1934
              case KEY_END  :
 
1935
              case (CTRL|'E') :                 /* goto end of line */
 
1936
                ods.p_ind = ods.p_len;
 
1937
                continue;
 
1938
 
 
1939
              case (CTRL|'D')   :               /* blast this char */
 
1940
              case KEY_DEL :
 
1941
                if(!allowedit){
 
1942
                    rdonly();
 
1943
                    continue;
 
1944
                }
 
1945
                else if(ods.p_ind >= ucs4_strlen(strng))
 
1946
                  continue;
 
1947
 
 
1948
                if(headents[ods.cur_e].is_attach && intag(strng, ods.p_ind)){
 
1949
                    emlwrite(_("\007Can't edit attachment number!"), NULL);
 
1950
                    continue;
 
1951
                }
 
1952
 
 
1953
                pputc(strng[ods.p_ind++], 0);   /* drop through and rubout */
 
1954
 
 
1955
              case DEL        :                 /* blast previous char */
 
1956
              case (CTRL|'H') :
 
1957
                if(!allowedit){
 
1958
                    rdonly();
 
1959
                    continue;
 
1960
                }
 
1961
 
 
1962
                if(headents[ods.cur_e].is_attach && intag(strng, ods.p_ind-1)){
 
1963
                    emlwrite(_("\007Can't edit attachment number!"), NULL);
 
1964
                    continue;
 
1965
                }
 
1966
 
 
1967
                if(ods.p_ind > 0){              /* just shift left one char */
 
1968
                    ods.p_len--;
 
1969
                    headents[ods.cur_e].dirty  = 1;
 
1970
                    if(ods.p_len == 0)
 
1971
                      headents[ods.cur_e].sticky = 0;
 
1972
                    else
 
1973
                      headents[ods.cur_e].sticky = 1;
 
1974
 
 
1975
                    tbufp = &strng[--ods.p_ind];
 
1976
                    while(*tbufp++ != '\0')
 
1977
                      tbufp[-1] = *tbufp;
 
1978
                    tbufp = &strng[ods.p_ind];
 
1979
                    if(pdel())                  /* physical screen delete */
 
1980
                      skipmove++;               /* must'a been optimal */
 
1981
                }
 
1982
                else{                           /* may have work to do */
 
1983
                    if(ods.cur_l->prev == NULL){  
 
1984
                        (*term.t_beep)();       /* no erase into next field */
 
1985
                        continue;
 
1986
                    }
 
1987
 
 
1988
                    ods.p_line--;
 
1989
                    ods.cur_l = ods.cur_l->prev;
 
1990
                    strng = ods.cur_l->text;
 
1991
                    if((i=ucs4_strlen(strng)) > 0){
 
1992
                        strng[i-1] = '\0';      /* erase the character */
 
1993
                        ods.p_ind = i-1;
 
1994
                    }
 
1995
                    else{
 
1996
                        headents[ods.cur_e].sticky = 0;
 
1997
                        ods.p_ind = 0;
 
1998
                    }
 
1999
                    
 
2000
                    tbufp = &strng[ods.p_ind];
 
2001
                }
 
2002
 
 
2003
                if((status = FormatLines(ods.cur_l, "", LINEWID(), 
 
2004
                                   headents[ods.cur_e].break_on_comma,0))==-1){
 
2005
                    (*term.t_beep)();
 
2006
                    continue;
 
2007
                }
 
2008
                else{
 
2009
                    /*
 
2010
                     * beware, the dot may have moved...
 
2011
                     */
 
2012
                    while((ods.p_len=ucs4_strlen(strng)) < ods.p_ind){
 
2013
                        ods.p_line++;
 
2014
                        ods.p_ind -= ucs4_strlen(strng);
 
2015
                        ods.cur_l = ods.cur_l->next;
 
2016
                        strng = ods.cur_l->text;
 
2017
                        ods.p_len = ucs4_strlen(strng);
 
2018
                        tbufp = &strng[ods.p_ind];
 
2019
                        status = TRUE;
 
2020
                    }
 
2021
 
 
2022
                    if(UpdateHeader(0))
 
2023
                      status = TRUE;
 
2024
 
 
2025
                    PaintHeader(COMPOSER_TOP_LINE, FALSE);
 
2026
                    if(status == TRUE)
 
2027
                      PaintBody(1);
 
2028
                }
 
2029
 
 
2030
                movecursor(ods.p_line,
 
2031
                    ucs4_str_width_ptr_to_ptr(strng, &strng[ods.p_ind])+headents[ods.cur_e].prwid);
 
2032
 
 
2033
                if(skipmove)
 
2034
                  continue;
 
2035
 
 
2036
                break;
 
2037
 
 
2038
              default   :
 
2039
                return(ch);
 
2040
            }
 
2041
        }
 
2042
 
 
2043
        while ((tbufp-strng) < HLSZ && *tbufp != '\0')          /* synchronizing loop */
 
2044
          pputc(*tbufp++, 0);
 
2045
 
 
2046
        if(ucs4_str_width_ptr_to_ptr(&strng[0], &strng[ods.p_len]) < LINEWID())
 
2047
          peeol();
 
2048
    }
 
2049
}
 
2050
 
 
2051
 
 
2052
void
 
2053
HeaderPaintCursor(void)
 
2054
{
 
2055
    movecursor(ods.p_line, ucs4_str_width_ptr_to_ptr(&ods.cur_l->text[0], &ods.cur_l->text[ods.p_ind])+headents[ods.cur_e].prwid);
 
2056
}
 
2057
 
 
2058
 
 
2059
 
 
2060
/*
 
2061
 * FormatLines - Place the given text at the front of the given line->text
 
2062
 *               making sure to properly format the line, then check
 
2063
 *               all lines below for proper format.
 
2064
 *
 
2065
 *      notes:
 
2066
 *              Not much optimization at all.  Right now, it recursively
 
2067
 *              fixes all remaining lines in the entry.  Some speed might
 
2068
 *              gained if this was built to iteratively scan the lines.
 
2069
 *
 
2070
 *      returns:
 
2071
 *              -1 on error
 
2072
 *              FALSE if only this line is changed
 
2073
 *              TRUE  if text below the first line is changed
 
2074
 */
 
2075
int
 
2076
FormatLines(struct hdr_line *h,                 /* where to begin formatting */
 
2077
            char *utf8_instr,                   /* input string */
 
2078
            int maxwid,                         /* max width of a line */
 
2079
            int break_on_comma,                 /* break lines on commas */
 
2080
            int quoted)                         /* this line inside quotes */
 
2081
{
 
2082
    int          retval = FALSE;
 
2083
    int          i, l, len;
 
2084
    char        *utf8;
 
2085
    UCS         *ostr;                  /* pointer to output string */
 
2086
    UCS         *free_istr = NULL;
 
2087
    UCS         *istr = NULL;
 
2088
    UCS         *breakp;                /* pointer to line break */
 
2089
    UCS         *bp, *tp;               /* temporary pointers */
 
2090
    UCS         *buf;                   /* string to add later */
 
2091
    struct hdr_line     *nlp, *lp;
 
2092
 
 
2093
    ostr = h->text;
 
2094
    nlp = h->next;
 
2095
    if(utf8_instr)
 
2096
      free_istr = istr = utf8_to_ucs4_cpystr(utf8_instr);
 
2097
 
 
2098
    len = ucs4_strlen(istr) + ucs4_strlen(ostr);
 
2099
    if((buf = (UCS *) malloc((len+10) * sizeof(*buf))) == NULL){
 
2100
        if(free_istr)
 
2101
          fs_give((void **) &free_istr);
 
2102
 
 
2103
        return(-1);
 
2104
    }
 
2105
 
 
2106
    if(ucs4_str_width(istr) + ucs4_str_width(ostr) >= maxwid){  /* break then fixup below */
 
2107
 
 
2108
        if((l=ucs4_str_width(istr)) < maxwid){          /* room for more */
 
2109
 
 
2110
            if(break_on_comma && (bp = ucs4_strqchr(istr, ',', &quoted, -1))){
 
2111
                bp += (bp[1] == ' ') ? 2 : 1;
 
2112
                for(tp = bp; *tp && *tp == ' '; tp++)
 
2113
                  ;
 
2114
 
 
2115
                ucs4_strncpy(buf, tp, len+10);
 
2116
                buf[len+10-1] = '\0';
 
2117
                ucs4_strncat(buf, ostr, len+10-ucs4_strlen(buf));
 
2118
                buf[len+10-1] = '\0';
 
2119
 
 
2120
                for(i = 0; &istr[i] < bp; i++)
 
2121
                  ostr[i] = istr[i];
 
2122
 
 
2123
                ostr[i] = '\0';
 
2124
                retval = TRUE;
 
2125
            }
 
2126
            else{
 
2127
                breakp = break_point(ostr, maxwid-ucs4_str_width(istr),
 
2128
                                     break_on_comma ? ',' : ' ',
 
2129
                                     break_on_comma ? &quoted : NULL);
 
2130
 
 
2131
                if(breakp == ostr){     /* no good breakpoint */
 
2132
                    if(break_on_comma && *breakp == ','){
 
2133
                        breakp = ostr + 1;
 
2134
                        retval = TRUE;
 
2135
                    }
 
2136
                    else if(ucs4_strchr(istr,(break_on_comma && !quoted)?',':' ')){
 
2137
                        ucs4_strncpy(buf, ostr, len+10);
 
2138
                        buf[len+10-1] = '\0';
 
2139
                        ucs4_strncpy(ostr, istr, HLSZ);
 
2140
                        ostr[HLSZ-1] = '\0';
 
2141
                    }
 
2142
                    else{               /* istr's broken as we can get it */
 
2143
                        /*
 
2144
                         * Break at maxwid - width of istr
 
2145
                         */
 
2146
                        breakp = ucs4_particular_width(ostr, maxwid - ucs4_str_width(istr)-1);
 
2147
                        retval = TRUE;
 
2148
                    }
 
2149
                }
 
2150
                else
 
2151
                  retval = TRUE;
 
2152
            
 
2153
                if(retval){
 
2154
                    ucs4_strncpy(buf, breakp, len+10);  /* save broken line */
 
2155
                    buf[len+10-1] = '\0';
 
2156
                    if(breakp == ostr){
 
2157
                        ucs4_strncpy(ostr, istr, HLSZ); /* simple if no break */
 
2158
                        ostr[HLSZ-1] = '\0';
 
2159
                    }
 
2160
                    else{
 
2161
                        *breakp = '\0';         /* more work to break it */
 
2162
                        i = ucs4_strlen(istr);
 
2163
                        /*
 
2164
                         * shift ostr i chars
 
2165
                         */
 
2166
                        for(bp=breakp; bp >= ostr && i; bp--)
 
2167
                          *(bp+i) = *bp;
 
2168
                        for(tp=ostr, bp=istr; *bp != '\0'; tp++, bp++)
 
2169
                          *tp = *bp;            /* then add istr */
 
2170
                    }
 
2171
                }
 
2172
            }
 
2173
        }
 
2174
        /*
 
2175
         * Short-circuit the recursion in this case.
 
2176
         * No time right now to figure out how to do it better.
 
2177
         */
 
2178
        else if(l > 2*maxwid){
 
2179
            UCS *istrp, *saveostr = NULL;
 
2180
 
 
2181
            retval = TRUE;
 
2182
            if(ostr && *ostr)
 
2183
              saveostr = ucs4_cpystr(ostr);
 
2184
 
 
2185
            istrp = istr;
 
2186
            while(l > 2*maxwid){
 
2187
                if(break_on_comma || maxwid == 1){
 
2188
                    breakp = (!(bp = ucs4_strqchr(istrp, ',', &quoted, maxwid))
 
2189
                              || ucs4_str_width_ptr_to_ptr(istrp, bp) >= maxwid || maxwid == 1)
 
2190
                               ? ucs4_particular_width(istrp, maxwid)
 
2191
                               : bp + ((bp[1] == ' ') ? 2 : 1);
 
2192
                }
 
2193
                else{
 
2194
                    breakp = break_point(istrp, maxwid, ' ', NULL);
 
2195
 
 
2196
                    if(breakp == istrp) /* no good break point */
 
2197
                      breakp =  ucs4_particular_width(istrp, maxwid-1);
 
2198
                }
 
2199
                
 
2200
                for(tp=ostr,bp=istrp; bp < breakp; tp++, bp++)
 
2201
                  *tp = *bp;
 
2202
 
 
2203
                *tp = '\0';
 
2204
                l -= ucs4_str_width_ptr_to_ptr(istrp, breakp);
 
2205
                istrp = breakp;
 
2206
 
 
2207
                if((lp = HALLOC()) == NULL){
 
2208
                    emlwrite("Can't allocate any more lines for header!", NULL);
 
2209
                    free(buf);
 
2210
                    if(free_istr)
 
2211
                      fs_give((void **) &free_istr);
 
2212
 
 
2213
                    return(-1);
 
2214
                }
 
2215
 
 
2216
                lp->next = h->next;
 
2217
                if(h->next)
 
2218
                  h->next->prev = lp;
 
2219
 
 
2220
                h->next = lp;
 
2221
                lp->prev = h;
 
2222
                lp->text[0] = '\0';
 
2223
                h = h->next;
 
2224
                ostr = h->text;
 
2225
            }
 
2226
 
 
2227
            /*
 
2228
             * Now l is still > maxwid. Do it the recursive way,
 
2229
             * like the else clause below. Surely we could fix up the
 
2230
             * flow control some here, but this works for now.
 
2231
             */
 
2232
 
 
2233
            nlp = h->next;
 
2234
            istr = istrp;
 
2235
            if(saveostr){
 
2236
                ucs4_strncpy(ostr, saveostr, HLSZ);
 
2237
                ostr[HLSZ-1] = '\0';
 
2238
                fs_give((void **) &saveostr);
 
2239
            }
 
2240
 
 
2241
            if(break_on_comma || maxwid == 1){
 
2242
                breakp = (!(bp = ucs4_strqchr(istrp, ',', &quoted, maxwid))
 
2243
                          || ucs4_str_width_ptr_to_ptr(istrp, bp) >= maxwid || maxwid == 1)
 
2244
                           ? ucs4_particular_width(istrp, maxwid)
 
2245
                           : bp + ((bp[1] == ' ') ? 2 : 1);
 
2246
            }
 
2247
            else{
 
2248
                breakp = break_point(istrp, maxwid, ' ', NULL);
 
2249
 
 
2250
                if(breakp == istrp)     /* no good break point */
 
2251
                  breakp =  ucs4_particular_width(istrp, maxwid-1);
 
2252
            }
 
2253
            
 
2254
            ucs4_strncpy(buf, breakp, len+10);  /* save broken line */
 
2255
            buf[len+10-1] = '\0';
 
2256
            ucs4_strncat(buf, ostr, len+10-ucs4_strlen(buf));   /* add line that was there */
 
2257
            buf[len+10-1] = '\0';
 
2258
 
 
2259
            for(tp=ostr,bp=istr; bp < breakp; tp++, bp++)
 
2260
              *tp = *bp;
 
2261
 
 
2262
            *tp = '\0';
 
2263
        }
 
2264
        else{                                   /* utf8_instr > maxwid ! */
 
2265
            if(break_on_comma || maxwid == 1){
 
2266
                breakp = (!(bp = ucs4_strqchr(istr, ',', &quoted, maxwid))
 
2267
                          || ucs4_str_width_ptr_to_ptr(istr, bp) >= maxwid || maxwid == 1)
 
2268
                           ? ucs4_particular_width(istr, maxwid)
 
2269
                           : bp + ((bp[1] == ' ') ? 2 : 1);
 
2270
            }
 
2271
            else{
 
2272
                breakp = break_point(istr, maxwid, ' ', NULL);
 
2273
 
 
2274
                if(breakp == istr)      /* no good break point */
 
2275
                  breakp =  ucs4_particular_width(istr, maxwid-1);
 
2276
            }
 
2277
            
 
2278
            ucs4_strncpy(buf, breakp, len+10);  /* save broken line */
 
2279
            buf[len+10-1] = '\0';
 
2280
            ucs4_strncat(buf, ostr, len+10-ucs4_strlen(buf));   /* add line that was there */
 
2281
            buf[len+10-1] = '\0';
 
2282
 
 
2283
            for(tp=ostr,bp=istr; bp < breakp; tp++, bp++)
 
2284
              *tp = *bp;
 
2285
 
 
2286
            *tp = '\0';
 
2287
        }
 
2288
 
 
2289
        if(nlp == NULL){                        /* no place to add below? */
 
2290
            if((lp = HALLOC()) == NULL){
 
2291
                emlwrite("Can't allocate any more lines for header!", NULL);
 
2292
                free(buf);
 
2293
                if(free_istr)
 
2294
                  fs_give((void **) &free_istr);
 
2295
 
 
2296
                return(-1);
 
2297
            }
 
2298
 
 
2299
            if(TERM_OPTIMIZE && (i = physical_line(h)) != -1)
 
2300
              scrolldown(wheadp, i - 1, 1);
 
2301
 
 
2302
            h->next = lp;                       /* fix up links */
 
2303
            lp->prev = h;
 
2304
            lp->next = NULL;
 
2305
            lp->text[0] = '\0';
 
2306
            nlp = lp;
 
2307
            retval = TRUE;
 
2308
        }
 
2309
    }
 
2310
    else{                                       /* combined width < max */
 
2311
        buf[0] = '\0';
 
2312
        if(istr && *istr){
 
2313
            ucs4_strncpy(buf, istr, len+10);    /* insert istr before ostr */
 
2314
            buf[len+10-1] = '\0';
 
2315
 
 
2316
            ucs4_strncat(buf, ostr, len+10-ucs4_strlen(buf));
 
2317
            buf[len+10-1] = '\0';
 
2318
 
 
2319
            ucs4_strncpy(ostr, buf, HLSZ);              /* copy back to ostr */
 
2320
            ostr[HLSZ-1] = '\0';
 
2321
        }
 
2322
 
 
2323
        *buf = '\0';
 
2324
        breakp = NULL;
 
2325
 
 
2326
        if(break_on_comma && (breakp = ucs4_strqchr(ostr, ',', &quoted, -1))){
 
2327
            breakp += (breakp[1] == ' ') ? 2 : 1;
 
2328
            ucs4_strncpy(buf, breakp, len+10);
 
2329
            buf[len+10-1] = '\0';
 
2330
            *breakp = '\0';
 
2331
 
 
2332
            if(*buf && !nlp){
 
2333
                if((lp = HALLOC()) == NULL){
 
2334
                    emlwrite("Can't allocate any more lines for header!",NULL);
 
2335
                    free(buf);
 
2336
                    if(free_istr)
 
2337
                      fs_give((void **) &free_istr);
 
2338
 
 
2339
                    return(-1);
 
2340
                }
 
2341
 
 
2342
                if(TERM_OPTIMIZE && (i = physical_line(h)) != -1)
 
2343
                  scrolldown(wheadp, i - 1, 1);
 
2344
 
 
2345
                h->next = lp;           /* fix up links */
 
2346
                lp->prev = h;
 
2347
                lp->next = NULL;
 
2348
                lp->text[0] = '\0';
 
2349
                nlp = lp;
 
2350
                retval = TRUE;
 
2351
            }
 
2352
        }
 
2353
 
 
2354
        if(nlp){
 
2355
            if(!*buf && !breakp){
 
2356
                if(ucs4_str_width(ostr) + ucs4_str_width(nlp->text) >= maxwid){ 
 
2357
                    breakp = break_point(nlp->text, maxwid-ucs4_str_width(ostr), 
 
2358
                                         break_on_comma ? ',' : ' ',
 
2359
                                         break_on_comma ? &quoted : NULL);
 
2360
                    
 
2361
                    if(breakp == nlp->text){    /* commas this line? */
 
2362
                        for(tp=ostr; *tp  && *tp != ' '; tp++)
 
2363
                          ;
 
2364
 
 
2365
                        if(!*tp){               /* no commas, get next best */
 
2366
                            breakp += maxwid - ucs4_str_width(ostr) - 1;
 
2367
                            retval = TRUE;
 
2368
                        }
 
2369
                        else
 
2370
                          retval = FALSE;
 
2371
                    }
 
2372
                    else
 
2373
                      retval = TRUE;
 
2374
 
 
2375
                    if(retval){                 /* only if something to do */
 
2376
                        for(tp = &ostr[ucs4_strlen(ostr)],bp=nlp->text; bp<breakp; 
 
2377
                        tp++, bp++)
 
2378
                          *tp = *bp;            /* add breakp to this line */
 
2379
                        *tp = '\0';
 
2380
                        for(tp=nlp->text, bp=breakp; *bp != '\0'; tp++, bp++)
 
2381
                          *tp = *bp;            /* shift next line to left */
 
2382
                        *tp = '\0';
 
2383
                    }
 
2384
                }
 
2385
                else{
 
2386
                    ucs4_strncat(ostr, nlp->text, HLSZ-ucs4_strlen(ostr));
 
2387
                    ostr[HLSZ-1] = '\0';
 
2388
 
 
2389
                    if(TERM_OPTIMIZE && (i = physical_line(nlp)) != -1)
 
2390
                      scrollup(wheadp, i, 1);
 
2391
 
 
2392
                    hldelete(nlp);
 
2393
 
 
2394
                    if(!(nlp = h->next)){
 
2395
                        free(buf);
 
2396
                        if(free_istr)
 
2397
                          fs_give((void **) &free_istr);
 
2398
 
 
2399
                        return(TRUE);           /* can't go further */
 
2400
                    }
 
2401
                    else
 
2402
                      retval = TRUE;            /* more work to do? */
 
2403
                }
 
2404
            }
 
2405
        }
 
2406
        else{
 
2407
            free(buf);
 
2408
            if(free_istr)
 
2409
              fs_give((void **) &free_istr);
 
2410
 
 
2411
            return(FALSE);
 
2412
        }
 
2413
 
 
2414
    }
 
2415
 
 
2416
    utf8 = ucs4_to_utf8_cpystr(buf);
 
2417
    free(buf);
 
2418
    if(free_istr)
 
2419
      fs_give((void **) &free_istr);
 
2420
 
 
2421
    if(utf8){
 
2422
        int rv;
 
2423
 
 
2424
        i = FormatLines(nlp, utf8, maxwid, break_on_comma, quoted);
 
2425
        fs_give((void **) &utf8);
 
2426
        switch(i){
 
2427
          case -1:                                      /* bubble up worst case */
 
2428
            rv = -1;
 
2429
            break;
 
2430
          case FALSE:
 
2431
            if(retval == FALSE){
 
2432
                rv = FALSE;
 
2433
                break;
 
2434
            }
 
2435
          default:
 
2436
            rv = TRUE;
 
2437
        }
 
2438
 
 
2439
        fs_give((void **) &utf8);
 
2440
        return(rv);
 
2441
    }
 
2442
    else
 
2443
      return(-1);
 
2444
}
 
2445
 
 
2446
/*
 
2447
 * Format the lines before parsing attachments so we
 
2448
 * don't expand a bunch of attachments that we don't
 
2449
 * have the buffer space for.
 
2450
 */
 
2451
int
 
2452
FormatSyncAttach(void)
 
2453
{
 
2454
    FormatLines(headents[ods.cur_e].hd_text, "",
 
2455
                term.t_ncol - headents[ods.cur_e].prwid,
 
2456
                headents[ods.cur_e].break_on_comma, 0);
 
2457
    return(SyncAttach());
 
2458
}
 
2459
 
 
2460
 
 
2461
/*
 
2462
 * PaintHeader - do the work of displaying the header from the given 
 
2463
 *               physical screen line the end of the header.
 
2464
 *
 
2465
 *       17 July 91 - fixed reshow to deal with arbitrarily large headers.
 
2466
 */
 
2467
void
 
2468
PaintHeader(int line,           /* physical line on screen */
 
2469
            int clear)          /* clear before painting */
 
2470
{
 
2471
    struct hdr_line *lp;
 
2472
    int              curline;
 
2473
    int              curindex;
 
2474
    int              curoffset;
 
2475
    UCS              buf[NLINE];
 
2476
    char             utf8buf[6*NLINE];
 
2477
    UCS             *bufp;
 
2478
    int              i, e, w;
 
2479
 
 
2480
    if(clear)
 
2481
      pclear(COMPOSER_TOP_LINE, ComposerTopLine);
 
2482
 
 
2483
    curline  = COMPOSER_TOP_LINE;
 
2484
    curindex = curoffset = 0;
 
2485
 
 
2486
    for(lp = ods.top_l, e = ods.top_e; ; curline++){
 
2487
        if((curline == line) || ((lp = next_hline(&e, lp)) == NULL))
 
2488
          break;
 
2489
    }
 
2490
 
 
2491
    while(headents[e].name != NULL){                    /* begin to redraw */
 
2492
        while(lp != NULL){
 
2493
            buf[0] = '\0';
 
2494
            if((!lp->prev || curline == COMPOSER_TOP_LINE) && !curoffset){
 
2495
                if(InvertPrompt(e, (e == ods.cur_e && ComposerEditing)) == -1
 
2496
                   && !is_blank(curline, 0, headents[e].prwid)){
 
2497
                    for(i = 0; i < headents[e].prwid; i++)
 
2498
                      buf[i] = ' ';
 
2499
 
 
2500
                    buf[i] = '\0';
 
2501
                }
 
2502
            }
 
2503
            else if(!is_blank(curline, 0, headents[e].prwid)){
 
2504
                for(i = 0; i < headents[e].prwid; i++)
 
2505
                  buf[i] = ' ';
 
2506
 
 
2507
                buf[i] = '\0';
 
2508
            }
 
2509
 
 
2510
            if(*(bufp = buf) != '\0'){          /* need to paint? */
 
2511
                movecursor(curline, 0);         /* paint the line... */
 
2512
                while(*bufp != '\0')
 
2513
                  pputc(*bufp++, 0);
 
2514
            }
 
2515
 
 
2516
            bufp = &(lp->text[curindex]);       /* skip chars already there */
 
2517
            curoffset += headents[e].prwid;
 
2518
            curindex = index_from_col(curline, curoffset);
 
2519
            while(pscr(curline, curindex) != NULL &&
 
2520
                  *bufp == pscr(curline, curindex)->c && *bufp != '\0'){
 
2521
                w = wcellwidth(*bufp);
 
2522
                curoffset += (w >= 0 ? w : 1);
 
2523
                ++bufp;
 
2524
                ++curindex;
 
2525
                if(curoffset >= term.t_ncol)
 
2526
                  break;
 
2527
            }
 
2528
 
 
2529
            if(*bufp != '\0'){                  /* need to move? */
 
2530
                movecursor(curline, curoffset);
 
2531
                while(*bufp != '\0'){           /* display what's not there */
 
2532
                    pputc(*bufp, 0);
 
2533
                    w = wcellwidth(*bufp);
 
2534
                    curoffset += (w >= 0 ? w : 1);
 
2535
                    ++bufp;
 
2536
                    ++curindex;
 
2537
                }
 
2538
            }
 
2539
 
 
2540
            if(curoffset < term.t_ncol){
 
2541
                     movecursor(curline, curoffset);
 
2542
                     peeol();
 
2543
            }
 
2544
            curline++;
 
2545
            curindex = curoffset = 0;
 
2546
            if(curline >= BOTTOM())
 
2547
              break;
 
2548
 
 
2549
            lp = lp->next;
 
2550
        }
 
2551
 
 
2552
        if(curline >= BOTTOM())
 
2553
          return;                               /* don't paint delimiter */
 
2554
 
 
2555
        while(headents[++e].name != NULL)
 
2556
          if(headents[e].display_it){
 
2557
              lp = headents[e].hd_text;
 
2558
              break;
 
2559
          }
 
2560
    }
 
2561
 
 
2562
    display_delimiter(ComposerEditing ? 0 : 1);
 
2563
}
 
2564
 
 
2565
 
 
2566
 
 
2567
/*
 
2568
 * PaintBody() - generic call to handle repainting everything BUT the 
 
2569
 *               header
 
2570
 *
 
2571
 *      notes:
 
2572
 *              The header redrawing in a level 0 body paint gets done
 
2573
 *              in update()
 
2574
 */
 
2575
void
 
2576
PaintBody(int level)
 
2577
{
 
2578
    curwp->w_flag |= WFHARD;                    /* make sure framing's right */
 
2579
    if(level == 0)                              /* specify what to update */
 
2580
        sgarbf = TRUE;
 
2581
 
 
2582
    update();                                   /* display message body */
 
2583
 
 
2584
    if(level == 0 && ComposerEditing){
 
2585
        mlerase();                              /* clear the error line */
 
2586
        ShowPrompt();
 
2587
    }
 
2588
}
 
2589
 
 
2590
 
 
2591
/*
 
2592
 * display_for_send - paint the composer from the top line and return.
 
2593
 */
 
2594
void
 
2595
display_for_send(void)
 
2596
{
 
2597
    int              i = 0;
 
2598
    struct hdr_line *l;
 
2599
 
 
2600
    /* if first header line isn't displayed, there's work to do */
 
2601
    if(headents && ((l = first_hline(&i)) != ods.top_l
 
2602
                    || ComposerTopLine == COMPOSER_TOP_LINE
 
2603
                    || !ods.p_line)){
 
2604
        struct on_display orig_ods;
 
2605
        int               orig_edit    = ComposerEditing,
 
2606
                          orig_ct_line = ComposerTopLine;
 
2607
 
 
2608
        /*
 
2609
         * fake that the cursor's in the first header line
 
2610
         * and force repaint...
 
2611
         */
 
2612
        orig_ods        = ods;
 
2613
        ods.cur_e       = i;
 
2614
        ods.top_l       = ods.cur_l = l;
 
2615
        ods.top_e       = ods.cur_e;
 
2616
        ods.p_line      = COMPOSER_TOP_LINE;
 
2617
        ComposerEditing = TRUE;                 /* to fool update() */
 
2618
        setimark(FALSE, 1);                     /* remember where we were */
 
2619
        gotobob(FALSE, 1);
 
2620
 
 
2621
        UpdateHeader(0);                        /* redraw whole enchilada */
 
2622
        PaintHeader(COMPOSER_TOP_LINE, TRUE);
 
2623
        PaintBody(0);
 
2624
 
 
2625
        ods = orig_ods;                         /* restore original state */
 
2626
        ComposerEditing = orig_edit;
 
2627
        ComposerTopLine = curwp->w_toprow = orig_ct_line;
 
2628
        curwp->w_ntrows = BOTTOM() - ComposerTopLine;
 
2629
        swapimark(FALSE, 1);
 
2630
 
 
2631
        /* in case we don't exit, set up restoring the screen */
 
2632
        sgarbf = TRUE;                          /* force redraw */
 
2633
    }
 
2634
}
 
2635
 
 
2636
 
 
2637
/*
 
2638
 * ArrangeHeader - set up display parm such that header is reasonably 
 
2639
 *                 displayed
 
2640
 */
 
2641
void
 
2642
ArrangeHeader(void)
 
2643
{
 
2644
    int      e;
 
2645
    register struct hdr_line *l;
 
2646
 
 
2647
    ods.p_line = ods.p_ind = 0;
 
2648
    e = ods.top_e = 0;
 
2649
    l = ods.top_l = headents[e].hd_text;
 
2650
    while(headents[e+1].name || (l && l->next))
 
2651
      if(l = next_sel_hline(&e, l)){
 
2652
          ods.cur_l = l;
 
2653
          ods.cur_e = e;
 
2654
      }
 
2655
 
 
2656
    UpdateHeader(1);
 
2657
}
 
2658
 
 
2659
 
 
2660
/*
 
2661
 * ComposerHelp() - display mail help in a context sensitive way
 
2662
 *                  based on the level passed ...
 
2663
 */
 
2664
int
 
2665
ComposerHelp(int level)
 
2666
{
 
2667
    char buf[80];
 
2668
    VARS_TO_SAVE *saved_state;
 
2669
 
 
2670
    curwp->w_flag |= WFMODE;
 
2671
    sgarbf = TRUE;
 
2672
 
 
2673
    if(level < 0 || !headents[level].name){
 
2674
        (*term.t_beep)();
 
2675
        emlwrite("Sorry, I can't help you with that.", NULL);
 
2676
        sleep(2);
 
2677
        return(FALSE);
 
2678
    }
 
2679
 
 
2680
    snprintf(buf, sizeof(buf), "Help for %s %.40s Field",
 
2681
                 (Pmaster->pine_flags & MDHDRONLY) ? "Address Book"
 
2682
                                                 : "Composer",
 
2683
                 headents[level].name);
 
2684
    saved_state = save_pico_state();
 
2685
    (*Pmaster->helper)(headents[level].help, buf, 1);
 
2686
    if(saved_state){
 
2687
        restore_pico_state(saved_state);
 
2688
        free_pico_state(saved_state);
 
2689
    }
 
2690
 
 
2691
    ttresize();
 
2692
    picosigs();                                 /* restore altered handlers */
 
2693
    return(TRUE);
 
2694
}
 
2695
 
 
2696
 
 
2697
 
 
2698
/*
 
2699
 * ToggleHeader() - set or unset pico values to the full screen size
 
2700
 *                  painting header if need be.
 
2701
 */
 
2702
int
 
2703
ToggleHeader(int show)
 
2704
{
 
2705
    /*
 
2706
     * check to see if we need to display the header... 
 
2707
     */
 
2708
    if(show){
 
2709
        UpdateHeader(0);                                /* figure bounds  */
 
2710
        PaintHeader(COMPOSER_TOP_LINE, FALSE);  /* draw it */
 
2711
    }
 
2712
    else{
 
2713
        /*
 
2714
         * set bounds for no header display
 
2715
         */
 
2716
        curwp->w_toprow = ComposerTopLine = COMPOSER_TOP_LINE;
 
2717
        curwp->w_ntrows = BOTTOM() - ComposerTopLine;
 
2718
    }
 
2719
    return(TRUE);
 
2720
}
 
2721
 
 
2722
 
 
2723
 
 
2724
/*
 
2725
 * HeaderLen() - return the length in lines of the exposed portion of the
 
2726
 *               header
 
2727
 */
 
2728
int
 
2729
HeaderLen(void)
 
2730
{
 
2731
    register struct hdr_line *lp;
 
2732
    int      e;
 
2733
    int      i;
 
2734
    
 
2735
    i = 1;
 
2736
    lp = ods.top_l;
 
2737
    e  = ods.top_e;
 
2738
    while(lp != NULL){
 
2739
        lp = next_hline(&e, lp);
 
2740
        i++;
 
2741
    }
 
2742
    return(i);
 
2743
}
 
2744
 
 
2745
 
 
2746
 
 
2747
/*
 
2748
 * first_hline() - return a pointer to the first displayable header line
 
2749
 * 
 
2750
 *      returns:
 
2751
 *              1) pointer to first displayable line in header and header
 
2752
 *                 entry, via side effect, that the first line is a part of
 
2753
 *              2) NULL if no next line, leaving entry at LASTHDR
 
2754
 */
 
2755
struct hdr_line *
 
2756
first_hline(int *entry)
 
2757
{
 
2758
    /* init *entry so we're sure to start from the top */
 
2759
    for(*entry = 0; headents[*entry].name; (*entry)++)
 
2760
      if(headents[*entry].display_it)
 
2761
        return(headents[*entry].hd_text);
 
2762
 
 
2763
    *entry = 0;
 
2764
    return(NULL);               /* this shouldn't happen */
 
2765
}
 
2766
 
 
2767
 
 
2768
/*
 
2769
 * first_sel_hline() - return a pointer to the first selectable header line
 
2770
 * 
 
2771
 *      returns:
 
2772
 *              1) pointer to first selectable line in header and header
 
2773
 *                 entry, via side effect, that the first line is a part of
 
2774
 *              2) NULL if no next line, leaving entry at LASTHDR
 
2775
 */
 
2776
struct hdr_line *
 
2777
first_sel_hline(int *entry)
 
2778
{
 
2779
    /* init *entry so we're sure to start from the top */
 
2780
    for(*entry = 0; headents[*entry].name; (*entry)++)
 
2781
      if(headents[*entry].display_it && !headents[*entry].blank)
 
2782
        return(headents[*entry].hd_text);
 
2783
 
 
2784
    *entry = 0;
 
2785
    return(NULL);               /* this shouldn't happen */
 
2786
}
 
2787
 
 
2788
 
 
2789
 
 
2790
/*
 
2791
 * next_hline() - return a pointer to the next line structure
 
2792
 * 
 
2793
 *      returns:
 
2794
 *              1) pointer to next displayable line in header and header
 
2795
 *                 entry, via side effect, that the next line is a part of
 
2796
 *              2) NULL if no next line, leaving entry at LASTHDR
 
2797
 */
 
2798
struct hdr_line *
 
2799
next_hline(int *entry, struct hdr_line *line)
 
2800
{
 
2801
    if(line == NULL)
 
2802
      return(NULL);
 
2803
 
 
2804
    if(line->next == NULL){
 
2805
        while(headents[++(*entry)].name != NULL){
 
2806
            if(headents[*entry].display_it)
 
2807
              return(headents[*entry].hd_text);
 
2808
        }
 
2809
        --(*entry);
 
2810
        return(NULL);
 
2811
    }
 
2812
    else
 
2813
      return(line->next);
 
2814
}
 
2815
 
 
2816
 
 
2817
/*
 
2818
 * next_sel_hline() - return a pointer to the next selectable line structure
 
2819
 * 
 
2820
 *      returns:
 
2821
 *              1) pointer to next selectable line in header and header
 
2822
 *                 entry, via side effect, that the next line is a part of
 
2823
 *              2) NULL if no next line, leaving entry at LASTHDR
 
2824
 */
 
2825
struct hdr_line *
 
2826
next_sel_hline(int *entry, struct hdr_line *line)
 
2827
{
 
2828
    if(line == NULL)
 
2829
      return(NULL);
 
2830
 
 
2831
    if(line->next == NULL){
 
2832
        while(headents[++(*entry)].name != NULL){
 
2833
            if(headents[*entry].display_it && !headents[*entry].blank)
 
2834
              return(headents[*entry].hd_text);
 
2835
        }
 
2836
        --(*entry);
 
2837
        return(NULL);
 
2838
    }
 
2839
    else
 
2840
      return(line->next);
 
2841
}
 
2842
 
 
2843
 
 
2844
 
 
2845
/*
 
2846
 * prev_hline() - return a pointer to the next line structure back
 
2847
 * 
 
2848
 *      returns:
 
2849
 *              1) pointer to previous displayable line in header and 
 
2850
 *                 the header entry that the next line is a part of 
 
2851
 *                 via side effect
 
2852
 *              2) NULL if no next line, leaving entry unchanged from
 
2853
 *                 the value it had on entry.
 
2854
 */
 
2855
struct hdr_line *
 
2856
prev_hline(int *entry, struct hdr_line *line)
 
2857
{
 
2858
    if(line == NULL)
 
2859
      return(NULL);
 
2860
 
 
2861
    if(line->prev == NULL){
 
2862
        int orig_entry;
 
2863
 
 
2864
        orig_entry = *entry;
 
2865
        while(--(*entry) >= 0){
 
2866
            if(headents[*entry].display_it){
 
2867
                line = headents[*entry].hd_text;
 
2868
                while(line->next != NULL)
 
2869
                  line = line->next;
 
2870
                return(line);
 
2871
            }
 
2872
        }
 
2873
 
 
2874
        *entry = orig_entry;
 
2875
        return(NULL);
 
2876
    }
 
2877
    else
 
2878
      return(line->prev);
 
2879
}
 
2880
 
 
2881
 
 
2882
/*
 
2883
 * prev_sel_hline() - return a pointer to the previous selectable line
 
2884
 * 
 
2885
 *      returns:
 
2886
 *              1) pointer to previous selectable line in header and 
 
2887
 *                 the header entry that the next line is a part of 
 
2888
 *                 via side effect
 
2889
 *              2) NULL if no next line, leaving entry unchanged from
 
2890
 *                 the value it had on entry.
 
2891
 */
 
2892
struct hdr_line *
 
2893
prev_sel_hline(int *entry, struct hdr_line *line)
 
2894
{
 
2895
    if(line == NULL)
 
2896
      return(NULL);
 
2897
 
 
2898
    if(line->prev == NULL){
 
2899
        int orig_entry;
 
2900
 
 
2901
        orig_entry = *entry;
 
2902
        while(--(*entry) >= 0){
 
2903
            if(headents[*entry].display_it && !headents[*entry].blank){
 
2904
                line = headents[*entry].hd_text;
 
2905
                while(line->next != NULL)
 
2906
                  line = line->next;
 
2907
                return(line);
 
2908
            }
 
2909
        }
 
2910
 
 
2911
        *entry = orig_entry;
 
2912
        return(NULL);
 
2913
    }
 
2914
    else
 
2915
      return(line->prev);
 
2916
}
 
2917
 
 
2918
 
 
2919
 
 
2920
/*
 
2921
 * first_requested_hline() - return pointer to first line that pico's caller
 
2922
 *                           asked that we start on.
 
2923
 */
 
2924
struct hdr_line *
 
2925
first_requested_hline(int *ent)
 
2926
{
 
2927
    int              i, reqfield;
 
2928
    struct hdr_line *rv = NULL;
 
2929
 
 
2930
    for(reqfield = -1, i = 0; headents[i].name;  i++)
 
2931
      if(headents[i].start_here){
 
2932
          headents[i].start_here = 0;           /* clear old setting */
 
2933
          if(reqfield < 0){                     /* if not already, set up */
 
2934
              headents[i].display_it = 1;       /* make sure it's shown */
 
2935
              *ent = reqfield = i;
 
2936
              rv = headents[i].hd_text;
 
2937
          }
 
2938
      }
 
2939
 
 
2940
    return(rv);
 
2941
}
 
2942
 
 
2943
 
 
2944
 
 
2945
/*
 
2946
 * UpdateHeader() - determines the best range of lines to be displayed 
 
2947
 *                  using the global ods value for the current line and the
 
2948
 *                  top line, also sets ComposerTopLine and pico limits
 
2949
 *
 
2950
 *      showtop -- Attempt to show all header lines if they'll fit.
 
2951
 *                    
 
2952
 *      notes:
 
2953
 *              This is pretty ugly because it has to keep the current line
 
2954
 *              on the screen in a reasonable location no matter what.
 
2955
 *              There are also a couple of rules to follow:
 
2956
 *                 1) follow paging conventions of pico (ie, half page 
 
2957
 *                    scroll)
 
2958
 *                 2) if more than one page, always display last half when 
 
2959
 *                    pline is toward the end of the header
 
2960
 * 
 
2961
 *      returns:
 
2962
 *             TRUE  if anything changed (side effects: new p_line, top_l
 
2963
 *                   top_e, and pico parms)
 
2964
 *             FALSE if nothing changed 
 
2965
 *             
 
2966
 */
 
2967
int
 
2968
UpdateHeader(int showtop)
 
2969
{
 
2970
    register struct     hdr_line        *lp;
 
2971
    int      i, le;
 
2972
    int      ret = FALSE;
 
2973
    int      old_top = ComposerTopLine;
 
2974
    int      old_p = ods.p_line;
 
2975
 
 
2976
    if(ods.p_line < COMPOSER_TOP_LINE ||
 
2977
       ((ods.p_line == ComposerTopLine-2) ? 2: 0) + ods.p_line >= BOTTOM()){
 
2978
        /* NewTop if cur header line is at bottom of screen or two from */
 
2979
        /* the bottom of the screen if cur line is bottom header line */
 
2980
        NewTop(showtop);                        /* get new top_l */
 
2981
        ret = TRUE;
 
2982
    }
 
2983
    else{                                       /* make sure p_line's OK */
 
2984
        i = COMPOSER_TOP_LINE;
 
2985
        lp = ods.top_l;
 
2986
        le = ods.top_e;
 
2987
        while(lp != ods.cur_l){
 
2988
            /*
 
2989
             * this checks to make sure cur_l is below top_l and that
 
2990
             * cur_l is on the screen...
 
2991
             */
 
2992
            if((lp = next_hline(&le, lp)) == NULL || ++i >= BOTTOM()){
 
2993
                NewTop(0);
 
2994
                ret = TRUE;
 
2995
                break;
 
2996
            }
 
2997
        }
 
2998
    }
 
2999
 
 
3000
    ods.p_line = COMPOSER_TOP_LINE;             /* find  p_line... */
 
3001
    lp = ods.top_l;
 
3002
    le = ods.top_e;
 
3003
    while(lp && lp != ods.cur_l){
 
3004
        lp = next_hline(&le, lp);
 
3005
        ods.p_line++;
 
3006
    }
 
3007
 
 
3008
    if(!ret)
 
3009
      ret = !(ods.p_line == old_p);
 
3010
 
 
3011
    ComposerTopLine = ods.p_line;               /* figure top composer line */
 
3012
    while(lp && ComposerTopLine <= BOTTOM()){
 
3013
        lp = next_hline(&le, lp);
 
3014
        ComposerTopLine += (lp) ? 1 : 2;        /* allow for delim at end   */
 
3015
    }
 
3016
 
 
3017
    if(!ret)
 
3018
      ret = !(ComposerTopLine == old_top);
 
3019
 
 
3020
    if(wheadp->w_toprow != ComposerTopLine){    /* update pico params... */
 
3021
        wheadp->w_toprow = ComposerTopLine;
 
3022
        wheadp->w_ntrows = ((i = BOTTOM() - ComposerTopLine) > 0) ? i : 0;
 
3023
        ret = TRUE;
 
3024
    }
 
3025
    return(ret);
 
3026
}
 
3027
 
 
3028
 
 
3029
 
 
3030
/*
 
3031
 * NewTop() - calculate a new top_l based on the cur_l
 
3032
 *
 
3033
 *      showtop -- Attempt to show all the header lines if they'll fit
 
3034
 *
 
3035
 *      returns:
 
3036
 *              with ods.top_l and top_e pointing at a reasonable line
 
3037
 *              entry
 
3038
 */
 
3039
void
 
3040
NewTop(int showtop)
 
3041
{
 
3042
    register struct hdr_line *lp;
 
3043
    register int i;
 
3044
    int      e;
 
3045
 
 
3046
    lp = ods.cur_l;
 
3047
    e  = ods.cur_e;
 
3048
    i  = showtop ? FULL_SCR() : HALF_SCR();
 
3049
 
 
3050
    while(lp != NULL && --i){
 
3051
        ods.top_l = lp;
 
3052
        ods.top_e = e;
 
3053
        lp = prev_hline(&e, lp);
 
3054
    }
 
3055
}
 
3056
 
 
3057
 
 
3058
 
 
3059
/*
 
3060
 * display_delimiter() - just paint the header/message body delimiter with
 
3061
 *                       inverse value specified by state.
 
3062
 */
 
3063
void
 
3064
display_delimiter(int state)
 
3065
{
 
3066
    UCS    *bufp, *buf;
 
3067
 
 
3068
    if(ComposerTopLine - 1 >= BOTTOM())         /* silently forget it */
 
3069
      return;
 
3070
 
 
3071
    buf = utf8_to_ucs4_cpystr((gmode & MDHDRONLY) ? "" : HDR_DELIM);
 
3072
    if(!buf)
 
3073
      return;
 
3074
 
 
3075
    bufp = buf;
 
3076
 
 
3077
    if(state == delim_ps){                      /* optimize ? */
 
3078
        for(delim_ps = 0; bufp[delim_ps] && pscr(ComposerTopLine-1,delim_ps) != NULL && pscr(ComposerTopLine-1,delim_ps)->c == bufp[delim_ps];delim_ps++)
 
3079
          ;
 
3080
 
 
3081
        if(bufp[delim_ps] == '\0' && !(gmode & MDHDRONLY)){
 
3082
            delim_ps = state;
 
3083
            fs_give((void **) &buf);
 
3084
            return;                             /* already displayed! */
 
3085
        }
 
3086
    }
 
3087
 
 
3088
    delim_ps = state;
 
3089
 
 
3090
    movecursor(ComposerTopLine - 1, 0);
 
3091
    if(state)
 
3092
      (*term.t_rev)(1);
 
3093
 
 
3094
    while(*bufp != '\0')
 
3095
      pputc(*bufp++, state ? 1 : 0);
 
3096
 
 
3097
    if(state)
 
3098
      (*term.t_rev)(0);
 
3099
 
 
3100
    peeol();
 
3101
    fs_give((void **) &buf);
 
3102
}
 
3103
 
 
3104
 
 
3105
 
 
3106
/*
 
3107
 * InvertPrompt() - invert the prompt associated with header entry to state
 
3108
 *                  state (true if invert, false otherwise).
 
3109
 *      returns:
 
3110
 *              non-zero if nothing done
 
3111
 *              0 if prompt inverted successfully
 
3112
 *
 
3113
 *      notes:
 
3114
 *              come to think of it, this func and the one above could
 
3115
 *              easily be combined
 
3116
 */
 
3117
int
 
3118
InvertPrompt(int entry, int state)
 
3119
{
 
3120
    UCS *buf, *bufp;
 
3121
    UCS *end;
 
3122
    int  i;
 
3123
 
 
3124
    buf = utf8_to_ucs4_cpystr(headents[entry].prompt);  /* fresh prompt paint */
 
3125
    if(!buf)
 
3126
      return(-1);
 
3127
 
 
3128
    bufp = buf;
 
3129
    if((i = entry_line(entry, FALSE)) == -1){
 
3130
      fs_give((void **) &buf);
 
3131
      return(-1);                               /* silently forget it */
 
3132
    }
 
3133
 
 
3134
    end = buf + ucs4_strlen(buf);
 
3135
 
 
3136
    /*
 
3137
     * Makes sure that the prompt doesn't take up more than prwid of screen space.
 
3138
     * The caller should do that, too, in order to make it look right so
 
3139
     * this should most likely be a no-op
 
3140
     */
 
3141
    if(ucs4_str_width_ptr_to_ptr(buf, end) > headents[entry].prwid){
 
3142
        end = ucs4_particular_width(buf, headents[entry].prwid);
 
3143
        *end = '\0';
 
3144
    }
 
3145
 
 
3146
    if(entry < 16 && (invert_ps&(1<<entry)) 
 
3147
       == (state ? 1<<entry : 0)){      /* optimize ? */
 
3148
        int j;
 
3149
 
 
3150
        for(j = 0; bufp[j] && pscr(i, j)->c == bufp[j]; j++)
 
3151
          ;
 
3152
 
 
3153
        if(bufp[j] == '\0'){
 
3154
            if(state)
 
3155
              invert_ps |= 1<<entry;
 
3156
            else
 
3157
              invert_ps &= ~(1<<entry);
 
3158
 
 
3159
            fs_give((void **) &buf);
 
3160
            return(0);                          /* already displayed! */
 
3161
        }
 
3162
    }
 
3163
 
 
3164
    if(entry < 16){  /* if > 16, cannot be stored in invert_ps */
 
3165
      if(state)
 
3166
        invert_ps |= 1<<entry;
 
3167
      else
 
3168
        invert_ps &= ~(1<<entry);
 
3169
    }
 
3170
 
 
3171
    movecursor(i, 0);
 
3172
    if(state)
 
3173
      (*term.t_rev)(1);
 
3174
 
 
3175
    while(*bufp && *(bufp + 1))
 
3176
      pputc(*bufp++, 1);                        /* putc upto last char */
 
3177
 
 
3178
    if(state)
 
3179
      (*term.t_rev)(0);
 
3180
 
 
3181
    pputc(*bufp, 0);                            /* last char not inverted */
 
3182
 
 
3183
    fs_give((void **) &buf);
 
3184
 
 
3185
    return(TRUE);
 
3186
}
 
3187
 
 
3188
 
 
3189
 
 
3190
/*
 
3191
 * partial_entries() - toggle display of the bcc and fcc fields.
 
3192
 *
 
3193
 *      returns:
 
3194
 *              TRUE if there are partial entries on the display
 
3195
 *              FALSE otherwise.
 
3196
 */
 
3197
int
 
3198
partial_entries(void)
 
3199
{
 
3200
    register struct headerentry *h;
 
3201
    int                          is_on;
 
3202
  
 
3203
    /*---- find out status of first rich header ---*/
 
3204
    for(h = headents; !h->rich_header && h->name != NULL; h++)
 
3205
      ;
 
3206
 
 
3207
    is_on = h->display_it;
 
3208
    for(h = headents; h->name != NULL; h++) 
 
3209
      if(h->rich_header) 
 
3210
        h->display_it = ! is_on;
 
3211
 
 
3212
    return(is_on);
 
3213
}
 
3214
 
 
3215
 
 
3216
 
 
3217
/*
 
3218
 * entry_line() - return the physical line on the screen associated
 
3219
 *                with the given header entry field.  Note: the field
 
3220
 *                may span lines, so if the last char is set, return
 
3221
 *                the appropriate value.
 
3222
 *
 
3223
 *      returns:
 
3224
 *             1) physical line number of entry
 
3225
 *             2) -1 if entry currently not on display
 
3226
 */
 
3227
int
 
3228
entry_line(int entry, int lastchar)
 
3229
{
 
3230
    register int    p_line = COMPOSER_TOP_LINE;
 
3231
    int    i;
 
3232
    register struct hdr_line    *line;
 
3233
 
 
3234
    for(line = ods.top_l, i = ods.top_e;
 
3235
        headents && headents[i].name && i <= entry;
 
3236
        p_line++){
 
3237
        if(p_line >= BOTTOM())
 
3238
          break;
 
3239
        if(i == entry){
 
3240
            if(lastchar){
 
3241
                if(line->next == NULL)
 
3242
                  return(p_line);
 
3243
            }
 
3244
            else if(line->prev == NULL)
 
3245
              return(p_line);
 
3246
            else
 
3247
              return(-1);
 
3248
        }
 
3249
        line = next_hline(&i, line);
 
3250
    }
 
3251
    return(-1);
 
3252
}
 
3253
 
 
3254
 
 
3255
 
 
3256
/*
 
3257
 * physical_line() - return the physical line on the screen associated
 
3258
 *                   with the given header line pointer.
 
3259
 *
 
3260
 *      returns:
 
3261
 *             1) physical line number of entry
 
3262
 *             2) -1 if entry currently not on display
 
3263
 */
 
3264
int
 
3265
physical_line(struct hdr_line *l)
 
3266
{
 
3267
    register int    p_line = COMPOSER_TOP_LINE;
 
3268
    register struct hdr_line    *lp;
 
3269
    int    i;
 
3270
 
 
3271
    for(lp=ods.top_l, i=ods.top_e; headents[i].name && lp != NULL; p_line++){
 
3272
        if(p_line >= BOTTOM())
 
3273
          break;
 
3274
 
 
3275
        if(lp == l)
 
3276
          return(p_line);
 
3277
 
 
3278
        lp = next_hline(&i, lp);
 
3279
    }
 
3280
    return(-1);
 
3281
}
 
3282
 
 
3283
 
 
3284
 
 
3285
/*
 
3286
 * call_builder() - resolve any nicknames in the address book associated
 
3287
 *                  with the given entry...
 
3288
 *
 
3289
 *    NOTES:
 
3290
 * 
 
3291
 *      BEWARE: this function can cause cur_l and top_l to get lost so BE 
 
3292
 *              CAREFUL before and after you call this function!!!
 
3293
 * 
 
3294
 *      There could to be something here to resolve cur_l and top_l
 
3295
 *      reasonably into the new linked list for this entry.  
 
3296
 *
 
3297
 *      The reason this would mostly work without it is resolve_niks gets
 
3298
 *      called for the most part in between fields.  Since we're moving
 
3299
 *      to the beginning or end (i.e. the next/prev pointer in the old 
 
3300
 *      freed cur_l is NULL) of the next entry, we get a new cur_l
 
3301
 *      pointing at a good line.  Then since top_l is based on cur_l in
 
3302
 *      NewTop() we have pretty much lucked out.
 
3303
 * 
 
3304
 *      Where we could get burned is in a canceled exit (ctrl|x).  Here
 
3305
 *      nicknames get resolved into addresses, which invalidates cur_l
 
3306
 *      and top_l.  Since we don't actually leave, we could begin editing
 
3307
 *      again with bad pointers.  This would usually results in a nice 
 
3308
 *      core dump.
 
3309
 *
 
3310
 *      NOTE: The mangled argument is a little strange. It's used on both
 
3311
 *      input and output. On input, if it is not set, then that tells the
 
3312
 *      builder not to do anything that might take a long time, like a
 
3313
 *      white pages lookup. On return, it tells the caller that the screen
 
3314
 *      and signals may have been mangled so signals should be reset, window
 
3315
 *      resized, and screen redrawn.
 
3316
 *
 
3317
 *      RETURNS:
 
3318
 *              > 0 if any names where resolved, otherwise
 
3319
 *                0 if not, or
 
3320
 *              < 0 on error
 
3321
 *                -1: move to next line
 
3322
 *                -2: don't move off this line
 
3323
 */
 
3324
int
 
3325
call_builder(struct headerentry *entry, int *mangled, char **err)
 
3326
{
 
3327
    register    int     retval = 0;
 
3328
    register    int     i;
 
3329
    register    struct  hdr_line  *line;
 
3330
    int          quoted = 0;
 
3331
    int          sbuflen;
 
3332
    char        *sbuf;
 
3333
    char        *s = NULL;
 
3334
    char        *tmp;
 
3335
    struct headerentry *e;
 
3336
    BUILDER_ARG *nextarg, *arg = NULL, *headarg = NULL;
 
3337
    VARS_TO_SAVE *saved_state;
 
3338
 
 
3339
    if(!entry->builder)
 
3340
      return(0);
 
3341
 
 
3342
    line = entry->hd_text;
 
3343
    sbuflen = 0;
 
3344
    while(line != NULL){
 
3345
        sbuflen += (6*term.t_ncol);
 
3346
        line = line->next;
 
3347
    }
 
3348
    
 
3349
    if((sbuf=(char *)malloc(sbuflen * sizeof(*sbuf))) == NULL){
 
3350
        emlwrite("Can't malloc space to expand address", NULL);
 
3351
        return(-1);
 
3352
    }
 
3353
    
 
3354
    *sbuf = '\0';
 
3355
 
 
3356
    /*
 
3357
     * cat the whole entry into one string...
 
3358
     */
 
3359
    line = entry->hd_text;
 
3360
    while(line != NULL){
 
3361
        i = ucs4_strlen(line->text);
 
3362
 
 
3363
        /*
 
3364
         * To keep pine address builder happy, addresses should be separated
 
3365
         * by ", ".  Add this space if needed, otherwise...
 
3366
         * (This is some ancient requirement that is no longer needed.)
 
3367
         *
 
3368
         * If this line is NOT a continuation of the previous line, add
 
3369
         * white space for pine's address builder if its not already there...
 
3370
         * (This is some ancient requirement that is no longer needed.)
 
3371
         *
 
3372
         * Also if it's not a continuation (i.e., there's already and addr on 
 
3373
         * the line), and there's another line below, treat the new line as
 
3374
         * an implied comma.
 
3375
         * (This should only be done for address-type lines, not for regular
 
3376
         * text lines like subjects. Key off of the break_on_comma bit which
 
3377
         * should only be set on those that won't mind a comma being added.)
 
3378
         */
 
3379
        if(entry->break_on_comma){
 
3380
            UCS *space, commaspace[3];
 
3381
 
 
3382
            commaspace[0] = ',';
 
3383
            commaspace[1] = ' ';
 
3384
            commaspace[2] = '\0';
 
3385
            space = commaspace+1;
 
3386
 
 
3387
            if(i && line->text[i-1] == ','){
 
3388
              ucs4_strncat(line->text, space, HLSZ-i);  /* help address builder */
 
3389
              line->text[HLSZ-1] = '\0';
 
3390
            }
 
3391
            else if(line->next != NULL && !strend(line->text, ',')){
 
3392
                if(ucs4_strqchr(line->text, ',', &quoted, -1)){
 
3393
                  ucs4_strncat(line->text, commaspace, HLSZ-i); /* implied comma */
 
3394
                  line->text[HLSZ-1] = '\0';
 
3395
                }
 
3396
            }
 
3397
            else if(line->prev != NULL && line->next != NULL){
 
3398
                if(ucs4_strchr(line->prev->text, ' ') != NULL 
 
3399
                   && line->text[i-1] != ' '){
 
3400
                  ucs4_strncat(line->text, space, HLSZ-i);
 
3401
                  line->text[HLSZ-1] = '\0';
 
3402
                }
 
3403
            }
 
3404
        }
 
3405
 
 
3406
        tmp = ucs4_to_utf8_cpystr(line->text);
 
3407
        if(tmp){
 
3408
            strncat(sbuf, tmp, sbuflen-strlen(sbuf));
 
3409
            sbuf[sbuflen-1] = '\0';
 
3410
            fs_give((void **) &tmp);
 
3411
        }
 
3412
 
 
3413
        line = line->next;
 
3414
    }
 
3415
 
 
3416
    if(entry->affected_entry){
 
3417
        /* check if any non-sticky affected entries */
 
3418
        for(e = entry->affected_entry; e; e = e->next_affected)
 
3419
          if(!e->sticky)
 
3420
            break;
 
3421
 
 
3422
        /* there is at least one non-sticky so make a list to pass */
 
3423
        if(e){
 
3424
            for(e = entry->affected_entry; e; e = e->next_affected){
 
3425
                if(!arg){
 
3426
                    headarg = arg = (BUILDER_ARG *)malloc(sizeof(BUILDER_ARG));
 
3427
                    if(!arg){
 
3428
                        emlwrite("Can't malloc space for fcc", NULL);
 
3429
                        return(-1);
 
3430
                    }
 
3431
                    else{
 
3432
                        arg->next = NULL;
 
3433
                        arg->tptr = NULL;
 
3434
                        arg->aff  = &(e->bldr_private);
 
3435
                        arg->me   = &(entry->bldr_private);
 
3436
                    }
 
3437
                }
 
3438
                else{
 
3439
                    nextarg = (BUILDER_ARG *)malloc(sizeof(BUILDER_ARG));
 
3440
                    if(!nextarg){
 
3441
                        emlwrite("Can't malloc space for fcc", NULL);
 
3442
                        return(-1);
 
3443
                    }
 
3444
                    else{
 
3445
                        nextarg->next = NULL;
 
3446
                        nextarg->tptr = NULL;
 
3447
                        nextarg->aff  = &(e->bldr_private);
 
3448
                        nextarg->me   = &(entry->bldr_private);
 
3449
                        arg->next     = nextarg;
 
3450
                        arg           = arg->next;
 
3451
                    }
 
3452
                }
 
3453
 
 
3454
                if(!e->sticky){
 
3455
                    line = e->hd_text;
 
3456
                    arg->tptr = ucs4_to_utf8_cpystr(line->text);
 
3457
                }
 
3458
            }
 
3459
        }
 
3460
    }
 
3461
 
 
3462
    /*
 
3463
     * Even if there are no affected entries, we still need the arg
 
3464
     * to pass the "me" pointer.
 
3465
     */
 
3466
    if(!headarg){
 
3467
        headarg = (BUILDER_ARG *)malloc(sizeof(BUILDER_ARG));
 
3468
        if(!headarg){
 
3469
            emlwrite("Can't malloc space", NULL);
 
3470
            return(-1);
 
3471
        }
 
3472
        else{
 
3473
            headarg->next = NULL;
 
3474
            headarg->tptr = NULL;
 
3475
            headarg->aff  = NULL;
 
3476
            headarg->me   = &(entry->bldr_private);
 
3477
        }
 
3478
    }
 
3479
 
 
3480
    /*
 
3481
     * The builder may make a new call back to pico() so we save and
 
3482
     * restore the pico state.
 
3483
     */
 
3484
    saved_state = save_pico_state();
 
3485
    retval = (*entry->builder)(sbuf, &s, err, headarg, mangled);
 
3486
    if(saved_state){
 
3487
        restore_pico_state(saved_state);
 
3488
        free_pico_state(saved_state);
 
3489
    }
 
3490
 
 
3491
    if(mangled && *mangled & BUILDER_MESSAGE_DISPLAYED){
 
3492
        *mangled &= ~ BUILDER_MESSAGE_DISPLAYED;
 
3493
        if(mpresf == FALSE)
 
3494
          mpresf = TRUE;
 
3495
    }
 
3496
 
 
3497
    if(retval >= 0){
 
3498
        if(strcmp(sbuf, s)){
 
3499
            line = entry->hd_text;
 
3500
            InitEntryText(s, entry);            /* arrange new one */
 
3501
            zotentry(line);                     /* blast old list o'entries */
 
3502
            entry->dirty = 1;                   /* mark it dirty */
 
3503
            retval = 1;
 
3504
        }
 
3505
 
 
3506
        for(e = entry->affected_entry, arg = headarg;
 
3507
            e;
 
3508
            e = e->next_affected, arg = arg ? arg->next : NULL){
 
3509
            if(!e->sticky){
 
3510
                line = e->hd_text;
 
3511
                tmp = ucs4_to_utf8_cpystr(line->text);
 
3512
                if(strcmp(tmp, arg ? arg->tptr : "")){ /* it changed */
 
3513
                    /* make sure they see it if changed */
 
3514
                    e->display_it = 1;
 
3515
                    InitEntryText(arg ? arg->tptr : "", e);
 
3516
                    if(line == ods.top_l)
 
3517
                      ods.top_l = e->hd_text;
 
3518
 
 
3519
                    zotentry(line);     /* blast old list o'entries */
 
3520
                    e->dirty = 1;       /* mark it dirty */
 
3521
                    retval = 1;
 
3522
                }
 
3523
 
 
3524
                if(tmp)
 
3525
                  fs_give((void **) &tmp);
 
3526
            }
 
3527
        }
 
3528
    }
 
3529
 
 
3530
    if(s)
 
3531
      free(s);
 
3532
 
 
3533
    for(arg = headarg; arg; arg = nextarg){
 
3534
        /* Don't free xtra or me, they just point to headerentry data */
 
3535
        nextarg = arg->next;
 
3536
        if(arg->tptr)
 
3537
          free(arg->tptr);
 
3538
        
 
3539
        free(arg);
 
3540
    }
 
3541
 
 
3542
    free(sbuf);
 
3543
    return(retval);
 
3544
}
 
3545
 
 
3546
 
 
3547
void
 
3548
call_expander(void)
 
3549
{
 
3550
    char        **s = NULL;
 
3551
    VARS_TO_SAVE *saved_state;
 
3552
    int           expret;
 
3553
 
 
3554
    if(!Pmaster->expander)
 
3555
      return;
 
3556
 
 
3557
    /*
 
3558
     * Since expander may make a call back to pico() we need to
 
3559
     * save and restore pico state.
 
3560
     */
 
3561
    if((saved_state = save_pico_state()) != NULL){
 
3562
 
 
3563
        expret = (*Pmaster->expander)(headents, &s);
 
3564
 
 
3565
        restore_pico_state(saved_state);
 
3566
        free_pico_state(saved_state);
 
3567
        ttresize();
 
3568
        picosigs();
 
3569
 
 
3570
        if(expret > 0 && s){
 
3571
            char               *tbuf, *p;
 
3572
            int                 i, biggest = 100;
 
3573
            struct headerentry *e;
 
3574
 
 
3575
            /*
 
3576
             * Use tbuf to cat together multiple line entries before comparing.
 
3577
             */
 
3578
            tbuf = (char *)malloc((biggest+1) * sizeof(*tbuf));
 
3579
            for(e = headents, i=0; e->name != NULL; e++,i++){
 
3580
                int sz = 0;
 
3581
                struct hdr_line *line;
 
3582
 
 
3583
                while(e->name && e->blank)
 
3584
                  e++;
 
3585
                
 
3586
                if(e->name == NULL)
 
3587
                  continue;
 
3588
 
 
3589
                for(line = e->hd_text; line != NULL; line = line->next){
 
3590
                  p = ucs4_to_utf8_cpystr(line->text);
 
3591
                  if(p){
 
3592
                    sz += strlen(p);
 
3593
                    fs_give((void **) &p);
 
3594
                  }
 
3595
                }
 
3596
                
 
3597
                if(sz > biggest){
 
3598
                    biggest = sz;
 
3599
                    free(tbuf);
 
3600
                    tbuf = (char *)malloc((biggest+1) * sizeof(*tbuf));
 
3601
                }
 
3602
 
 
3603
                tbuf[0] = '\0';
 
3604
                for(line = e->hd_text; line != NULL; line = line->next){
 
3605
                  p = ucs4_to_utf8_cpystr(line->text);
 
3606
                  if(p){
 
3607
                    strncat(tbuf, p, biggest+1-strlen(tbuf));
 
3608
                    tbuf[biggest] = '\0';
 
3609
                    fs_give((void **) &p);
 
3610
                  }
 
3611
                }
 
3612
                  
 
3613
                if(strcmp(tbuf, s[i])){ /* it changed */
 
3614
                    struct hdr_line *zline;
 
3615
 
 
3616
                    line = zline = e->hd_text;
 
3617
                    InitEntryText(s[i], e);
 
3618
 
 
3619
                    /*
 
3620
                     * If any of the lines for this entry are current or
 
3621
                     * top, fix that.
 
3622
                     */
 
3623
                    for(; line != NULL; line = line->next){
 
3624
                        if(line == ods.top_l)
 
3625
                          ods.top_l = e->hd_text;
 
3626
 
 
3627
                        if(line == ods.cur_l)
 
3628
                          ods.cur_l = e->hd_text;
 
3629
                    }
 
3630
 
 
3631
                    zotentry(zline);    /* blast old list o'entries */
 
3632
                }
 
3633
            }
 
3634
 
 
3635
            free(tbuf);
 
3636
        }
 
3637
 
 
3638
        if(s){
 
3639
            char **p;
 
3640
 
 
3641
            for(p = s; *p; p++)
 
3642
              free(*p);
 
3643
 
 
3644
            free(s);
 
3645
        }
 
3646
    }
 
3647
 
 
3648
    return;
 
3649
}
 
3650
 
 
3651
 
 
3652
/*
 
3653
 * strend - neglecting white space, returns TRUE if c is at the
 
3654
 *          end of the given line.  otherwise FALSE.
 
3655
 */
 
3656
int
 
3657
strend(UCS *s, UCS ch)
 
3658
{
 
3659
    UCS *b;
 
3660
 
 
3661
    if(s == NULL || *s == '\0')
 
3662
      return(FALSE);
 
3663
 
 
3664
    for(b = &s[ucs4_strlen(s)] - 1; *b && ucs4_isspace(*b); b--){
 
3665
        if(b == s)
 
3666
          return(FALSE);
 
3667
    }
 
3668
 
 
3669
    return(*b == ch);
 
3670
}
 
3671
 
 
3672
 
 
3673
/*
 
3674
 * ucs4_strqchr - returns pointer to first non-quote-enclosed occurance of ch in 
 
3675
 *           the given string.  otherwise NULL.
 
3676
 *      s -- the string
 
3677
 *     ch -- the character we're looking for
 
3678
 *      q -- q tells us if we start out inside quotes on entry and is set
 
3679
 *           correctly on exit.
 
3680
 *      m -- max characters we'll check for ch (set to -1 for no max)
 
3681
 */
 
3682
UCS *
 
3683
ucs4_strqchr(UCS *s, UCS ch, int *q, int m)
 
3684
{
 
3685
    int  quoted = (q) ? *q : 0;
 
3686
 
 
3687
    for(; s && *s && m != 0; s++, m--){
 
3688
        if(*s == '"'){
 
3689
            quoted = !quoted;
 
3690
            if(q)
 
3691
              *q = quoted;
 
3692
        }
 
3693
 
 
3694
        if(!quoted && *s == ch)
 
3695
          return(s);
 
3696
    }
 
3697
 
 
3698
    return(NULL);
 
3699
}
 
3700
 
 
3701
 
 
3702
/*
 
3703
 * KillHeaderLine() - kill a line in the header
 
3704
 *
 
3705
 *      notes:
 
3706
 *              This is pretty simple.  Just using the emacs kill buffer
 
3707
 *              and its accompanying functions to cut the text from lines.
 
3708
 *
 
3709
 *      returns:
 
3710
 *              TRUE if hldelete worked
 
3711
 *              FALSE otherwise
 
3712
 */
 
3713
int
 
3714
KillHeaderLine(struct hdr_line *l, int append)
 
3715
{
 
3716
    UCS *c;
 
3717
    int i = ods.p_ind;
 
3718
    int nl = TRUE;
 
3719
 
 
3720
    if(!append)
 
3721
        kdelete();
 
3722
 
 
3723
    c = l->text;
 
3724
    if (gmode & MDDTKILL){
 
3725
        if (c[i] == '\0')  /* don't insert a new line after this line*/
 
3726
          nl = FALSE;
 
3727
        /*put to be deleted part into kill buffer */
 
3728
        for (i=ods.p_ind; c[i] != '\0'; i++) 
 
3729
          kinsert(c[i]);                       
 
3730
    }else{
 
3731
        while(*c != '\0')                               /* splat out the line */
 
3732
          kinsert(*c++);
 
3733
    }
 
3734
 
 
3735
    if (nl)
 
3736
        kinsert('\n');                          /* helpful to yank in body */
 
3737
 
 
3738
#ifdef _WINDOWS
 
3739
    mswin_killbuftoclip (kremove);
 
3740
#endif
 
3741
 
 
3742
    if (gmode & MDDTKILL){
 
3743
        if (l->text[0]=='\0'){
 
3744
 
 
3745
           if(l->next && l->prev)
 
3746
              ods.cur_l = next_hline(&ods.cur_e, l);
 
3747
           else if(l->prev)
 
3748
              ods.cur_l = prev_hline(&ods.cur_e, l);
 
3749
 
 
3750
           if(l == ods.top_l)
 
3751
              ods.top_l = ods.cur_l;
 
3752
 
 
3753
           return(hldelete(l));
 
3754
        }
 
3755
        else {
 
3756
          l->text[ods.p_ind]='\0';    /* delete part of the line from the cursor */
 
3757
          return(TRUE);
 
3758
        }
 
3759
    }else{
 
3760
        if(l->next && l->prev)
 
3761
           ods.cur_l = next_hline(&ods.cur_e, l);
 
3762
        else if(l->prev)
 
3763
           ods.cur_l = prev_hline(&ods.cur_e, l);
 
3764
 
 
3765
        if(l == ods.top_l)
 
3766
           ods.top_l = ods.cur_l;
 
3767
 
 
3768
        return(hldelete(l));                    /* blast it  */
 
3769
    }
 
3770
}
 
3771
 
 
3772
 
 
3773
 
 
3774
/*
 
3775
 * SaveHeaderLines() - insert the saved lines in the list before the 
 
3776
 *                     current line in the header
 
3777
 *
 
3778
 *      notes:
 
3779
 *              Once again, just using emacs' kill buffer and its 
 
3780
 *              functions.
 
3781
 *
 
3782
 *      returns:
 
3783
 *              TRUE if something good happend
 
3784
 *              FALSE otherwise
 
3785
 */
 
3786
int
 
3787
SaveHeaderLines(void)
 
3788
{
 
3789
    UCS     *buf;                       /* malloc'd copy of buffer */
 
3790
    UCS     *bp;                        /* pointer to above buffer */
 
3791
    register unsigned   i;                      /* index */
 
3792
    UCS     *work_buf, *work_buf_begin;
 
3793
    char     empty[1];
 
3794
    int      len, buf_len, work_buf_len, tentative_p_ind = 0;
 
3795
    struct hdr_line *travel, *tentative_cur_l = NULL;
 
3796
 
 
3797
    if(ksize()){
 
3798
        if((bp = buf = (UCS *) malloc((ksize()+5) * sizeof(*buf))) == NULL){
 
3799
            emlwrite("Can't malloc space for saved text", NULL);
 
3800
            return(FALSE);
 
3801
        }
 
3802
    }
 
3803
    else
 
3804
      return(FALSE);
 
3805
 
 
3806
    for(i=0; i < ksize(); i++)
 
3807
      if(kremove(i) != '\n')                    /* filter out newlines */
 
3808
        *bp++ = (UCS) kremove(i);
 
3809
 
 
3810
    *bp = '\0';
 
3811
 
 
3812
    while(--bp >= buf)                          /* kill trailing white space */
 
3813
      if(*bp != ' '){
 
3814
          if(ods.cur_l->text[0] != '\0'){
 
3815
              if(*bp == '>'){                   /* inserting an address */
 
3816
                  *++bp = ',';                  /* so add separator */
 
3817
                  *++bp = '\0';
 
3818
              }
 
3819
          }
 
3820
          else{                                 /* nothing in field yet */
 
3821
              if(*bp == ','){                   /* so blast any extra */
 
3822
                  *bp = '\0';                   /* separators */
 
3823
              }
 
3824
          }
 
3825
          break;
 
3826
      }
 
3827
 
 
3828
    /* insert new text at the dot position */
 
3829
    buf_len      = ucs4_strlen(buf);
 
3830
    tentative_p_ind = ods.p_ind + buf_len;
 
3831
    work_buf_len = ucs4_strlen(ods.cur_l->text) + buf_len;
 
3832
    work_buf = (UCS *) malloc((work_buf_len + 1) * sizeof(UCS));
 
3833
    if (work_buf == NULL) {
 
3834
        emlwrite("Can't malloc space for saved text", NULL);
 
3835
        return(FALSE);
 
3836
    }
 
3837
 
 
3838
    work_buf[0] = '\0';
 
3839
    work_buf_begin = work_buf;
 
3840
    i = MIN(ods.p_ind, work_buf_len);
 
3841
    ucs4_strncpy(work_buf, ods.cur_l->text, i);
 
3842
    work_buf[i] = '\0';
 
3843
    ucs4_strncat(work_buf, buf, work_buf_len+1);
 
3844
    work_buf[work_buf_len] = '\0';
 
3845
    ucs4_strncat(work_buf, &ods.cur_l->text[ods.p_ind], work_buf_len+1);
 
3846
    work_buf[work_buf_len] = '\0';
 
3847
    empty[0]='\0';
 
3848
    ods.p_ind = 0;
 
3849
 
 
3850
    i = TRUE;
 
3851
 
 
3852
    /* insert text in HLSZ character chunks */
 
3853
    while(work_buf_len + ods.p_ind > HLSZ) {
 
3854
        ucs4_strncpy(&ods.cur_l->text[ods.p_ind], work_buf, HLSZ-ods.p_ind);
 
3855
        work_buf += (HLSZ - ods.p_ind);
 
3856
        work_buf_len -= (HLSZ - ods.p_ind);
 
3857
 
 
3858
        if(FormatLines(ods.cur_l, empty, LINEWID(),
 
3859
                       headents[ods.cur_e].break_on_comma, 0) == -1) {
 
3860
           i = FALSE;
 
3861
           break;
 
3862
        } else {
 
3863
           i = TRUE;
 
3864
          len = 0;
 
3865
          travel = ods.cur_l;
 
3866
          while (len < HLSZ){
 
3867
              len += ucs4_strlen(travel->text);
 
3868
              if (len >= HLSZ)
 
3869
                break;
 
3870
 
 
3871
              /*
 
3872
               * This comes after the break above because it will
 
3873
               * be accounted for in the while loop below.
 
3874
               */
 
3875
              if(!tentative_cur_l){
 
3876
                  if(tentative_p_ind <= ucs4_strlen(travel->text))
 
3877
                    tentative_cur_l = travel;
 
3878
                  else
 
3879
                    tentative_p_ind -= ucs4_strlen(travel->text);
 
3880
              }
 
3881
 
 
3882
              travel = travel->next;
 
3883
          }
 
3884
 
 
3885
          ods.cur_l = travel;
 
3886
          ods.p_ind = ucs4_strlen(travel->text) - len + HLSZ;
 
3887
        }
 
3888
    }
 
3889
 
 
3890
    /* insert the remainder of text */
 
3891
    if (i != FALSE && work_buf_len > 0) {
 
3892
        ucs4_strncpy(&ods.cur_l->text[ods.p_ind], work_buf, HLSZ-ods.p_ind);
 
3893
        ods.cur_l->text[HLSZ-1] = '\0';
 
3894
        work_buf = work_buf_begin;
 
3895
        free(work_buf);
 
3896
 
 
3897
        if(FormatLines(ods.cur_l, empty, LINEWID(),
 
3898
                       headents[ods.cur_e].break_on_comma, 0) == -1) {
 
3899
           i = FALSE;
 
3900
        } else {  
 
3901
          len = 0;
 
3902
          travel = ods.cur_l;
 
3903
          while (len < work_buf_len + ods.p_ind){
 
3904
              if(!tentative_cur_l){
 
3905
                  if(tentative_p_ind <= ucs4_strlen(travel->text))
 
3906
                    tentative_cur_l = travel;
 
3907
                  else
 
3908
                    tentative_p_ind -= ucs4_strlen(travel->text);
 
3909
              }
 
3910
 
 
3911
              len += ucs4_strlen(travel->text);
 
3912
              if (len >= work_buf_len + ods.p_ind)
 
3913
                break;
 
3914
 
 
3915
              travel = travel->next;
 
3916
          }
 
3917
 
 
3918
          ods.cur_l = travel;
 
3919
          ods.p_ind = ucs4_strlen(travel->text) - len + work_buf_len + ods.p_ind;
 
3920
          if(tentative_cur_l
 
3921
             && tentative_p_ind >= 0
 
3922
             && tentative_p_ind <= ucs4_strlen(tentative_cur_l->text)){
 
3923
              ods.cur_l = tentative_cur_l;
 
3924
              ods.p_ind = tentative_p_ind;
 
3925
          }
 
3926
        }
 
3927
    }
 
3928
 
 
3929
    free(buf);
 
3930
    return(i);
 
3931
}
 
3932
 
 
3933
 
 
3934
 
 
3935
/*
 
3936
 * break_point - Break the given line at the most reasonable character breakch
 
3937
 *               within maxwid max characters.
 
3938
 *
 
3939
 *      returns:
 
3940
 *              Pointer to the best break point in s, or
 
3941
 *              Pointer to the beginning of s if no break point found
 
3942
 */
 
3943
UCS *
 
3944
break_point(UCS *line, int maxwid, UCS breakch, int *quotedarg)
 
3945
{
 
3946
    UCS           *bp;          /* break point */
 
3947
    int            quoted = (quotedarg) ? *quotedarg : 0;
 
3948
 
 
3949
    /*
 
3950
     * Start at maxwid and work back until first opportunity to break.
 
3951
     */
 
3952
    bp = ucs4_particular_width(line, maxwid);
 
3953
 
 
3954
    while(bp != line){
 
3955
        if(breakch == ',' && *bp == '"')        /* don't break on quoted ',' */
 
3956
          quoted = !quoted;                     /* toggle quoted state */
 
3957
 
 
3958
        if(*bp == breakch){
 
3959
            if(breakch == ' '){
 
3960
                if(ucs4_str_width_ptr_to_ptr(line, bp+1) < maxwid){
 
3961
                    bp++;                       /* leave the ' ' */
 
3962
                    break;
 
3963
                }
 
3964
            }
 
3965
            else{
 
3966
                /*
 
3967
                 * if break char isn't a space, leave a space after
 
3968
                 * the break char.
 
3969
                 */
 
3970
                if(!(ucs4_str_width_ptr_to_ptr(line, bp+1) >= maxwid
 
3971
                     || (bp[1] == ' ' && ucs4_str_width_ptr_to_ptr(line, bp+2) >= maxwid))){
 
3972
                    bp += (bp[1] == ' ') ? 2 : 1;
 
3973
                    break;
 
3974
                }
 
3975
            }
 
3976
        }
 
3977
 
 
3978
        bp--;
 
3979
    }
 
3980
 
 
3981
    if(quotedarg)
 
3982
      *quotedarg = quoted;
 
3983
 
 
3984
    return((quoted) ? line : bp);
 
3985
}
 
3986
 
 
3987
 
 
3988
 
 
3989
 
 
3990
/*
 
3991
 * hldelete() - remove the header line pointed to by l from the linked list
 
3992
 *              of lines.
 
3993
 *
 
3994
 *      notes:
 
3995
 *              the case of first line in field is kind of bogus.  since
 
3996
 *              the array of headers has a pointer to the first line, and 
 
3997
 *              i don't want to worry about this too much, i just copied 
 
3998
 *              the line below and removed it rather than the first one
 
3999
 *              from the list.
 
4000
 *
 
4001
 *      returns:
 
4002
 *              TRUE if it worked 
 
4003
 *              FALSE otherwise
 
4004
 */
 
4005
int
 
4006
hldelete(struct hdr_line *l)
 
4007
{
 
4008
    register struct hdr_line *lp;
 
4009
 
 
4010
    if(l == NULL)
 
4011
      return(FALSE);
 
4012
 
 
4013
    if(l->next == NULL && l->prev == NULL){     /* only one line in field */
 
4014
        l->text[0] = '\0';
 
4015
        return(TRUE);                           /* no free only line in list */
 
4016
    }
 
4017
    else if(l->next == NULL){                   /* last line in field */
 
4018
        l->prev->next = NULL;
 
4019
    }
 
4020
    else if(l->prev == NULL){                   /* first line in field */
 
4021
        ucs4_strncpy(l->text, l->next->text, HLSZ);
 
4022
        l->text[HLSZ-1] = '\0';
 
4023
        lp = l->next;
 
4024
        if((l->next = lp->next) != NULL)
 
4025
          l->next->prev = l;
 
4026
        l = lp;
 
4027
    }
 
4028
    else{                                       /* some where in field */
 
4029
        l->prev->next = l->next;
 
4030
        l->next->prev = l->prev;
 
4031
    }
 
4032
 
 
4033
    l->next = NULL;
 
4034
    l->prev = NULL;
 
4035
    free((char *)l);
 
4036
    return(TRUE);
 
4037
}
 
4038
 
 
4039
 
 
4040
 
 
4041
/*
 
4042
 * is_blank - returns true if the next n chars from coordinates row, col
 
4043
 *           on display are spaces
 
4044
 */
 
4045
int
 
4046
is_blank(int row, int col, int n)
 
4047
{
 
4048
    n += col;
 
4049
    for( ;col < n; col++){
 
4050
        if(pscr(row, col) == NULL || pscr(row, col)->c != ' ')
 
4051
          return(0);
 
4052
    }
 
4053
    return(1);
 
4054
}
 
4055
 
 
4056
 
 
4057
/*
 
4058
 * ShowPrompt - display key help corresponding to the current header entry
 
4059
 */
 
4060
void
 
4061
ShowPrompt(void)
 
4062
{
 
4063
    if(headents[ods.cur_e].key_label){
 
4064
        menu_header[TO_KEY].name  = "^T";
 
4065
        menu_header[TO_KEY].label = headents[ods.cur_e].key_label;
 
4066
        KS_OSDATASET(&menu_header[TO_KEY], KS_OSDATAGET(&headents[ods.cur_e]));
 
4067
    }
 
4068
    else
 
4069
      menu_header[TO_KEY].name  = NULL;
 
4070
    
 
4071
    if(Pmaster && Pmaster->exit_label)
 
4072
      menu_header[SEND_KEY].label = Pmaster->exit_label;
 
4073
    else if(gmode & (MDVIEW | MDHDRONLY))
 
4074
      menu_header[SEND_KEY].label =  (gmode & MDHDRONLY) ? "eXit/Save" : "eXit";
 
4075
    else
 
4076
      menu_header[SEND_KEY].label = N_("Send");
 
4077
 
 
4078
    if(gmode & MDVIEW){
 
4079
        menu_header[CUT_KEY].name  = NULL;
 
4080
        menu_header[DEL_KEY].name  = NULL;
 
4081
        menu_header[UDEL_KEY].name = NULL;
 
4082
    }
 
4083
    else{
 
4084
        menu_header[CUT_KEY].name  = "^K";
 
4085
        menu_header[DEL_KEY].name  = "^D";
 
4086
        menu_header[UDEL_KEY].name = "^U";
 
4087
    }
 
4088
 
 
4089
    if(Pmaster->ctrlr_label){
 
4090
        menu_header[RICH_KEY].label = Pmaster->ctrlr_label;
 
4091
        menu_header[RICH_KEY].name = "^R";
 
4092
    }
 
4093
    else if(gmode & MDHDRONLY){
 
4094
        menu_header[RICH_KEY].name  = NULL;
 
4095
    }
 
4096
    else{
 
4097
        menu_header[RICH_KEY].label = N_("Rich Hdr");
 
4098
        menu_header[RICH_KEY].name  = "^R";
 
4099
    }
 
4100
 
 
4101
    if(gmode & MDHDRONLY){
 
4102
        if(headents[ods.cur_e].fileedit){
 
4103
            menu_header[PONE_KEY].name  = "^_";
 
4104
            menu_header[PONE_KEY].label   = N_("Edit File");
 
4105
        }
 
4106
        else
 
4107
          menu_header[PONE_KEY].name  = NULL;
 
4108
 
 
4109
        menu_header[ATT_KEY].name   = NULL;
 
4110
    }
 
4111
    else{
 
4112
        menu_header[PONE_KEY].name  = "^O";
 
4113
        menu_header[PONE_KEY].label = N_("Postpone");
 
4114
 
 
4115
        menu_header[ATT_KEY].name   = "^J";
 
4116
    }
 
4117
 
 
4118
    wkeyhelp(menu_header);
 
4119
}
 
4120
 
 
4121
 
 
4122
/*
 
4123
 * packheader - packup all of the header fields for return to caller. 
 
4124
 *              NOTE: all of the header info passed in, including address
 
4125
 *                    of the pointer to each string is contained in the
 
4126
 *                    header entry array "headents".
 
4127
 */
 
4128
int
 
4129
packheader(void)
 
4130
{
 
4131
    register int        i = 0;          /* array index */
 
4132
    register int        count;          /* count of chars in a field */
 
4133
    register int        retval = TRUE;
 
4134
    register char       *bufp;
 
4135
    register struct     hdr_line *line;
 
4136
    char               *p;
 
4137
 
 
4138
    if(!headents)
 
4139
      return(TRUE);
 
4140
 
 
4141
    while(headents[i].name != NULL){
 
4142
#ifdef  ATTACHMENTS
 
4143
        /*
 
4144
         * attachments are special case, already in struct we pass back
 
4145
         */
 
4146
        if(headents[i].is_attach){
 
4147
            i++;
 
4148
            continue;
 
4149
        }
 
4150
#endif
 
4151
 
 
4152
        if(headents[i].blank){
 
4153
            i++;
 
4154
            continue;
 
4155
        }
 
4156
 
 
4157
        /*
 
4158
         * count chars to see if we need a new malloc'd space for our
 
4159
         * array.
 
4160
         */
 
4161
        line = headents[i].hd_text;
 
4162
        count = 0;
 
4163
        while(line != NULL){
 
4164
            /*
 
4165
             * add one for possible concatination of a ' ' character ...
 
4166
             */
 
4167
            p = ucs4_to_utf8_cpystr(line->text);
 
4168
            if(p){
 
4169
                count += strlen(p);
 
4170
                if(p[0] && p[strlen(p)-1] == ',')
 
4171
                  count++;
 
4172
 
 
4173
                fs_give((void **) &p);
 
4174
            }
 
4175
 
 
4176
            line = line->next;
 
4177
        }
 
4178
 
 
4179
        line = headents[i].hd_text;
 
4180
        if(count <= headents[i].maxlen){                
 
4181
            *headents[i].realaddr[0] = '\0';
 
4182
        }
 
4183
        else{
 
4184
            /*
 
4185
             * don't forget to include space for the null terminator!!!!
 
4186
             */
 
4187
            if((bufp = (char *)malloc((count+1) * sizeof(char))) != NULL){
 
4188
                *bufp = '\0';
 
4189
 
 
4190
                free(*headents[i].realaddr);
 
4191
                *headents[i].realaddr = bufp;
 
4192
                headents[i].maxlen = count;
 
4193
            }
 
4194
            else{
 
4195
                emlwrite("Can't make room to pack header field.", NULL);
 
4196
                retval = FALSE;
 
4197
            }
 
4198
        }
 
4199
 
 
4200
        if(retval != FALSE){
 
4201
            int saw_current_line = 0;
 
4202
 
 
4203
            while(line != NULL){
 
4204
 
 
4205
                /* pass the cursor offset back in Pmaster struct */
 
4206
                if(headents[i].start_here && Pmaster && !saw_current_line){
 
4207
                    if(ods.cur_l == line)
 
4208
                      saw_current_line++;
 
4209
                    else
 
4210
                      Pmaster->edit_offset += ucs4_strlen(line->text);
 
4211
                }
 
4212
 
 
4213
                p = ucs4_to_utf8_cpystr(line->text);
 
4214
                if(p){
 
4215
                    strncat(*headents[i].realaddr, p, headents[i].maxlen+1-strlen(*headents[i].realaddr));
 
4216
                    (*headents[i].realaddr)[headents[i].maxlen] = '\0';
 
4217
 
 
4218
                    if(p[0] && p[strlen(p)-1] == ','){
 
4219
                        strncat(*headents[i].realaddr, " ", headents[i].maxlen+1-strlen(*headents[i].realaddr));
 
4220
                        (*headents[i].realaddr)[headents[i].maxlen] = '\0';
 
4221
                    }
 
4222
 
 
4223
                    fs_give((void **) &p);
 
4224
                }
 
4225
 
 
4226
                line = line->next;
 
4227
            }
 
4228
        }
 
4229
 
 
4230
        i++;
 
4231
    }
 
4232
 
 
4233
    return(retval);    
 
4234
}
 
4235
 
 
4236
 
 
4237
 
 
4238
/*
 
4239
 * zotheader - free all malloc'd lines associated with the header structs
 
4240
 */
 
4241
void
 
4242
zotheader(void)
 
4243
{
 
4244
    register struct headerentry *i;
 
4245
  
 
4246
    for(i = headents; headents && i->name; i++)
 
4247
      zotentry(i->hd_text);
 
4248
}
 
4249
 
 
4250
 
 
4251
/*
 
4252
 * zotentry - free malloc'd space associated with the given linked list
 
4253
 */
 
4254
void
 
4255
zotentry(struct hdr_line *l)
 
4256
{
 
4257
    register struct hdr_line *ld, *lf = l;
 
4258
 
 
4259
    while((ld = lf) != NULL){
 
4260
        lf = ld->next;
 
4261
        ld->next = ld->prev = NULL;
 
4262
        free((char *) ld);
 
4263
    }
 
4264
}
 
4265
 
 
4266
 
 
4267
 
 
4268
/*
 
4269
 * zotcomma - blast any trailing commas and white space from the end 
 
4270
 *            of the given line
 
4271
 */
 
4272
int
 
4273
zotcomma(UCS *s)
 
4274
{
 
4275
    UCS *p;
 
4276
    int retval = FALSE;
 
4277
 
 
4278
    p = &s[ucs4_strlen(s)];
 
4279
    while(--p >= s){
 
4280
        if(*p != ' '){
 
4281
            if(*p == ','){
 
4282
                *p = '\0';
 
4283
                retval = TRUE;
 
4284
            }
 
4285
 
 
4286
            return(retval);
 
4287
        }
 
4288
    }
 
4289
 
 
4290
    return(retval);
 
4291
}
 
4292
 
 
4293
 
 
4294
/*
 
4295
 * Save the current state of global variables so that we can restore
 
4296
 * them later. This is so we can call pico again.
 
4297
 * Also have to initialize some variables that normally would be set to
 
4298
 * zero on startup.
 
4299
 */
 
4300
VARS_TO_SAVE *
 
4301
save_pico_state(void)
 
4302
{
 
4303
    VARS_TO_SAVE  *ret;
 
4304
    extern int     vtrow;
 
4305
    extern int     vtcol;
 
4306
    extern int     lbound;
 
4307
    extern VIDEO **vscreen;
 
4308
    extern VIDEO **pscreen;
 
4309
    extern int     pico_all_done;
 
4310
    extern jmp_buf finstate;
 
4311
    extern UCS    *pico_anchor;
 
4312
 
 
4313
    if((ret = (VARS_TO_SAVE *)malloc(sizeof(VARS_TO_SAVE))) == NULL)
 
4314
      return(ret);
 
4315
 
 
4316
    ret->vtrow = vtrow;
 
4317
    ret->vtcol = vtcol;
 
4318
    ret->lbound = lbound;
 
4319
    ret->vscreen = vscreen;
 
4320
    ret->pscreen = pscreen;
 
4321
    ret->ods = ods;
 
4322
    ret->delim_ps = delim_ps;
 
4323
    ret->invert_ps = invert_ps;
 
4324
    ret->pico_all_done = pico_all_done;
 
4325
    memcpy(ret->finstate, finstate, sizeof(jmp_buf));
 
4326
    ret->pico_anchor = pico_anchor;
 
4327
    ret->Pmaster = Pmaster;
 
4328
    ret->fillcol = fillcol;
 
4329
    if((ret->pat = (UCS *)malloc(sizeof(UCS) * (ucs4_strlen(pat)+1))) != NULL)
 
4330
      ucs4_strncpy(ret->pat, pat, ucs4_strlen(pat)+1);
 
4331
 
 
4332
    ret->ComposerTopLine = ComposerTopLine;
 
4333
    ret->ComposerEditing = ComposerEditing;
 
4334
    ret->gmode = gmode;
 
4335
    ret->alt_speller = alt_speller;
 
4336
    ret->quote_str = glo_quote_str;
 
4337
    ret->currow = currow;
 
4338
    ret->curcol = curcol;
 
4339
    ret->thisflag = thisflag;
 
4340
    ret->lastflag = lastflag;
 
4341
    ret->curgoal = curgoal;
 
4342
    ret->opertree = (char *) malloc(sizeof(char) * (strlen(opertree) + 1));
 
4343
    if(ret->opertree != NULL)
 
4344
      strncpy(ret->opertree, opertree, strlen(opertree)+1);
 
4345
 
 
4346
    ret->curwp = curwp;
 
4347
    ret->wheadp = wheadp;
 
4348
    ret->curbp = curbp;
 
4349
    ret->bheadp = bheadp;
 
4350
    ret->km_popped = km_popped;
 
4351
    ret->mrow = term.t_mrow;
 
4352
 
 
4353
    /* Initialize for next pico call */
 
4354
    wheadp = NULL;
 
4355
    curwp = NULL;
 
4356
    bheadp = NULL;
 
4357
    curbp = NULL;
 
4358
 
 
4359
    return(ret);
 
4360
}
 
4361
 
 
4362
 
 
4363
void
 
4364
restore_pico_state(VARS_TO_SAVE *state)
 
4365
{
 
4366
    extern int     vtrow;
 
4367
    extern int     vtcol;
 
4368
    extern int     lbound;
 
4369
    extern VIDEO **vscreen;
 
4370
    extern VIDEO **pscreen;
 
4371
    extern int     pico_all_done;
 
4372
    extern jmp_buf finstate;
 
4373
    extern UCS    *pico_anchor;
 
4374
 
 
4375
    clearcursor();
 
4376
    vtrow = state->vtrow;
 
4377
    vtcol = state->vtcol;
 
4378
    lbound = state->lbound;
 
4379
    vscreen = state->vscreen;
 
4380
    pscreen = state->pscreen;
 
4381
    ods = state->ods;
 
4382
    delim_ps = state->delim_ps;
 
4383
    invert_ps = state->invert_ps;
 
4384
    pico_all_done = state->pico_all_done;
 
4385
    memcpy(finstate, state->finstate, sizeof(jmp_buf));
 
4386
    pico_anchor = state->pico_anchor;
 
4387
    Pmaster = state->Pmaster;
 
4388
    if(Pmaster)
 
4389
      headents = Pmaster->headents;
 
4390
 
 
4391
    fillcol = state->fillcol;
 
4392
    if(state->pat)
 
4393
      ucs4_strncpy(pat, state->pat, NPAT);
 
4394
 
 
4395
    ComposerTopLine = state->ComposerTopLine;
 
4396
    ComposerEditing = state->ComposerEditing;
 
4397
    gmode = state->gmode;
 
4398
    alt_speller = state->alt_speller;
 
4399
    glo_quote_str = state->quote_str;
 
4400
    currow = state->currow;
 
4401
    curcol = state->curcol;
 
4402
    thisflag = state->thisflag;
 
4403
    lastflag = state->lastflag;
 
4404
    curgoal = state->curgoal;
 
4405
    if(state->opertree){
 
4406
      strncpy(opertree, state->opertree, sizeof(opertree));
 
4407
      opertree[sizeof(opertree)-1] = '\0';
 
4408
    }
 
4409
 
 
4410
    curwp = state->curwp;
 
4411
    wheadp = state->wheadp;
 
4412
    curbp = state->curbp;
 
4413
    bheadp = state->bheadp;
 
4414
    km_popped = state->km_popped;
 
4415
    term.t_mrow = state->mrow;
 
4416
}
 
4417
 
 
4418
 
 
4419
void
 
4420
free_pico_state(VARS_TO_SAVE *state)
 
4421
{
 
4422
    if(state->pat)
 
4423
      free(state->pat);
 
4424
 
 
4425
    if(state->opertree)
 
4426
      free(state->opertree);
 
4427
 
 
4428
    free(state);
 
4429
}
 
4430
 
 
4431
 
 
4432
/*
 
4433
 * Ok to call this twice in a row because it won't do anything the second
 
4434
 * time.
 
4435
 */
 
4436
void
 
4437
fix_mangle_and_err(int *mangled, char **errmsg, char *name)
 
4438
{
 
4439
    if(mangled && *mangled){
 
4440
        ttresize();
 
4441
        picosigs();
 
4442
        PaintBody(0);
 
4443
        *mangled = 0;
 
4444
    }
 
4445
 
 
4446
    if(errmsg && *errmsg){
 
4447
        if(**errmsg){
 
4448
            char err[500];
 
4449
 
 
4450
            snprintf(err, sizeof(err), "%s field: %s", name, *errmsg);
 
4451
            (*term.t_beep)();
 
4452
            emlwrite(err, NULL);
 
4453
        }
 
4454
        else
 
4455
            mlerase();
 
4456
 
 
4457
        free(*errmsg);
 
4458
        *errmsg = NULL;
 
4459
    }
 
4460
}
 
4461
 
 
4462
 
 
4463
#ifdef  MOUSE
 
4464
#undef  HeaderEditor
 
4465
 
 
4466
/*
 
4467
 * Wraper function for the real header editor. 
 
4468
 * Does the important tasks of:
 
4469
 *      1) verifying that we _can_ edit the headers.
 
4470
 *      2) acting on the result code from the header editor.
 
4471
 */
 
4472
int
 
4473
HeaderEditor(int f, int n)
 
4474
{
 
4475
    int  retval;
 
4476
    
 
4477
    
 
4478
#ifdef _WINDOWS
 
4479
    /* Sometimes we get here from a scroll callback, which
 
4480
     * is no good at all because mswin is not ready to process input and
 
4481
     * this _headeredit() will never do anything.
 
4482
     * Putting this test here was the most general solution I could think
 
4483
     * of. */
 
4484
    if (!mswin_caninput()) 
 
4485
        return (-1);
 
4486
#endif
 
4487
 
 
4488
    retval = HeaderEditorWork(f, n);
 
4489
    if (retval == -3) {
 
4490
        retval = mousepress(0,0);
 
4491
    }
 
4492
    return (retval);
 
4493
}
 
4494
#endif