1
#if !defined(lint) && !defined(DOS)
2
static char rcsid[] = "$Id: composer.c 380 2007-01-23 00:09:18Z hubert@u.washington.edu $";
6
* ========================================================================
7
* Copyright 2006-2007 University of Washington
9
* Licensed under the Apache License, Version 2.0 (the "License");
10
* you may not use this file except in compliance with the License.
11
* You may obtain a copy of the License at
13
* http://www.apache.org/licenses/LICENSE-2.0
15
* ========================================================================
17
* Program: Pine composer routines
21
* - composer.c is the composer for the PINE mail system
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 ....
32
* Notes: Installed header line editing, with wrapping and unwrapping,
33
* context sensitive help, and other mail header editing features.
35
* - finalish code cleanup 07/15/91
37
* Notes: Killed/yanked header lines use emacs kill buffer.
38
* Arbitrarily large headers are handled gracefully.
39
* All formatting handled by FormatLines.
41
* - Work done to optimize display painting 06/26/92
42
* Not as clean as it should be, needs more thought
47
#include "osdep/terminal.h"
49
int InitEntryText(char *, struct headerentry *);
50
int HeaderOffset(int);
51
int HeaderFocus(int, 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);
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);
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 *);
83
* definition header field array, structures defined in pico.h
85
struct headerentry *headents;
89
* structure that keeps track of the range of header lines that are
90
* to be displayed and other fun stuff about the header
92
struct on_display ods; /* global on_display struct */
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)
106
* Redefine HeaderEditor to install wrapper required for mouse event
109
#define HeaderEditor HeaderEditorWork
112
#define HDR_DELIM "----- Message Text -----"
115
* useful declarations
117
static short delim_ps = 0; /* previous state */
118
static short invert_ps = 0; /* previous state */
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}
149
* function key mappings for header editor
151
static UCS ckm[12][2] = {
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.
174
* Returns: TRUE if special header handling was requested,
175
* FALSE under standard default behavior.
178
InitMailHeader(PICO *mp)
181
struct headerentry *he;
190
* initialize some of on_display structure, others below...
193
ods.p_line = COMPOSER_TOP_LINE;
194
ods.top_l = ods.cur_l = NULL;
196
headents = mp->headents;
197
/*--- initialize the fields in the headerent structure ----*/
198
for(he = headents; he->name != NULL; he++){
200
he->display_it = he->display_it ? he->display_it : !he->rich_header;
202
/*--- A lot of work to do since attachments are special ---*/
204
if(mp->attachments != NULL){
207
int l1, ofp, ofp1, ofp2; /* OverFlowProtection */
208
size_t addrbuflen = 4 * NLINE; /* malloc()ed size of addrbuf */
209
PATMT *ap = mp->attachments;
213
addrbuf = (char *)malloc(addrbuflen);
217
if((l1 = strlen(ap->filename)) <= ofp){
227
snprintf(buf, sizeof(buf), "%d. %.*s%s %s%s%s\"",
231
(l1 > ofp) ? "...]" : "",
233
ap->size ? ap->size : "",
234
ap->size ? ") " : "");
236
/* append description, escaping quotes */
238
char *dp = ap->description, *bufp = &buf[strlen(buf)];
242
if(*dp == '\"' && !escaped){
250
while(--ofp2 > 0 && (*bufp++ = *dp++));
255
snprintf(buf + strlen(buf), sizeof(buf)-strlen(buf), "\"%s", ap->next ? "," : "");
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);
266
strncat(addrbuf, buf, addrbuflen-strlen(addrbuf));
267
addrbuf[addrbuflen-1] = '\0';
271
InitEntryText(addrbuf, he);
272
free((char *)addrbuf);
274
InitEntryText("", he);
279
addrbuf = *(he->realaddr);
283
InitEntryText(addrbuf, he);
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.
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);
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;
314
* InitEntryText - Add the given header text into the header entry
318
InitEntryText(char *utf8text, struct headerentry *e)
320
struct hdr_line *curline;
321
register int longest;
324
* get first chunk of memory, and tie it to structure...
326
if((curline = HALLOC()) == NULL){
327
emlwrite("Unable to make room for full Header.", NULL);
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 */
337
if(FormatLines(curline, utf8text, longest, e->break_on_comma, 0) == -1)
346
* ResizeHeader - Handle resizing display when SIGWINCH received.
349
* works OK, but needs thorough testing
355
register struct headerentry *i;
361
offset = (ComposerEditing) ? HeaderOffset(ods.cur_e) : 0;
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){
370
if(ComposerEditing) /* restart at the top */
371
HeaderFocus(ods.cur_e, offset); /* fix cur_l and p_ind */
376
for(i = headents; i->name != NULL; i++); /* Find last line */
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 */
385
l = headents[e].hd_text;
388
HeaderFocus(e, -1); /* put focus on last line */
391
if(ComposerTopLine != COMPOSER_TOP_LINE)
397
movecursor(ods.p_line, ods.p_ind+headents[ods.cur_e].prwid);
406
* HeaderOffset - return the character offset into the given header
411
register struct hdr_line *l;
414
l = headents[h].hd_text;
416
while(l != ods.cur_l){
417
i += ucs4_strlen(l->text);
426
* HeaderFocus - put the dot at the given offset into the given header
429
HeaderFocus(int h, int offset)
431
register struct hdr_line *l;
435
if(offset == -1) /* focus on last line */
438
l = headents[h].hd_text;
440
if(last && l->next == NULL){
444
if((i=ucs4_strlen(l->text)) >= offset)
449
if((l = l->next) == NULL)
454
ods.p_len = ucs4_strlen(l->text);
455
ods.p_ind = (last) ? 0 : offset;
463
* HeaderEditor() - edit the mail header field by field, trapping
464
* important key sequences, hand the hard work off
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
473
HeaderEditor(int f, int n)
478
struct headerentry *h;
479
int cur_e, mangled, retval = -1,
480
hdr_only = (gmode & MDHDRONLY) ? 1 : 0;
487
return(TRUE); /* nothing to edit! */
489
ComposerEditing = TRUE;
490
display_delimiter(0); /* provide feedback */
493
mswin_setscrollrange (0, 0);
494
#endif /* _WINDOWS */
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.
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.
510
if(f == 2){ /* 2 leaves cursor at end */
511
struct hdr_line *l = ods.cur_l;
514
/*--- make sure on last field ---*/
515
while(l = next_sel_hline(&e, l))
516
if(headents[ods.cur_e].display_it){
521
ods.p_ind = 1000; /* and make sure at EOL */
525
* note: assumes that ods.cur_e and ods.cur_l haven't changed
530
if(curwp->w_doto < headents[ods.cur_e].prwid)
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;
537
/* and scroll back if needed */
539
for(i = 0; header_upline(0) && i <= FULL_SCR(); i++)
543
ods.p_line = ComposerTopLine - 2;
545
/* else just trust what ods contains */
547
InvertPrompt(ods.cur_e, TRUE); /* highlight header field */
558
if(km_popped){ /* temporarily change to cause menu to paint */
560
curwp->w_ntrows -= 2;
561
movecursor(term.t_nrow-2, 0); /* clear status line, too */
564
else if(term.t_mrow == 0)
567
ShowPrompt(); /* display correct options */
571
curwp->w_ntrows += 2;
575
ch = LineEdit(!(gmode&MDVIEW)); /* work on the current line */
585
movecursor(term.t_nrow-2, 0);
587
movecursor(term.t_nrow-1, 0);
589
movecursor(term.t_nrow, 0);
595
case (CTRL|'R') : /* Toggle header display */
596
if(Pmaster->pine_flags & MDHDRONLY){
597
if(Pmaster->expander){
607
/*---- Are there any headers to expand above us? ---*/
608
for(h = headents; h != &headents[ods.cur_e]; h++)
612
InvertPrompt(ods.cur_e, FALSE); /* Yes, don't leave inverted */
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 --*/
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);
630
if(headents[ods.cur_e].builder) /* verify text */
631
i = call_builder(&headents[ods.cur_e], &mangled, &err)>0;
633
for(cur_e =ods.cur_e; headents[cur_e].name!=NULL; cur_e++)
634
if(!headents[cur_e].rich_header)
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;
640
if(!headents[cur_e].rich_header)
646
ods.cur_l = headents[ods.cur_e].hd_text;
650
ods.p_line = 0; /* force update */
652
PaintHeader(COMPOSER_TOP_LINE, FALSE);
654
fix_mangle_and_err(&mangled, &err, headents[ods.cur_e].name);
657
case (CTRL|'C') : /* bag whole thing ?*/
658
if(abort_composer(1, 0) == TRUE)
663
case (CTRL|'X') : /* Done. Send it. */
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...
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);
681
if(headents[ods.cur_e].builder) /* verify text? */
682
i = call_builder(&headents[ods.cur_e], &mangled, &err);
684
if(i < 0){ /* don't leave without a valid addr */
685
fix_mangle_and_err(&mangled, &err, headents[ods.cur_e].name);
689
ods.cur_l = headents[ods.cur_e].hd_text; /* attach cur_l */
691
ods.p_line = 0; /* force realignment */
692
fix_mangle_and_err(&mangled, &err, headents[ods.cur_e].name);
696
fix_mangle_and_err(&mangled, &err, headents[ods.cur_e].name);
698
if(wquit(1,0) == TRUE)
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).
708
PaintHeader(COMPOSER_TOP_LINE, FALSE);
713
case (CTRL|'Z') : /* Suspend compose */
714
if(gmode&MDSSPD){ /* is it allowed? */
720
emlwrite(_("Unknown Command: ^Z"), NULL);
724
case (CTRL|'O') : /* Suspend message */
725
if(Pmaster->pine_flags & MDHDRONLY)
731
if(headents[ods.cur_e].is_attach){
732
if(FormatSyncAttach() < 0){
733
if(mlyesno_utf8(_("Problem with attachments. Postpone anyway?"),
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);
740
PaintHeader(COMPOSER_TOP_LINE, FALSE);
746
else if(headents[ods.cur_e].builder)
747
i = call_builder(&headents[ods.cur_e], &mangled, &err);
749
fix_mangle_and_err(&mangled, &err, headents[ods.cur_e].name);
751
if(i < 0) /* don't leave without a valid addr */
754
suspend_composer(1, 0);
758
case (CTRL|'J') : /* handle attachments */
759
if(Pmaster->pine_flags & MDHDRONLY)
763
LMLIST *lm = NULL, *lmp;
764
char buf[NLINE], *bfp;
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.
775
saved_km_popped = km_popped;
778
if(AskAttach(cmt, sizeof(cmt), &lm)){
780
for(lmp = lm; lmp; lmp = lmp->next){
783
len = lmp->dir ? strlen(lmp->dir)+1 : 0;
784
len += lmp->fname ? strlen(lmp->fname) : 0;
786
if(len+3 > sizeof(buf)){
789
if((bfp=malloc(len+3)) == NULL){
790
emlwrite("\007Can't malloc space for filename",
800
if(lmp->dir && lmp->dir[0])
801
snprintf(bfp, space, "%s%c%s", lmp->dir, C_FILESEP,
802
lmp->fname ? lmp->fname : "");
804
snprintf(bfp, space, "%s", lmp->fname ? lmp->fname : "");
806
(void) QuoteAttach(bfp, space);
808
(void) AppendAttachment(bfp, lm->size, cmt);
817
km_popped = saved_km_popped;
818
sgarbk = 1; /* clean up prompt */
823
case (CTRL|'I') : /* tab */
824
ods.p_ind = 0; /* fall through... */
828
header_downline(!hdr_only, hdr_only);
836
case (CTRL|'V') : /* down a page */
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 */
845
int move_down, bot_pline;
846
struct hdr_line *new_cur_l, *line, *next_line, *prev_line;
848
move_down = BOTTOM() - 2 - ods.p_line;
853
* Count down move_down lines to find the pointer to the line
854
* that we want to become the current line.
856
new_cur_l = ods.cur_l;
858
for(i = 0; i < move_down; i++){
859
next_line = next_hline(&cur_e, new_cur_l);
863
new_cur_l = next_line;
866
if(headents[cur_e].blank){
867
next_line = next_sel_hline(&cur_e, new_cur_l);
871
new_cur_l = next_line;
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.
880
while(ods.cur_l != new_cur_l && header_downline(0, 0))
884
* Count back up, if we're at the bottom, to find the new
888
if(next_hline(&cur_e, ods.cur_l) == NULL){
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.
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);
913
ods.top_l = ods.cur_l;
914
ods.top_e = ods.cur_e;
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.
921
bot_pline = BOTTOM() - 1 - ((gmode & MDHDRONLY) ? 0 : 1);
924
for(i = bot_pline; i > COMPOSER_TOP_LINE; i--){
925
next_line = next_hline(&cur_e, line);
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.
940
for(; i > COMPOSER_TOP_LINE; i--){
941
prev_line = prev_hline(&cur_e, line);
952
* Special case. If p_line is within one of the bottom,
953
* move it to the bottom.
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;
965
PaintHeader(COMPOSER_TOP_LINE, FALSE);
971
case (CTRL|'Y') : /* up a page */
973
for(i = 0; header_upline(0) && i <= FULL_SCR(); i++)
981
mouse_get_last (NULL, &mp);
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);
992
for (i = mp.row-ods.p_line;
993
i > 0 && header_downline(!hdr_only, 0);
998
if((ods.p_ind = mp.col - headents[ods.cur_e].prwid) <= 0)
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.
1005
if (ods.p_line >= ComposerTopLine)
1011
case M_BUTTON_RIGHT :
1015
case M_BUTTON_MIDDLE :
1016
default : /* NOOP */
1023
case (CTRL|'T') : /* Call field selector */
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;
1030
strncpy(dir, (gmode & MDCURDIR)
1031
? (browse_dir[0] ? browse_dir : ".")
1032
: ((gmode & MDTREE) || opertree[0])
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;
1043
for(lmp = lm; lmp; lmp = lmp->next){
1046
len = lmp->dir ? strlen(lmp->dir)+1 : 0;
1047
len += lmp->fname ? strlen(lmp->fname) : 0;
1049
len += strlen(lmp->size);
1051
if(len+3 > sizeof(buf)){
1052
bfp = malloc(len+3);
1054
if((bfp=malloc(len+3)) == NULL){
1055
emlwrite("\007Can't malloc space for filename",
1062
space = sizeof(buf);
1065
if(lmp->dir && lmp->dir[0])
1066
snprintf(bfp, space, "%s%c%s", lmp->dir, C_FILESEP,
1067
lmp->fname ? lmp->fname : "");
1069
snprintf(bfp, space, "%s", lmp->fname ? lmp->fname : "");
1071
(void) QuoteAttach(bfp, space);
1073
snprintf(bfp + strlen(bfp), space-strlen(bfp), " (%s) \"\"%s", lmp->size,
1074
(!headents[ods.cur_e].hd_text->text[0]) ? "":",");
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);
1089
} /* else, nothing of interest */
1090
} else if (headents[ods.cur_e].selector != NULL) {
1091
VARS_TO_SAVE *saved_state;
1093
/*---- General selector for non-attachments -----*/
1096
* Since the selector may make a new call back to pico()
1097
* we need to save and restore the pico state here.
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 */
1107
char *s = "Not enough memory";
1111
errmss = (char *)malloc((len+1) * sizeof(char));
1112
strncpy(errmss, s, len+1);
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;
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)){
1133
if(hh && hh != ods.cur_l){
1134
/*--- Looks like a continuation ---*/
1136
ods.p_len = ucs4_strlen(hh->text);
1138
for(i = ++ods.p_len; i; i--)
1139
ods.cur_l->text[i] = ods.cur_l->text[i-1];
1141
ods.cur_l->text[0] = ',';
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 !",
1154
* If the "selector" has a "builder" as well, pass
1155
* what was just selected thru the builder...
1157
if(headents[ods.cur_e].builder){
1159
int cur_row, top_too = 0;
1161
for(l = headents[ods.cur_e].hd_text, cur_row = 0;
1162
l && l != ods.cur_l;
1163
l = l->next, cur_row++)
1166
top_too = headents[ods.cur_e].hd_text == ods.top_l;
1168
if(call_builder(&headents[ods.cur_e], &mangled,
1170
fix_mangle_and_err(&mangled, &err,
1171
headents[ods.cur_e].name);
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--)
1180
ods.top_l = headents[ods.cur_e].hd_text;
1187
u = utf8_to_ucs4_cpystr(bufp);
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);
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);
1202
/*----- No selector -----*/
1208
if(errmss != NULL) {
1210
emlwrite(errmss, NULL);
1216
case (CTRL|'G'): /* HELP */
1217
if(term.t_mrow == 0){
1220
sgarbk = 1; /* bring up menu */
1225
if(!ComposerHelp(ods.cur_e))
1226
break; /* else, fall through... */
1228
case (CTRL|'L'): /* redraw requested */
1232
case (CTRL|'_'): /* file editor */
1233
if(headents[ods.cur_e].fileedit != NULL){
1234
struct headerentry *e;
1235
struct hdr_line *line;
1237
char *filename = NULL;
1238
VARS_TO_SAVE *saved_state;
1241
* Since the fileedit will make a new call back to pico()
1242
* we need to save and restore the pico state here.
1244
if((saved_state = save_pico_state()) != NULL){
1247
e = &headents[ods.cur_e];
1249
for(line = e->hd_text; line != NULL; line = line->next)
1250
sz += ucs4_strlen(line->text);
1252
u = (UCS *)malloc((sz+1) * sizeof(*u));
1255
for(line = e->hd_text; line != NULL; line = line->next)
1256
ucs4_strncat(u, line->text, sz+1-ucs4_strlen(u));
1258
filename = ucs4_to_utf8_cpystr(u);
1262
errmss = (*(headents[ods.cur_e].fileedit))(filename);
1267
restore_pico_state(saved_state);
1268
free_pico_state(saved_state);
1269
ttresize(); /* fixup screen bufs */
1270
picosigs(); /* restore altered signals */
1273
char *s = "Not enough memory";
1277
errmss = (char *)malloc((len+1) * sizeof(char));
1278
strncpy(errmss, s, len+1);
1284
if(errmss != NULL) {
1286
emlwrite(errmss, NULL);
1298
default : /* huh? */
1300
if(ch&CTRL && (ch & ~CTRL) < 0xff)
1301
emlwrite(_("\007Unknown command: ^%c"), (void *)(ch&0xff));
1304
emlwrite(_("\007Unknown command"), NULL);
1310
while (ods.p_line < ComposerTopLine);
1312
display_delimiter(1);
1313
curwp->w_flag |= WFMODE;
1314
movecursor(currow, curcol);
1315
ComposerEditing = FALSE;
1316
if (ComposerTopLine == BOTTOM()){
1318
PaintHeader(COMPOSER_TOP_LINE, FALSE);
1330
header_downline(int beyond, int gripe)
1332
struct hdr_line *new_l, *l;
1333
int new_e, status, fullpaint, len, e, incr = 0;
1335
/* calculate the next line: physical *and* logical */
1338
if((new_l = next_sel_hline(&new_e, ods.cur_l)) == NULL && !beyond){
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)
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';
1362
* Because of blank header lines the cursor may need to move down
1363
* more than one line. Figure out how far.
1368
if((l = next_hline(&e, l)) != NULL)
1371
break; /* can't happen */
1375
fullpaint = ods.p_line >= BOTTOM(); /* force full redraw? */
1377
/* expand what needs expanding */
1378
if(new_e != ods.cur_e || !new_l){ /* new (or last) field ! */
1380
InvertPrompt(ods.cur_e, FALSE); /* turn off current entry */
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);
1390
} else if(headents[ods.cur_e].builder) { /* expand addresses */
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)
1400
if(new_l) /* if new_l, force validity */
1401
new_l = headents[new_e].hd_text;
1403
NewTop(0); /* get new top_l */
1405
else if(status < 0){ /* bad addr? no leave! */
1407
fix_mangle_and_err(&mangled, &err, headents[ods.cur_e].name);
1408
InvertPrompt(ods.cur_e, TRUE);
1412
fix_mangle_and_err(&mangled, &err, headents[ods.cur_e].name);
1415
if(new_l){ /* if one below, turn it on */
1416
InvertPrompt(new_e, TRUE);
1417
sgarbk = 1; /* paint keymenu too */
1421
if(new_l){ /* fixup new pointers */
1422
ods.cur_l = (ods.cur_e != new_e) ? headents[new_e].hd_text : new_l;
1424
if(ods.p_ind > (len = ucs4_strlen(ods.cur_l->text)))
1428
if(!new_l || status || fullpaint){ /* handle big screen paint */
1430
PaintHeader(COMPOSER_TOP_LINE, FALSE);
1433
if(!new_l){ /* make sure we're done */
1434
ods.p_line = ComposerTopLine;
1435
InvertPrompt(ods.cur_e, FALSE); /* turn off current entry */
1439
return(new_l ? 1 : 0);
1447
header_upline(int gripe)
1449
struct hdr_line *new_l, *l;
1450
int new_e, status, fullpaint, len, e, incr = 0;
1452
/* calculate the next line: physical *and* logical */
1455
if(!(new_l = prev_sel_hline(&new_e, ods.cur_l))){ /* all the way up! */
1456
ods.p_line = COMPOSER_TOP_LINE;
1458
emlwrite(_("Can't move beyond top of %s"),
1459
(Pmaster->pine_flags & MDHDRONLY) ? "entry" : "header");
1465
* Because of blank header lines the cursor may need to move up
1466
* more than one line. Figure out how far.
1471
if((l = prev_hline(&e, l)) != NULL)
1474
break; /* can't happen */
1478
fullpaint = ods.p_line <= COMPOSER_TOP_LINE;
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);
1491
else if(headents[ods.cur_e].builder){
1495
if((status = call_builder(&headents[ods.cur_e], &mangled,
1498
for(new_l = headents[new_e].hd_text;
1503
/* and cur_l (required in fix_and... */
1508
fix_mangle_and_err(&mangled, &err, headents[ods.cur_e].name);
1509
InvertPrompt(ods.cur_e, TRUE);
1513
fix_mangle_and_err(&mangled, &err, headents[ods.cur_e].name);
1516
InvertPrompt(new_e, TRUE);
1520
ods.cur_e = new_e; /* update pointers */
1522
if(ods.p_ind > (len = ucs4_strlen(ods.cur_l->text)))
1525
if(status > 0 || fullpaint){
1527
PaintHeader(COMPOSER_TOP_LINE, FALSE);
1539
AppendAttachment(char *fn, char *sz, char *cmt)
1541
int a_e, status, spaces;
1542
struct hdr_line *lp;
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;
1555
/* append new attachment line */
1556
for(lp = headents[a_e].hd_text; lp->next; lp=lp->next)
1559
/* build new attachment line */
1560
if(lp->text[0]){ /* adding a line? */
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;
1572
emlwrite("\007Can't allocate line for new attachment!", NULL);
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);
1584
ucs4_strncpy(lp->text, u, HLSZ);
1585
lp->text[HLSZ-1] = '\0';
1586
fs_give((void **) &u);
1589
/* validate the new attachment, and reformat if needed */
1590
if(status = SyncAttach()){
1592
emlwrite("\007Problem attaching: %s", fn);
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);
1603
PaintHeader(COMPOSER_TOP_LINE, status != 0);
1605
return(status != 0);
1612
* LineEdit - the idea is to manage 7 bit ascii character only input.
1613
* Always use insert mode and handle line wrapping
1616
* Any characters typed in that aren't printable
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.
1627
LineEdit(int allowedit)
1629
register struct hdr_line *lp; /* temporary line pointer */
1632
register int status; /* various func's return val */
1633
UCS *tbufp; /* temporary buffer pointers */
1636
UCS last_key; /* last keystroke */
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? */
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()){
1647
u = ucs4_particular_width(strng, LINEWID());
1648
ods.p_ind = u - strng;
1651
while(1){ /* edit the line... */
1656
HeaderPaintCursor();
1660
(*term.t_flush)(); /* get everything out */
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),
1668
mswin_setdndcallback (composer_file_drop);
1669
mswin_mousetrackcallback(pico_cursor);
1674
if (term.t_nrow < 6 && ch != NODATA){
1676
emlwrite(_("Please make the screen larger."), NULL);
1681
clear_mfunc(mouse_in_content);
1684
mswin_cleardndcallback ();
1685
mswin_mousetrackcallback(NULL);
1690
if(gmode & P_DELRUBS)
1694
(*Pmaster->keybinput)();
1695
if(!time_to_check())
1698
case NODATA : /* new mail ? */
1699
if((*Pmaster->newmail)(ch == NODATA ? 0 : 2, 1) >= 0){
1704
curwp->w_ntrows -= 2;
1709
rv = (*Pmaster->showmsg)(ch);
1712
if(rv) /* Did showmsg corrupt the display? */
1713
PaintBody(0); /* Yes, repaint */
1718
curwp->w_ntrows += 2;
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 */
1731
if(mpresf){ /* blast old messages */
1732
if(mpresf++ > NMMESSDELAY){ /* every few keystrokes */
1734
movecursor(ods.p_line,
1735
ucs4_str_width_ptr_to_ptr(strng, &strng[ods.p_ind])+headents[ods.cur_e].prwid);
1739
tbufp = &strng[ods.p_len];
1741
if(VALID_KEY(ch)){ /* char input */
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 ...
1749
if(headents[ods.cur_e].is_attach && intag(strng,ods.p_ind)){
1750
emlwrite(_("\007Can't edit attachment number!"), NULL);
1754
if(headents[ods.cur_e].single_space){
1756
&& (strng[ods.p_ind]==' ' || strng[ods.p_ind-1]==' '))
1761
* go ahead and add the character...
1763
if(ods.p_len < HLSZ){
1764
tbufp = &strng[++ods.p_len]; /* find the end */
1767
} while(--tbufp > &strng[ods.p_ind]); /* shift right */
1768
strng[ods.p_ind++] = ch; /* add char to str */
1771
/* mark this entry dirty */
1772
headents[ods.cur_e].sticky = 1;
1773
headents[ods.cur_e].dirty = 1;
1776
* then find out where things fit...
1778
if(ucs4_str_width_ptr_to_ptr(&strng[0], &strng[ods.p_len]) < LINEWID()){
1781
c.c = ch & CELLMASK;
1783
if(pinsert(c)){ /* add char to str */
1784
skipmove++; /* must'a been optimal */
1785
continue; /* on to the next! */
1789
if((status = FormatLines(ods.cur_l, "", LINEWID(),
1790
headents[ods.cur_e].break_on_comma,0)) == -1){
1796
* during the format, the dot may have moved
1797
* down to the next line...
1799
if(ods.p_ind >= ucs4_strlen(strng)){
1801
ods.p_ind -= ucs4_strlen(strng);
1802
ods.cur_l = ods.cur_l->next;
1803
strng = ods.cur_l->text;
1806
ods.p_len = ucs4_strlen(strng);
1810
PaintHeader(COMPOSER_TOP_LINE, FALSE);
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 */
1826
while(strng[ods.p_ind] && !ucs4_isalnum(strng[ods.p_ind]))
1827
ods.p_ind++; /* skip any whitespace after it */
1829
if(strng[ods.p_ind] == '\0'){
1830
ods.p_ind = 0; /* end of line, let caller handle it */
1836
case (CTRL|'K') : /* kill line cursor's on */
1843
if (!(gmode & MDDTKILL))
1846
if(KillHeaderLine(lp, (last_key == (CTRL|'K')))){
1848
!(ods.cur_l->prev==NULL && ods.cur_l->next==NULL))
1849
scrollup(wheadp, ods.p_line, 1);
1851
if(ods.cur_l->next == NULL)
1852
if(zotcomma(ods.cur_l->text)){
1854
ods.p_ind = ucs4_strlen(ods.cur_l->text);
1857
i = (ods.p_line == COMPOSER_TOP_LINE);
1859
PaintHeader(COMPOSER_TOP_LINE, TRUE);
1863
movecursor(term.t_nrow, 0);
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;
1876
case (CTRL|'U') : /* un-delete deleted lines */
1882
if(SaveHeaderLines()){
1884
PaintHeader(COMPOSER_TOP_LINE, FALSE);
1887
movecursor(term.t_nrow, 0);
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;
1898
/* TRANSLATORS: Killing text is deleting it and
1899
Unkilling text is undeleting killed text. */
1900
emlwrite(_("Problem Unkilling text"), NULL);
1904
case KEY_RIGHT: /* move character right */
1905
if(ods.p_ind < ods.p_len){
1909
else if(gmode & MDHDRONLY)
1916
case KEY_LEFT : /* move character left */
1921
if(ods.p_line != COMPOSER_TOP_LINE)
1922
ods.p_ind = 1000; /* put cursor at end of line */
1925
case (CTRL|'M') : /* goto next field */
1930
case (CTRL|'A') : /* goto beginning of line */
1935
case (CTRL|'E') : /* goto end of line */
1936
ods.p_ind = ods.p_len;
1939
case (CTRL|'D') : /* blast this char */
1945
else if(ods.p_ind >= ucs4_strlen(strng))
1948
if(headents[ods.cur_e].is_attach && intag(strng, ods.p_ind)){
1949
emlwrite(_("\007Can't edit attachment number!"), NULL);
1953
pputc(strng[ods.p_ind++], 0); /* drop through and rubout */
1955
case DEL : /* blast previous char */
1962
if(headents[ods.cur_e].is_attach && intag(strng, ods.p_ind-1)){
1963
emlwrite(_("\007Can't edit attachment number!"), NULL);
1967
if(ods.p_ind > 0){ /* just shift left one char */
1969
headents[ods.cur_e].dirty = 1;
1971
headents[ods.cur_e].sticky = 0;
1973
headents[ods.cur_e].sticky = 1;
1975
tbufp = &strng[--ods.p_ind];
1976
while(*tbufp++ != '\0')
1978
tbufp = &strng[ods.p_ind];
1979
if(pdel()) /* physical screen delete */
1980
skipmove++; /* must'a been optimal */
1982
else{ /* may have work to do */
1983
if(ods.cur_l->prev == NULL){
1984
(*term.t_beep)(); /* no erase into next field */
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 */
1996
headents[ods.cur_e].sticky = 0;
2000
tbufp = &strng[ods.p_ind];
2003
if((status = FormatLines(ods.cur_l, "", LINEWID(),
2004
headents[ods.cur_e].break_on_comma,0))==-1){
2010
* beware, the dot may have moved...
2012
while((ods.p_len=ucs4_strlen(strng)) < ods.p_ind){
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];
2025
PaintHeader(COMPOSER_TOP_LINE, FALSE);
2030
movecursor(ods.p_line,
2031
ucs4_str_width_ptr_to_ptr(strng, &strng[ods.p_ind])+headents[ods.cur_e].prwid);
2043
while ((tbufp-strng) < HLSZ && *tbufp != '\0') /* synchronizing loop */
2046
if(ucs4_str_width_ptr_to_ptr(&strng[0], &strng[ods.p_len]) < LINEWID())
2053
HeaderPaintCursor(void)
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);
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.
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.
2072
* FALSE if only this line is changed
2073
* TRUE if text below the first line is changed
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 */
2085
UCS *ostr; /* pointer to output string */
2086
UCS *free_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;
2096
free_istr = istr = utf8_to_ucs4_cpystr(utf8_instr);
2098
len = ucs4_strlen(istr) + ucs4_strlen(ostr);
2099
if((buf = (UCS *) malloc((len+10) * sizeof(*buf))) == NULL){
2101
fs_give((void **) &free_istr);
2106
if(ucs4_str_width(istr) + ucs4_str_width(ostr) >= maxwid){ /* break then fixup below */
2108
if((l=ucs4_str_width(istr)) < maxwid){ /* room for more */
2110
if(break_on_comma && (bp = ucs4_strqchr(istr, ',', "ed, -1))){
2111
bp += (bp[1] == ' ') ? 2 : 1;
2112
for(tp = bp; *tp && *tp == ' '; tp++)
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';
2120
for(i = 0; &istr[i] < bp; i++)
2127
breakp = break_point(ostr, maxwid-ucs4_str_width(istr),
2128
break_on_comma ? ',' : ' ',
2129
break_on_comma ? "ed : NULL);
2131
if(breakp == ostr){ /* no good breakpoint */
2132
if(break_on_comma && *breakp == ','){
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';
2142
else{ /* istr's broken as we can get it */
2144
* Break at maxwid - width of istr
2146
breakp = ucs4_particular_width(ostr, maxwid - ucs4_str_width(istr)-1);
2154
ucs4_strncpy(buf, breakp, len+10); /* save broken line */
2155
buf[len+10-1] = '\0';
2157
ucs4_strncpy(ostr, istr, HLSZ); /* simple if no break */
2158
ostr[HLSZ-1] = '\0';
2161
*breakp = '\0'; /* more work to break it */
2162
i = ucs4_strlen(istr);
2164
* shift ostr i chars
2166
for(bp=breakp; bp >= ostr && i; bp--)
2168
for(tp=ostr, bp=istr; *bp != '\0'; tp++, bp++)
2169
*tp = *bp; /* then add istr */
2175
* Short-circuit the recursion in this case.
2176
* No time right now to figure out how to do it better.
2178
else if(l > 2*maxwid){
2179
UCS *istrp, *saveostr = NULL;
2183
saveostr = ucs4_cpystr(ostr);
2186
while(l > 2*maxwid){
2187
if(break_on_comma || maxwid == 1){
2188
breakp = (!(bp = ucs4_strqchr(istrp, ',', "ed, 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);
2194
breakp = break_point(istrp, maxwid, ' ', NULL);
2196
if(breakp == istrp) /* no good break point */
2197
breakp = ucs4_particular_width(istrp, maxwid-1);
2200
for(tp=ostr,bp=istrp; bp < breakp; tp++, bp++)
2204
l -= ucs4_str_width_ptr_to_ptr(istrp, breakp);
2207
if((lp = HALLOC()) == NULL){
2208
emlwrite("Can't allocate any more lines for header!", NULL);
2211
fs_give((void **) &free_istr);
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.
2236
ucs4_strncpy(ostr, saveostr, HLSZ);
2237
ostr[HLSZ-1] = '\0';
2238
fs_give((void **) &saveostr);
2241
if(break_on_comma || maxwid == 1){
2242
breakp = (!(bp = ucs4_strqchr(istrp, ',', "ed, 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);
2248
breakp = break_point(istrp, maxwid, ' ', NULL);
2250
if(breakp == istrp) /* no good break point */
2251
breakp = ucs4_particular_width(istrp, maxwid-1);
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';
2259
for(tp=ostr,bp=istr; bp < breakp; tp++, bp++)
2264
else{ /* utf8_instr > maxwid ! */
2265
if(break_on_comma || maxwid == 1){
2266
breakp = (!(bp = ucs4_strqchr(istr, ',', "ed, 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);
2272
breakp = break_point(istr, maxwid, ' ', NULL);
2274
if(breakp == istr) /* no good break point */
2275
breakp = ucs4_particular_width(istr, maxwid-1);
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';
2283
for(tp=ostr,bp=istr; bp < breakp; tp++, bp++)
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);
2294
fs_give((void **) &free_istr);
2299
if(TERM_OPTIMIZE && (i = physical_line(h)) != -1)
2300
scrolldown(wheadp, i - 1, 1);
2302
h->next = lp; /* fix up links */
2310
else{ /* combined width < max */
2313
ucs4_strncpy(buf, istr, len+10); /* insert istr before ostr */
2314
buf[len+10-1] = '\0';
2316
ucs4_strncat(buf, ostr, len+10-ucs4_strlen(buf));
2317
buf[len+10-1] = '\0';
2319
ucs4_strncpy(ostr, buf, HLSZ); /* copy back to ostr */
2320
ostr[HLSZ-1] = '\0';
2326
if(break_on_comma && (breakp = ucs4_strqchr(ostr, ',', "ed, -1))){
2327
breakp += (breakp[1] == ' ') ? 2 : 1;
2328
ucs4_strncpy(buf, breakp, len+10);
2329
buf[len+10-1] = '\0';
2333
if((lp = HALLOC()) == NULL){
2334
emlwrite("Can't allocate any more lines for header!",NULL);
2337
fs_give((void **) &free_istr);
2342
if(TERM_OPTIMIZE && (i = physical_line(h)) != -1)
2343
scrolldown(wheadp, i - 1, 1);
2345
h->next = lp; /* fix up links */
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 ? "ed : NULL);
2361
if(breakp == nlp->text){ /* commas this line? */
2362
for(tp=ostr; *tp && *tp != ' '; tp++)
2365
if(!*tp){ /* no commas, get next best */
2366
breakp += maxwid - ucs4_str_width(ostr) - 1;
2375
if(retval){ /* only if something to do */
2376
for(tp = &ostr[ucs4_strlen(ostr)],bp=nlp->text; bp<breakp;
2378
*tp = *bp; /* add breakp to this line */
2380
for(tp=nlp->text, bp=breakp; *bp != '\0'; tp++, bp++)
2381
*tp = *bp; /* shift next line to left */
2386
ucs4_strncat(ostr, nlp->text, HLSZ-ucs4_strlen(ostr));
2387
ostr[HLSZ-1] = '\0';
2389
if(TERM_OPTIMIZE && (i = physical_line(nlp)) != -1)
2390
scrollup(wheadp, i, 1);
2394
if(!(nlp = h->next)){
2397
fs_give((void **) &free_istr);
2399
return(TRUE); /* can't go further */
2402
retval = TRUE; /* more work to do? */
2409
fs_give((void **) &free_istr);
2416
utf8 = ucs4_to_utf8_cpystr(buf);
2419
fs_give((void **) &free_istr);
2424
i = FormatLines(nlp, utf8, maxwid, break_on_comma, quoted);
2425
fs_give((void **) &utf8);
2427
case -1: /* bubble up worst case */
2431
if(retval == FALSE){
2439
fs_give((void **) &utf8);
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.
2452
FormatSyncAttach(void)
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());
2462
* PaintHeader - do the work of displaying the header from the given
2463
* physical screen line the end of the header.
2465
* 17 July 91 - fixed reshow to deal with arbitrarily large headers.
2468
PaintHeader(int line, /* physical line on screen */
2469
int clear) /* clear before painting */
2471
struct hdr_line *lp;
2476
char utf8buf[6*NLINE];
2481
pclear(COMPOSER_TOP_LINE, ComposerTopLine);
2483
curline = COMPOSER_TOP_LINE;
2484
curindex = curoffset = 0;
2486
for(lp = ods.top_l, e = ods.top_e; ; curline++){
2487
if((curline == line) || ((lp = next_hline(&e, lp)) == NULL))
2491
while(headents[e].name != NULL){ /* begin to redraw */
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++)
2503
else if(!is_blank(curline, 0, headents[e].prwid)){
2504
for(i = 0; i < headents[e].prwid; i++)
2510
if(*(bufp = buf) != '\0'){ /* need to paint? */
2511
movecursor(curline, 0); /* paint the line... */
2512
while(*bufp != '\0')
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);
2525
if(curoffset >= term.t_ncol)
2529
if(*bufp != '\0'){ /* need to move? */
2530
movecursor(curline, curoffset);
2531
while(*bufp != '\0'){ /* display what's not there */
2533
w = wcellwidth(*bufp);
2534
curoffset += (w >= 0 ? w : 1);
2540
if(curoffset < term.t_ncol){
2541
movecursor(curline, curoffset);
2545
curindex = curoffset = 0;
2546
if(curline >= BOTTOM())
2552
if(curline >= BOTTOM())
2553
return; /* don't paint delimiter */
2555
while(headents[++e].name != NULL)
2556
if(headents[e].display_it){
2557
lp = headents[e].hd_text;
2562
display_delimiter(ComposerEditing ? 0 : 1);
2568
* PaintBody() - generic call to handle repainting everything BUT the
2572
* The header redrawing in a level 0 body paint gets done
2576
PaintBody(int level)
2578
curwp->w_flag |= WFHARD; /* make sure framing's right */
2579
if(level == 0) /* specify what to update */
2582
update(); /* display message body */
2584
if(level == 0 && ComposerEditing){
2585
mlerase(); /* clear the error line */
2592
* display_for_send - paint the composer from the top line and return.
2595
display_for_send(void)
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
2604
struct on_display orig_ods;
2605
int orig_edit = ComposerEditing,
2606
orig_ct_line = ComposerTopLine;
2609
* fake that the cursor's in the first header line
2610
* and force repaint...
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 */
2621
UpdateHeader(0); /* redraw whole enchilada */
2622
PaintHeader(COMPOSER_TOP_LINE, TRUE);
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);
2631
/* in case we don't exit, set up restoring the screen */
2632
sgarbf = TRUE; /* force redraw */
2638
* ArrangeHeader - set up display parm such that header is reasonably
2645
register struct hdr_line *l;
2647
ods.p_line = ods.p_ind = 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)){
2661
* ComposerHelp() - display mail help in a context sensitive way
2662
* based on the level passed ...
2665
ComposerHelp(int level)
2668
VARS_TO_SAVE *saved_state;
2670
curwp->w_flag |= WFMODE;
2673
if(level < 0 || !headents[level].name){
2675
emlwrite("Sorry, I can't help you with that.", NULL);
2680
snprintf(buf, sizeof(buf), "Help for %s %.40s Field",
2681
(Pmaster->pine_flags & MDHDRONLY) ? "Address Book"
2683
headents[level].name);
2684
saved_state = save_pico_state();
2685
(*Pmaster->helper)(headents[level].help, buf, 1);
2687
restore_pico_state(saved_state);
2688
free_pico_state(saved_state);
2692
picosigs(); /* restore altered handlers */
2699
* ToggleHeader() - set or unset pico values to the full screen size
2700
* painting header if need be.
2703
ToggleHeader(int show)
2706
* check to see if we need to display the header...
2709
UpdateHeader(0); /* figure bounds */
2710
PaintHeader(COMPOSER_TOP_LINE, FALSE); /* draw it */
2714
* set bounds for no header display
2716
curwp->w_toprow = ComposerTopLine = COMPOSER_TOP_LINE;
2717
curwp->w_ntrows = BOTTOM() - ComposerTopLine;
2725
* HeaderLen() - return the length in lines of the exposed portion of the
2731
register struct hdr_line *lp;
2739
lp = next_hline(&e, lp);
2748
* first_hline() - return a pointer to the first displayable header line
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
2756
first_hline(int *entry)
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);
2764
return(NULL); /* this shouldn't happen */
2769
* first_sel_hline() - return a pointer to the first selectable header line
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
2777
first_sel_hline(int *entry)
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);
2785
return(NULL); /* this shouldn't happen */
2791
* next_hline() - return a pointer to the next line structure
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
2799
next_hline(int *entry, struct hdr_line *line)
2804
if(line->next == NULL){
2805
while(headents[++(*entry)].name != NULL){
2806
if(headents[*entry].display_it)
2807
return(headents[*entry].hd_text);
2818
* next_sel_hline() - return a pointer to the next selectable line structure
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
2826
next_sel_hline(int *entry, struct hdr_line *line)
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);
2846
* prev_hline() - return a pointer to the next line structure back
2849
* 1) pointer to previous displayable line in header and
2850
* the header entry that the next line is a part of
2852
* 2) NULL if no next line, leaving entry unchanged from
2853
* the value it had on entry.
2856
prev_hline(int *entry, struct hdr_line *line)
2861
if(line->prev == NULL){
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)
2874
*entry = orig_entry;
2883
* prev_sel_hline() - return a pointer to the previous selectable line
2886
* 1) pointer to previous selectable line in header and
2887
* the header entry that the next line is a part of
2889
* 2) NULL if no next line, leaving entry unchanged from
2890
* the value it had on entry.
2893
prev_sel_hline(int *entry, struct hdr_line *line)
2898
if(line->prev == NULL){
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)
2911
*entry = orig_entry;
2921
* first_requested_hline() - return pointer to first line that pico's caller
2922
* asked that we start on.
2925
first_requested_hline(int *ent)
2928
struct hdr_line *rv = NULL;
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;
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
2950
* showtop -- Attempt to show all header lines if they'll fit.
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
2958
* 2) if more than one page, always display last half when
2959
* pline is toward the end of the header
2962
* TRUE if anything changed (side effects: new p_line, top_l
2963
* top_e, and pico parms)
2964
* FALSE if nothing changed
2968
UpdateHeader(int showtop)
2970
register struct hdr_line *lp;
2973
int old_top = ComposerTopLine;
2974
int old_p = ods.p_line;
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 */
2983
else{ /* make sure p_line's OK */
2984
i = COMPOSER_TOP_LINE;
2987
while(lp != ods.cur_l){
2989
* this checks to make sure cur_l is below top_l and that
2990
* cur_l is on the screen...
2992
if((lp = next_hline(&le, lp)) == NULL || ++i >= BOTTOM()){
3000
ods.p_line = COMPOSER_TOP_LINE; /* find p_line... */
3003
while(lp && lp != ods.cur_l){
3004
lp = next_hline(&le, lp);
3009
ret = !(ods.p_line == old_p);
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 */
3018
ret = !(ComposerTopLine == old_top);
3020
if(wheadp->w_toprow != ComposerTopLine){ /* update pico params... */
3021
wheadp->w_toprow = ComposerTopLine;
3022
wheadp->w_ntrows = ((i = BOTTOM() - ComposerTopLine) > 0) ? i : 0;
3031
* NewTop() - calculate a new top_l based on the cur_l
3033
* showtop -- Attempt to show all the header lines if they'll fit
3036
* with ods.top_l and top_e pointing at a reasonable line
3042
register struct hdr_line *lp;
3048
i = showtop ? FULL_SCR() : HALF_SCR();
3050
while(lp != NULL && --i){
3053
lp = prev_hline(&e, lp);
3060
* display_delimiter() - just paint the header/message body delimiter with
3061
* inverse value specified by state.
3064
display_delimiter(int state)
3068
if(ComposerTopLine - 1 >= BOTTOM()) /* silently forget it */
3071
buf = utf8_to_ucs4_cpystr((gmode & MDHDRONLY) ? "" : HDR_DELIM);
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++)
3081
if(bufp[delim_ps] == '\0' && !(gmode & MDHDRONLY)){
3083
fs_give((void **) &buf);
3084
return; /* already displayed! */
3090
movecursor(ComposerTopLine - 1, 0);
3094
while(*bufp != '\0')
3095
pputc(*bufp++, state ? 1 : 0);
3101
fs_give((void **) &buf);
3107
* InvertPrompt() - invert the prompt associated with header entry to state
3108
* state (true if invert, false otherwise).
3110
* non-zero if nothing done
3111
* 0 if prompt inverted successfully
3114
* come to think of it, this func and the one above could
3115
* easily be combined
3118
InvertPrompt(int entry, int state)
3124
buf = utf8_to_ucs4_cpystr(headents[entry].prompt); /* fresh prompt paint */
3129
if((i = entry_line(entry, FALSE)) == -1){
3130
fs_give((void **) &buf);
3131
return(-1); /* silently forget it */
3134
end = buf + ucs4_strlen(buf);
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
3141
if(ucs4_str_width_ptr_to_ptr(buf, end) > headents[entry].prwid){
3142
end = ucs4_particular_width(buf, headents[entry].prwid);
3146
if(entry < 16 && (invert_ps&(1<<entry))
3147
== (state ? 1<<entry : 0)){ /* optimize ? */
3150
for(j = 0; bufp[j] && pscr(i, j)->c == bufp[j]; j++)
3153
if(bufp[j] == '\0'){
3155
invert_ps |= 1<<entry;
3157
invert_ps &= ~(1<<entry);
3159
fs_give((void **) &buf);
3160
return(0); /* already displayed! */
3164
if(entry < 16){ /* if > 16, cannot be stored in invert_ps */
3166
invert_ps |= 1<<entry;
3168
invert_ps &= ~(1<<entry);
3175
while(*bufp && *(bufp + 1))
3176
pputc(*bufp++, 1); /* putc upto last char */
3181
pputc(*bufp, 0); /* last char not inverted */
3183
fs_give((void **) &buf);
3191
* partial_entries() - toggle display of the bcc and fcc fields.
3194
* TRUE if there are partial entries on the display
3198
partial_entries(void)
3200
register struct headerentry *h;
3203
/*---- find out status of first rich header ---*/
3204
for(h = headents; !h->rich_header && h->name != NULL; h++)
3207
is_on = h->display_it;
3208
for(h = headents; h->name != NULL; h++)
3210
h->display_it = ! is_on;
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.
3224
* 1) physical line number of entry
3225
* 2) -1 if entry currently not on display
3228
entry_line(int entry, int lastchar)
3230
register int p_line = COMPOSER_TOP_LINE;
3232
register struct hdr_line *line;
3234
for(line = ods.top_l, i = ods.top_e;
3235
headents && headents[i].name && i <= entry;
3237
if(p_line >= BOTTOM())
3241
if(line->next == NULL)
3244
else if(line->prev == NULL)
3249
line = next_hline(&i, line);
3257
* physical_line() - return the physical line on the screen associated
3258
* with the given header line pointer.
3261
* 1) physical line number of entry
3262
* 2) -1 if entry currently not on display
3265
physical_line(struct hdr_line *l)
3267
register int p_line = COMPOSER_TOP_LINE;
3268
register struct hdr_line *lp;
3271
for(lp=ods.top_l, i=ods.top_e; headents[i].name && lp != NULL; p_line++){
3272
if(p_line >= BOTTOM())
3278
lp = next_hline(&i, lp);
3286
* call_builder() - resolve any nicknames in the address book associated
3287
* with the given entry...
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!!!
3294
* There could to be something here to resolve cur_l and top_l
3295
* reasonably into the new linked list for this entry.
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.
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
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.
3318
* > 0 if any names where resolved, otherwise
3321
* -1: move to next line
3322
* -2: don't move off this line
3325
call_builder(struct headerentry *entry, int *mangled, char **err)
3327
register int retval = 0;
3329
register struct hdr_line *line;
3335
struct headerentry *e;
3336
BUILDER_ARG *nextarg, *arg = NULL, *headarg = NULL;
3337
VARS_TO_SAVE *saved_state;
3342
line = entry->hd_text;
3344
while(line != NULL){
3345
sbuflen += (6*term.t_ncol);
3349
if((sbuf=(char *)malloc(sbuflen * sizeof(*sbuf))) == NULL){
3350
emlwrite("Can't malloc space to expand address", NULL);
3357
* cat the whole entry into one string...
3359
line = entry->hd_text;
3360
while(line != NULL){
3361
i = ucs4_strlen(line->text);
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.)
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.)
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
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.)
3379
if(entry->break_on_comma){
3380
UCS *space, commaspace[3];
3382
commaspace[0] = ',';
3383
commaspace[1] = ' ';
3384
commaspace[2] = '\0';
3385
space = commaspace+1;
3387
if(i && line->text[i-1] == ','){
3388
ucs4_strncat(line->text, space, HLSZ-i); /* help address builder */
3389
line->text[HLSZ-1] = '\0';
3391
else if(line->next != NULL && !strend(line->text, ',')){
3392
if(ucs4_strqchr(line->text, ',', "ed, -1)){
3393
ucs4_strncat(line->text, commaspace, HLSZ-i); /* implied comma */
3394
line->text[HLSZ-1] = '\0';
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';
3406
tmp = ucs4_to_utf8_cpystr(line->text);
3408
strncat(sbuf, tmp, sbuflen-strlen(sbuf));
3409
sbuf[sbuflen-1] = '\0';
3410
fs_give((void **) &tmp);
3416
if(entry->affected_entry){
3417
/* check if any non-sticky affected entries */
3418
for(e = entry->affected_entry; e; e = e->next_affected)
3422
/* there is at least one non-sticky so make a list to pass */
3424
for(e = entry->affected_entry; e; e = e->next_affected){
3426
headarg = arg = (BUILDER_ARG *)malloc(sizeof(BUILDER_ARG));
3428
emlwrite("Can't malloc space for fcc", NULL);
3434
arg->aff = &(e->bldr_private);
3435
arg->me = &(entry->bldr_private);
3439
nextarg = (BUILDER_ARG *)malloc(sizeof(BUILDER_ARG));
3441
emlwrite("Can't malloc space for fcc", NULL);
3445
nextarg->next = NULL;
3446
nextarg->tptr = NULL;
3447
nextarg->aff = &(e->bldr_private);
3448
nextarg->me = &(entry->bldr_private);
3449
arg->next = nextarg;
3456
arg->tptr = ucs4_to_utf8_cpystr(line->text);
3463
* Even if there are no affected entries, we still need the arg
3464
* to pass the "me" pointer.
3467
headarg = (BUILDER_ARG *)malloc(sizeof(BUILDER_ARG));
3469
emlwrite("Can't malloc space", NULL);
3473
headarg->next = NULL;
3474
headarg->tptr = NULL;
3475
headarg->aff = NULL;
3476
headarg->me = &(entry->bldr_private);
3481
* The builder may make a new call back to pico() so we save and
3482
* restore the pico state.
3484
saved_state = save_pico_state();
3485
retval = (*entry->builder)(sbuf, &s, err, headarg, mangled);
3487
restore_pico_state(saved_state);
3488
free_pico_state(saved_state);
3491
if(mangled && *mangled & BUILDER_MESSAGE_DISPLAYED){
3492
*mangled &= ~ BUILDER_MESSAGE_DISPLAYED;
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 */
3506
for(e = entry->affected_entry, arg = headarg;
3508
e = e->next_affected, arg = arg ? arg->next : NULL){
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 */
3515
InitEntryText(arg ? arg->tptr : "", e);
3516
if(line == ods.top_l)
3517
ods.top_l = e->hd_text;
3519
zotentry(line); /* blast old list o'entries */
3520
e->dirty = 1; /* mark it dirty */
3525
fs_give((void **) &tmp);
3533
for(arg = headarg; arg; arg = nextarg){
3534
/* Don't free xtra or me, they just point to headerentry data */
3535
nextarg = arg->next;
3551
VARS_TO_SAVE *saved_state;
3554
if(!Pmaster->expander)
3558
* Since expander may make a call back to pico() we need to
3559
* save and restore pico state.
3561
if((saved_state = save_pico_state()) != NULL){
3563
expret = (*Pmaster->expander)(headents, &s);
3565
restore_pico_state(saved_state);
3566
free_pico_state(saved_state);
3570
if(expret > 0 && s){
3572
int i, biggest = 100;
3573
struct headerentry *e;
3576
* Use tbuf to cat together multiple line entries before comparing.
3578
tbuf = (char *)malloc((biggest+1) * sizeof(*tbuf));
3579
for(e = headents, i=0; e->name != NULL; e++,i++){
3581
struct hdr_line *line;
3583
while(e->name && e->blank)
3589
for(line = e->hd_text; line != NULL; line = line->next){
3590
p = ucs4_to_utf8_cpystr(line->text);
3593
fs_give((void **) &p);
3600
tbuf = (char *)malloc((biggest+1) * sizeof(*tbuf));
3604
for(line = e->hd_text; line != NULL; line = line->next){
3605
p = ucs4_to_utf8_cpystr(line->text);
3607
strncat(tbuf, p, biggest+1-strlen(tbuf));
3608
tbuf[biggest] = '\0';
3609
fs_give((void **) &p);
3613
if(strcmp(tbuf, s[i])){ /* it changed */
3614
struct hdr_line *zline;
3616
line = zline = e->hd_text;
3617
InitEntryText(s[i], e);
3620
* If any of the lines for this entry are current or
3623
for(; line != NULL; line = line->next){
3624
if(line == ods.top_l)
3625
ods.top_l = e->hd_text;
3627
if(line == ods.cur_l)
3628
ods.cur_l = e->hd_text;
3631
zotentry(zline); /* blast old list o'entries */
3653
* strend - neglecting white space, returns TRUE if c is at the
3654
* end of the given line. otherwise FALSE.
3657
strend(UCS *s, UCS ch)
3661
if(s == NULL || *s == '\0')
3664
for(b = &s[ucs4_strlen(s)] - 1; *b && ucs4_isspace(*b); b--){
3674
* ucs4_strqchr - returns pointer to first non-quote-enclosed occurance of ch in
3675
* the given string. otherwise NULL.
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)
3683
ucs4_strqchr(UCS *s, UCS ch, int *q, int m)
3685
int quoted = (q) ? *q : 0;
3687
for(; s && *s && m != 0; s++, m--){
3694
if(!quoted && *s == ch)
3703
* KillHeaderLine() - kill a line in the header
3706
* This is pretty simple. Just using the emacs kill buffer
3707
* and its accompanying functions to cut the text from lines.
3710
* TRUE if hldelete worked
3714
KillHeaderLine(struct hdr_line *l, int append)
3724
if (gmode & MDDTKILL){
3725
if (c[i] == '\0') /* don't insert a new line after this line*/
3727
/*put to be deleted part into kill buffer */
3728
for (i=ods.p_ind; c[i] != '\0'; i++)
3731
while(*c != '\0') /* splat out the line */
3736
kinsert('\n'); /* helpful to yank in body */
3739
mswin_killbuftoclip (kremove);
3742
if (gmode & MDDTKILL){
3743
if (l->text[0]=='\0'){
3745
if(l->next && l->prev)
3746
ods.cur_l = next_hline(&ods.cur_e, l);
3748
ods.cur_l = prev_hline(&ods.cur_e, l);
3751
ods.top_l = ods.cur_l;
3753
return(hldelete(l));
3756
l->text[ods.p_ind]='\0'; /* delete part of the line from the cursor */
3760
if(l->next && l->prev)
3761
ods.cur_l = next_hline(&ods.cur_e, l);
3763
ods.cur_l = prev_hline(&ods.cur_e, l);
3766
ods.top_l = ods.cur_l;
3768
return(hldelete(l)); /* blast it */
3775
* SaveHeaderLines() - insert the saved lines in the list before the
3776
* current line in the header
3779
* Once again, just using emacs' kill buffer and its
3783
* TRUE if something good happend
3787
SaveHeaderLines(void)
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;
3794
int len, buf_len, work_buf_len, tentative_p_ind = 0;
3795
struct hdr_line *travel, *tentative_cur_l = NULL;
3798
if((bp = buf = (UCS *) malloc((ksize()+5) * sizeof(*buf))) == NULL){
3799
emlwrite("Can't malloc space for saved text", NULL);
3806
for(i=0; i < ksize(); i++)
3807
if(kremove(i) != '\n') /* filter out newlines */
3808
*bp++ = (UCS) kremove(i);
3812
while(--bp >= buf) /* kill trailing white space */
3814
if(ods.cur_l->text[0] != '\0'){
3815
if(*bp == '>'){ /* inserting an address */
3816
*++bp = ','; /* so add separator */
3820
else{ /* nothing in field yet */
3821
if(*bp == ','){ /* so blast any extra */
3822
*bp = '\0'; /* separators */
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);
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);
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';
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);
3858
if(FormatLines(ods.cur_l, empty, LINEWID(),
3859
headents[ods.cur_e].break_on_comma, 0) == -1) {
3867
len += ucs4_strlen(travel->text);
3872
* This comes after the break above because it will
3873
* be accounted for in the while loop below.
3875
if(!tentative_cur_l){
3876
if(tentative_p_ind <= ucs4_strlen(travel->text))
3877
tentative_cur_l = travel;
3879
tentative_p_ind -= ucs4_strlen(travel->text);
3882
travel = travel->next;
3886
ods.p_ind = ucs4_strlen(travel->text) - len + HLSZ;
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;
3897
if(FormatLines(ods.cur_l, empty, LINEWID(),
3898
headents[ods.cur_e].break_on_comma, 0) == -1) {
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;
3908
tentative_p_ind -= ucs4_strlen(travel->text);
3911
len += ucs4_strlen(travel->text);
3912
if (len >= work_buf_len + ods.p_ind)
3915
travel = travel->next;
3919
ods.p_ind = ucs4_strlen(travel->text) - len + work_buf_len + ods.p_ind;
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;
3936
* break_point - Break the given line at the most reasonable character breakch
3937
* within maxwid max characters.
3940
* Pointer to the best break point in s, or
3941
* Pointer to the beginning of s if no break point found
3944
break_point(UCS *line, int maxwid, UCS breakch, int *quotedarg)
3946
UCS *bp; /* break point */
3947
int quoted = (quotedarg) ? *quotedarg : 0;
3950
* Start at maxwid and work back until first opportunity to break.
3952
bp = ucs4_particular_width(line, maxwid);
3955
if(breakch == ',' && *bp == '"') /* don't break on quoted ',' */
3956
quoted = !quoted; /* toggle quoted state */
3960
if(ucs4_str_width_ptr_to_ptr(line, bp+1) < maxwid){
3961
bp++; /* leave the ' ' */
3967
* if break char isn't a space, leave a space after
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;
3982
*quotedarg = quoted;
3984
return((quoted) ? line : bp);
3991
* hldelete() - remove the header line pointed to by l from the linked list
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
4006
hldelete(struct hdr_line *l)
4008
register struct hdr_line *lp;
4013
if(l->next == NULL && l->prev == NULL){ /* only one line in field */
4015
return(TRUE); /* no free only line in list */
4017
else if(l->next == NULL){ /* last line in field */
4018
l->prev->next = NULL;
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';
4024
if((l->next = lp->next) != NULL)
4028
else{ /* some where in field */
4029
l->prev->next = l->next;
4030
l->next->prev = l->prev;
4042
* is_blank - returns true if the next n chars from coordinates row, col
4043
* on display are spaces
4046
is_blank(int row, int col, int n)
4049
for( ;col < n; col++){
4050
if(pscr(row, col) == NULL || pscr(row, col)->c != ' ')
4058
* ShowPrompt - display key help corresponding to the current header entry
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]));
4069
menu_header[TO_KEY].name = NULL;
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";
4076
menu_header[SEND_KEY].label = N_("Send");
4079
menu_header[CUT_KEY].name = NULL;
4080
menu_header[DEL_KEY].name = NULL;
4081
menu_header[UDEL_KEY].name = NULL;
4084
menu_header[CUT_KEY].name = "^K";
4085
menu_header[DEL_KEY].name = "^D";
4086
menu_header[UDEL_KEY].name = "^U";
4089
if(Pmaster->ctrlr_label){
4090
menu_header[RICH_KEY].label = Pmaster->ctrlr_label;
4091
menu_header[RICH_KEY].name = "^R";
4093
else if(gmode & MDHDRONLY){
4094
menu_header[RICH_KEY].name = NULL;
4097
menu_header[RICH_KEY].label = N_("Rich Hdr");
4098
menu_header[RICH_KEY].name = "^R";
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");
4107
menu_header[PONE_KEY].name = NULL;
4109
menu_header[ATT_KEY].name = NULL;
4112
menu_header[PONE_KEY].name = "^O";
4113
menu_header[PONE_KEY].label = N_("Postpone");
4115
menu_header[ATT_KEY].name = "^J";
4118
wkeyhelp(menu_header);
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".
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;
4141
while(headents[i].name != NULL){
4144
* attachments are special case, already in struct we pass back
4146
if(headents[i].is_attach){
4152
if(headents[i].blank){
4158
* count chars to see if we need a new malloc'd space for our
4161
line = headents[i].hd_text;
4163
while(line != NULL){
4165
* add one for possible concatination of a ' ' character ...
4167
p = ucs4_to_utf8_cpystr(line->text);
4170
if(p[0] && p[strlen(p)-1] == ',')
4173
fs_give((void **) &p);
4179
line = headents[i].hd_text;
4180
if(count <= headents[i].maxlen){
4181
*headents[i].realaddr[0] = '\0';
4185
* don't forget to include space for the null terminator!!!!
4187
if((bufp = (char *)malloc((count+1) * sizeof(char))) != NULL){
4190
free(*headents[i].realaddr);
4191
*headents[i].realaddr = bufp;
4192
headents[i].maxlen = count;
4195
emlwrite("Can't make room to pack header field.", NULL);
4200
if(retval != FALSE){
4201
int saw_current_line = 0;
4203
while(line != NULL){
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)
4210
Pmaster->edit_offset += ucs4_strlen(line->text);
4213
p = ucs4_to_utf8_cpystr(line->text);
4215
strncat(*headents[i].realaddr, p, headents[i].maxlen+1-strlen(*headents[i].realaddr));
4216
(*headents[i].realaddr)[headents[i].maxlen] = '\0';
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';
4223
fs_give((void **) &p);
4239
* zotheader - free all malloc'd lines associated with the header structs
4244
register struct headerentry *i;
4246
for(i = headents; headents && i->name; i++)
4247
zotentry(i->hd_text);
4252
* zotentry - free malloc'd space associated with the given linked list
4255
zotentry(struct hdr_line *l)
4257
register struct hdr_line *ld, *lf = l;
4259
while((ld = lf) != NULL){
4261
ld->next = ld->prev = NULL;
4269
* zotcomma - blast any trailing commas and white space from the end
4278
p = &s[ucs4_strlen(s)];
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
4301
save_pico_state(void)
4307
extern VIDEO **vscreen;
4308
extern VIDEO **pscreen;
4309
extern int pico_all_done;
4310
extern jmp_buf finstate;
4311
extern UCS *pico_anchor;
4313
if((ret = (VARS_TO_SAVE *)malloc(sizeof(VARS_TO_SAVE))) == NULL)
4318
ret->lbound = lbound;
4319
ret->vscreen = vscreen;
4320
ret->pscreen = pscreen;
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);
4332
ret->ComposerTopLine = ComposerTopLine;
4333
ret->ComposerEditing = ComposerEditing;
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);
4347
ret->wheadp = wheadp;
4349
ret->bheadp = bheadp;
4350
ret->km_popped = km_popped;
4351
ret->mrow = term.t_mrow;
4353
/* Initialize for next pico call */
4364
restore_pico_state(VARS_TO_SAVE *state)
4369
extern VIDEO **vscreen;
4370
extern VIDEO **pscreen;
4371
extern int pico_all_done;
4372
extern jmp_buf finstate;
4373
extern UCS *pico_anchor;
4376
vtrow = state->vtrow;
4377
vtcol = state->vtcol;
4378
lbound = state->lbound;
4379
vscreen = state->vscreen;
4380
pscreen = state->pscreen;
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;
4389
headents = Pmaster->headents;
4391
fillcol = state->fillcol;
4393
ucs4_strncpy(pat, state->pat, NPAT);
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';
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;
4420
free_pico_state(VARS_TO_SAVE *state)
4426
free(state->opertree);
4433
* Ok to call this twice in a row because it won't do anything the second
4437
fix_mangle_and_err(int *mangled, char **errmsg, char *name)
4439
if(mangled && *mangled){
4446
if(errmsg && *errmsg){
4450
snprintf(err, sizeof(err), "%s field: %s", name, *errmsg);
4452
emlwrite(err, NULL);
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.
4473
HeaderEditor(int f, int n)
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
4484
if (!mswin_caninput())
4488
retval = HeaderEditorWork(f, n);
4490
retval = mousepress(0,0);