1 #if !defined(lint) && !defined(DOS)
2 static char rcsid[] = "$Id: send.c 1142 2008-08-13 17:22:21Z hubert@u.washington.edu $";
3 #endif
4 
5 /*
6  * ========================================================================
7  * Copyright 2013-2021 Eduardo Chappa
8  * Copyright 2006-2008 University of Washington
9  *
10  * Licensed under the Apache License, Version 2.0 (the "License");
11  * you may not use this file except in compliance with the License.
12  * You may obtain a copy of the License at
13  *
14  *     http://www.apache.org/licenses/LICENSE-2.0
15  *
16  * ========================================================================
17  */
18 
19 /*======================================================================
20        Functions for composing and sending mail
21 
22  ====*/
23 
24 
25 #include "headers.h"
26 #include "send.h"
27 #include "status.h"
28 #include "mailview.h"
29 #include "mailindx.h"
30 #include "dispfilt.h"
31 #include "keymenu.h"
32 #include "folder.h"
33 #include "radio.h"
34 #include "addrbook.h"
35 #include "reply.h"
36 #include "titlebar.h"
37 #include "signal.h"
38 #include "mailcmd.h"
39 #include "roleconf.h"
40 #include "adrbkcmd.h"
41 #include "busy.h"
42 #include "../pith/debug.h"
43 #include "../pith/state.h"
44 #include "../pith/conf.h"
45 #include "../pith/flag.h"
46 #include "../pith/bldaddr.h"
47 #include "../pith/copyaddr.h"
48 #include "../pith/detach.h"
49 #include "../pith/mimedesc.h"
50 #include "../pith/pipe.h"
51 #include "../pith/addrstring.h"
52 #include "../pith/news.h"
53 #include "../pith/detoken.h"
54 #include "../pith/util.h"
55 #include "../pith/init.h"
56 #include "../pith/mailcmd.h"
57 #include "../pith/ablookup.h"
58 #include "../pith/reply.h"
59 #include "../pith/hist.h"
60 #include "../pith/list.h"
61 #include "../pith/icache.h"
62 #include "../pith/busy.h"
63 #include "../pith/mimetype.h"
64 #include "../pith/send.h"
65 #include "../pith/smime.h"
66 
67 
68 typedef struct body_particulars {
69     unsigned short     type, encoding, had_csp;
70     char              *subtype, *charset;
71     PARAMETER         *parameter;
72 } BODY_PARTICULARS_S;
73 
74 /*
75  * macro to bind pico's headerentry pointer to PINEFIELD "extdata" hook
76  */
77 #define	HE(PF)	((struct headerentry *)((PF)->extdata))
78 
79 
80 /*
81  * Internal Prototypes
82  */
83 int	   redraft(MAILSTREAM **, ENVELOPE **, BODY **, char **, char **, REPLY_S **,
84 		   REDRAFT_POS_S **, PINEFIELD **, ACTION_S **, int);
85 int	   redraft_prompt(char *, char *, int);
86 int	   check_for_subject(METAENV *);
87 int	   check_for_fcc(char *);
88 void	   free_prompts(PINEFIELD *);
89 int	   postpone_prompt(void);
90 METAENV	  *pine_simple_send_header(ENVELOPE *, char **, char ***);
91 void	   call_mailer_file_result(char *, int);
92 void	   mark_address_failure_for_pico(METAENV *);
93 BODY_PARTICULARS_S
94 	  *save_body_particulars(BODY *);
95 void       reset_body_particulars(BODY_PARTICULARS_S *, BODY *);
96 void       free_body_particulars(BODY_PARTICULARS_S *);
97 long	   message_format_for_pico(long, int (*)(int));
98 int	   send_exit_for_pico(struct headerentry *, void (*)(void), int, char **);
99 void	   new_thread_on_blank_subject(void);
100 char      *choose_a_priority(char *);
101 int        dont_flow_this_time(void);
102 int	   mime_type_for_pico(char *);
103 char      *cancel_for_pico(void (*)(void));
104 int	   filter_message_text(char *, ENVELOPE *, BODY *, STORE_S **, METAENV *);
105 void	   pine_send_newsgroup_name(char *, char*, size_t);
106 void       outgoing2strings(METAENV *, BODY *, void **, PATMT **, int);
107 void       strings2outgoing(METAENV *, BODY **, PATMT *, int);
108 void	   create_message_body_text(BODY *, int);
109 void	   set_body_size(BODY *);
110 int        view_as_rich(char *, int);
111 int	   background_posting(int);
112 int	   valid_subject(char *, char **, char **,BUILDER_ARG *,int *);
113 int	   build_addr_lcc(char *, char **, char **, BUILDER_ARG *, int *);
114 int	   news_build(char *, char **, char **, BUILDER_ARG *, int *);
115 void	   news_build_busy(void);
116 #if defined(DOS) || defined(OS2)
117 int	   dos_valid_from(void);
118 #endif /* defined(DOS) || defined(OS2) */
119 
120 
121 /*
122  * Pointer to buffer to hold pointers into pine data that's needed by pico.
123  */
124 static	PICO	  *pbf;
125 
126 
127 static char	  *g_rolenick = NULL;
128 
129 
130 static char	  *sending_filter_requested;
131 static char	   background_requested, flowing_requested;
132 static unsigned	   call_mailer_flags;
133 static char	  *priority_requested;
134 
135 /* local global to save busy_cue state */
136 static int	   news_busy_cue = 0;
137 
138 
139 /*
140  * Various useful strings
141  */
142 #define	INTRPT_PMT \
143 	    _("Continue INTERRUPTED composition (answering \"n\" won't erase it)")
144 #define	PSTPND_PMT \
145 	    _("Continue postponed composition (answering \"No\" won't erase it)")
146 #define	FORM_PMT \
147 	    _("Start composition from Form Letter Folder")
148 #define	PSTPN_FORM_PMT	\
149 	    _("Save to Postponed or Form letter folder? ")
150 #define	POST_PMT   \
151 	    _("Posted message may go to thousands of readers. Really post")
152 #define	INTR_DEL_PMT \
153 	    _("Deleted messages will be removed from folder after use.  Proceed")
154 
155 
156 /*
157  * Macros to help sort out posting results
158  */
159 #define	P_MAIL_WIN	0x01
160 #define	P_MAIL_LOSE	0x02
161 #define	P_MAIL_BITS	0x03
162 #define	P_NEWS_WIN	0x04
163 #define	P_NEWS_LOSE	0x08
164 #define	P_NEWS_BITS	0x0C
165 #define	P_FCC_WIN	0x10
166 #define	P_FCC_LOSE	0x20
167 #define	P_FCC_BITS	0x30
168 
169 
170 #define COMPOSE_MAIL_TITLE "COMPOSE MESSAGE"
171 
172 
173 /*
174  * For check_for_subject and check_for_fcc
175  */
176 #define CF_OK		0x1
177 #define CF_MISSING	0x2
178 
179 
180 /*----------------------------------------------------------------------
181     Compose screen (not forward or reply). Set up envelope, call composer
182 
183    Args: pine_state -- The usual pine structure
184 
185   Little front end for the compose screen
186   ---*/
187 void
compose_screen(struct pine * pine_state)188 compose_screen(struct pine *pine_state)
189 {
190     void (*prev_screen)(struct pine *) = pine_state->prev_screen,
191 	 (*redraw)(void) = pine_state->redrawer;
192 
193     pine_state->redrawer = NULL;
194     ps_global->next_screen = SCREEN_FUN_NULL;
195     mailcap_free(); /* free resources we won't be using for a while */
196     compose_mail(NULL, NULL, NULL, NULL, NULL);
197     pine_state->next_screen = prev_screen;
198     pine_state->redrawer = redraw;
199 }
200 
201 
202 /*----------------------------------------------------------------------
203     Alternate compose screen. Set up role and call regular compose.
204 
205    Args: pine_state -- The usual pine structure
206   ---*/
207 void
alt_compose_screen(struct pine * pine_state)208 alt_compose_screen(struct pine *pine_state)
209 {
210     ACTION_S *role = NULL;
211     void (*prev_screen)(struct pine *) = pine_state->prev_screen,
212 	 (*redraw)(void) = pine_state->redrawer;
213 
214     pine_state->redrawer = NULL;
215     ps_global->next_screen = SCREEN_FUN_NULL;
216     mailcap_free(); /* free resources we won't be using for a while */
217 
218     /* Setup role */
219     if(role_select_screen(pine_state, &role, MC_COMPOSE) < 0){
220 	cmd_cancelled("Composition");
221 	pine_state->next_screen = prev_screen;
222 	pine_state->redrawer = redraw;
223 	return;
224     }
225 
226     /*
227      * If default role was selected (NULL) we need to make up a role which
228      * won't do anything, but will cause compose_mail to think there's
229      * already a role so that it won't try to confirm the default.
230      */
231     if(role)
232       role = combine_inherited_role(role);
233     else{
234 	role = (ACTION_S *)fs_get(sizeof(*role));
235 	memset((void *)role, 0, sizeof(*role));
236 	role->nick = cpystr("Default Role");
237     }
238 
239     pine_state->redrawer = NULL;
240     compose_mail(NULL, NULL, role, NULL, NULL);
241     free_action(&role);
242     pine_state->next_screen = prev_screen;
243     pine_state->redrawer = redraw;
244 }
245 
246 
247 /*----------------------------------------------------------------------
248      Format envelope for outgoing message and call editor
249 
250  Args:  given_to -- An address to send mail to (usually from command line
251                        invocation)
252         fcc_arg  -- The fcc that goes with this address.
253 
254  If a "To" line is given format that into the envelope and get ready to call
255            the composer
256  If there's a message postponed, offer to continue it, and set it up,
257  otherwise just fill in the outgoing envelope as blank.
258 
259  NOTE: we ignore postponed and interrupted messages in nr mode
260  ----*/
261 void
compose_mail(char * given_to,char * fcc_arg,ACTION_S * role_arg,PATMT * attach,gf_io_t inc_text_getc)262 compose_mail(char *given_to, char *fcc_arg, ACTION_S *role_arg,
263 	     PATMT *attach, gf_io_t inc_text_getc)
264 {
265     BODY	  *body = NULL;
266     ENVELOPE	  *outgoing = NULL;
267     PINEFIELD	  *custom   = NULL;
268     REPLY_S	  *reply	= NULL;
269     REDRAFT_POS_S *redraft_pos = NULL;
270     ACTION_S      *role = NULL;
271     MAILSTREAM	  *stream;
272     char	  *fcc_to_free,
273 		  *fcc      = NULL,
274 		  *lcc      = NULL,
275 		  *sig      = NULL;
276     int		   fcc_is_sticky = 0,
277 		   to_is_sticky = 0,
278                    intrptd = 0,
279                    postponed = 0,
280 		   form = 0;
281 
282     dprint((1,
283                  "\n\n    ---- COMPOSE SCREEN (not in pico yet) ----\n"));
284 
285     /*-- Check for INTERRUPTED mail  --*/
286     if(!role_arg && !(given_to || attach)){
287 	char	     file_path[MAXPATH+1];
288 
289 	/* build filename and see if it exists.  build_path creates
290 	 * an explicit local path name, so all c-client access is thru
291 	 * local drivers.
292 	 */
293 	file_path[0] = '\0';
294 	build_path(file_path,
295 		   ps_global->VAR_OPER_DIR ? ps_global->VAR_OPER_DIR
296 					   : ps_global->home_dir,
297 		   INTERRUPTED_MAIL, sizeof(file_path));
298 
299 	/* check to see if the folder exists, the user wants to continue
300 	 * and that we can actually read something in...
301 	 */
302 	if(folder_exists(NULL, file_path) & FEX_ISFILE)
303 	  intrptd = 1;
304     }
305 
306     /*-- Check for postponed mail --*/
307     if(!role_arg
308        && !outgoing				/* not replying/forwarding */
309        && !(given_to || attach)			/* not command line send */
310        && ps_global->VAR_POSTPONED_FOLDER	/* folder to look in */
311        && ps_global->VAR_POSTPONED_FOLDER[0])
312       postponed = 1;
313 
314     /*-- Check for form letter folder --*/
315     if(!role_arg
316        && !outgoing				/* not replying/forwarding */
317        && !(given_to || attach)			/* not command line send */
318        && ps_global->VAR_FORM_FOLDER		/* folder to look in */
319        && ps_global->VAR_FORM_FOLDER[0])
320       form = 1;
321 
322     if(!outgoing && !(given_to || attach)
323        && !role_arg && F_ON(F_ALT_COMPOSE_MENU, ps_global)){
324         char     prompt[80];
325  	char     letters[30];
326 	char     chosen_task;
327  	char    *new      = "New";
328  	char    *intrpt   = "Interrupted";
329  	char    *postpnd  = "Postponed";
330  	char    *formltr  = "FormLetter";
331  	char    *roles    = "setRole";
332 	HelpType help     = h_composer_browse;
333 	ESCKEY_S compose_style[6];
334 	unsigned which_help;
335 	int      ekey_num;
336 
337 	ekey_num = 0;
338 	compose_style[ekey_num].ch      = 'n';
339  	compose_style[ekey_num].rval    = 'n';
340  	compose_style[ekey_num].name    = "N";
341  	compose_style[ekey_num++].label = new;
342 
343 	if(intrptd){
344  	    compose_style[ekey_num].ch      = 'i';
345  	    compose_style[ekey_num].rval    = 'i';
346  	    compose_style[ekey_num].name    = "I";
347  	    compose_style[ekey_num++].label = intrpt;
348  	}
349 
350  	if(postponed){
351  	    compose_style[ekey_num].ch      = 'p';
352  	    compose_style[ekey_num].rval    = 'p';
353  	    compose_style[ekey_num].name    = "P";
354  	    compose_style[ekey_num++].label = postpnd;
355  	}
356 
357  	if(form){
358  	    compose_style[ekey_num].ch      = 'f';
359  	    compose_style[ekey_num].rval    = 'f';
360  	    compose_style[ekey_num].name    = "F";
361  	    compose_style[ekey_num++].label = formltr;
362  	}
363 
364 	compose_style[ekey_num].ch      = 'r';
365 	compose_style[ekey_num].rval    = 'r';
366 	compose_style[ekey_num].name    = "R";
367 	compose_style[ekey_num++].label = roles;
368 
369  	compose_style[ekey_num].ch    = -1;
370 
371  	if(F_ON(F_BLANK_KEYMENU,ps_global)){
372  	    char *p;
373 
374  	    p = letters;
375  	    *p = '\0';
376  	    for(ekey_num = 0; compose_style[ekey_num].ch != -1; ekey_num++){
377 		if(p - letters < sizeof(letters))
378  		  *p++ = (char) compose_style[ekey_num].ch;
379 
380  		if(compose_style[ekey_num + 1].ch != -1 && p - letters < sizeof(letters))
381  		  *p++ = ',';
382  	    }
383 
384 	    if(p - letters < sizeof(letters))
385  	      *p = '\0';
386  	}
387 
388 	which_help = intrptd + 2 * postponed + 4 * form;
389 	switch(which_help){
390 	  case 1:
391 	    help = h_compose_intrptd;
392 	    break;
393 	  case 2:
394 	    help = h_compose_postponed;
395 	    break;
396 	  case 3:
397 	    help = h_compose_intrptd_postponed;
398 	    break;
399 	  case 4:
400 	    help = h_compose_form;
401 	    break;
402 	  case 5:
403 	    help = h_compose_intrptd_form;
404 	    break;
405 	  case 6:
406 	    help = h_compose_postponed_form;
407 	    break;
408 	  case 7:
409 	    help = h_compose_intrptd_postponed_form;
410 	    break;
411 	  default:
412 	    help = h_compose_default;
413 	    break;
414 	}
415 
416  	snprintf(prompt, sizeof(prompt),
417  		"Choose a compose method from %s : ",
418  		F_ON(F_BLANK_KEYMENU,ps_global) ? letters : "the menu below");
419 	prompt[sizeof(prompt)-1] = '\0';
420 
421  	chosen_task = radio_buttons(prompt, -FOOTER_ROWS(ps_global),
422  				    compose_style, 'n', 'x', help, RB_NORM);
423 	intrptd = postponed = form = 0;
424 
425 	switch(chosen_task){
426 	  case 'i':
427 	    intrptd = 1;
428 	    break;
429 	  case 'p':
430 	    postponed = 1;
431 	    break;
432 	  case 'r':
433 	    {
434 	      void (*prev_screen)(struct pine *) = ps_global->prev_screen,
435 		   (*redraw)(void) = ps_global->redrawer;
436 
437 	      ps_global->redrawer = NULL;
438 	      ps_global->next_screen = SCREEN_FUN_NULL;
439 	      if(role_select_screen(ps_global, &role, MC_COMPOSE) < 0){
440 		cmd_cancelled("Composition");
441 		ps_global->next_screen = prev_screen;
442 		ps_global->redrawer = redraw;
443 		return;
444 	      }
445 
446 	      ps_global->next_screen = prev_screen;
447 	      ps_global->redrawer = redraw;
448 	      if(role)
449 		role = combine_inherited_role(role);
450 	    }
451 	    break;
452 
453 	  case 'f':
454 	    form = 1;
455 	    break;
456 
457 	  case 'x':
458 	    q_status_message(SM_ORDER, 0, 3,
459 			     "Composition cancelled");
460 	    return;
461 	    break;
462 
463 	  default:
464 	    break;
465 	}
466     }
467 
468     if(intrptd && !outgoing){
469 	char	     file_path[MAXPATH+1];
470 	int	     ret = 'n';
471 
472 	file_path[0] = '\0';
473 	build_path(file_path,
474 		   ps_global->VAR_OPER_DIR ? ps_global->VAR_OPER_DIR
475 					   : ps_global->home_dir,
476 		   INTERRUPTED_MAIL, sizeof(file_path));
477 	if(folder_exists(NULL, file_path) & FEX_ISFILE){
478 	    if((stream = pine_mail_open(NULL, file_path,
479 					SP_USEPOOL|SP_TEMPUSE, NULL))
480 	       && !stream->halfopen){
481 
482 		if(F_ON(F_ALT_COMPOSE_MENU, ps_global) ||
483 		   (ret = redraft_prompt("Interrupted",INTRPT_PMT,'n')) =='y'){
484 		    if(!redraft(&stream, &outgoing, &body, &fcc, &lcc, &reply,
485 				&redraft_pos, &custom, &role, REDRAFT_DEL)){
486 			if(stream)
487 			  pine_mail_close(stream);
488 
489 			return;
490 		    }
491 
492 		    to_is_sticky++;
493 
494 		    /* redraft() may or may not have closed stream */
495 		    if(stream)
496 		      pine_mail_close(stream);
497 
498 		    postponed = form = 0;
499 		}
500 		else{
501 		    pine_mail_close(stream);
502 		    if(ret == 'x'){
503 			q_status_message(SM_ORDER, 0, 3,
504 					 _("Composition cancelled"));
505 			return;
506 		    }
507 		}
508 	    }
509 	    else{
510 		q_status_message1(SM_ORDER | SM_DING, 3, 3,
511 				  _("Can't open Interrupted mailbox: %s"),
512 				  file_path);
513 		if(stream)
514 		  pine_mail_close(stream);
515 	    }
516 	}
517     }
518 
519     if(postponed && !outgoing){
520 	int ret = 'n', done = 0;
521 	int exists;
522 
523 	if((exists=postponed_stream(&stream,
524 				    ps_global->VAR_POSTPONED_FOLDER,
525 				    "Postponed", 0)) & FEX_ISFILE){
526 	    if(F_ON(F_ALT_COMPOSE_MENU, ps_global) ||
527 	       (ret = redraft_prompt("Postponed",PSTPND_PMT,'n')) == 'y'){
528 		if(!redraft(&stream, &outgoing, &body, &fcc, &lcc, &reply,
529 			    &redraft_pos, &custom, &role,
530 			    REDRAFT_DEL | REDRAFT_PPND))
531 		  done++;
532 
533 		/* stream may or may not be closed in redraft() */
534 		if(stream && (stream != ps_global->mail_stream))
535 		  pine_mail_close(stream);
536 
537 		to_is_sticky++;
538 		intrptd = form = 0;
539 	    }
540 	    else{
541 		if(stream != ps_global->mail_stream)
542 		  pine_mail_close(stream);
543 
544 		if(ret == 'x'){
545 		    q_status_message(SM_ORDER, 0, 3,
546 				     _("Composition cancelled"));
547 		    done++;
548 		}
549 	    }
550 	}
551 	else if(F_ON(F_ALT_COMPOSE_MENU, ps_global))
552 	  done++;
553 
554 	if(done)
555 	  return;
556     }
557 
558     if(form && !outgoing){
559 	int ret = 'n', done = 0;
560 	int exists;
561 
562 	if((exists=postponed_stream(&stream,
563 				    ps_global->VAR_FORM_FOLDER,
564 				    "Form letter", 1)) & FEX_ISFILE){
565 	    if(F_ON(F_ALT_COMPOSE_MENU, ps_global) ||
566 	       (ret = want_to(FORM_PMT,'y','x',NO_HELP,WT_NORM))=='y'){
567 		if(!redraft(&stream, &outgoing, &body, &fcc, &lcc, &reply,
568 			    &redraft_pos, &custom, &role, REDRAFT_NONE))
569 		    done++;
570 
571 		/* stream may or may not be closed in redraft() */
572 		if(stream && (stream != ps_global->mail_stream))
573 		  pine_mail_close(stream);
574 
575 		to_is_sticky++;
576 		intrptd = postponed = 0;
577 	    }
578 	    else{
579 		if(stream != ps_global->mail_stream)
580 		  pine_mail_close(stream);
581 
582 		if(ret == 'x'){
583 		    q_status_message(SM_ORDER, 0, 3,
584 				     _("Composition cancelled"));
585 		    done++;
586 		}
587 	    }
588 	}
589 	else{
590 	  if(F_ON(F_ALT_COMPOSE_MENU, ps_global)){
591 	    q_status_message(SM_ORDER | SM_DING, 3, 3,
592 			      _("Form letter folder doesn't exist!"));
593 	    return;
594 	  }
595 	}
596 
597 	if(done)
598 	  return;
599     }
600 
601     /*-- normal composition --*/
602     if(!outgoing){
603 	int impl, template_len = 0;
604 	long rflags = ROLE_COMPOSE;
605 	PAT_STATE dummy;
606 
607         /*=================  Compose new message ===============*/
608         body         = mail_newbody();
609         outgoing     = mail_newenvelope();
610 
611         if(given_to)
612 	  rfc822_parse_adrlist(&outgoing->to, given_to, ps_global->maildomain);
613 
614 	/*
615 	 * Setup possible role
616 	 */
617 	if(role_arg)
618 	  role = copy_action(role_arg);
619 
620 	if(!role){
621 	    /* Setup possible compose role */
622 	    if(nonempty_patterns(rflags, &dummy)){
623 		/*
624 		 * setup default role
625 		 * Msgno = -1 means there is no msg.
626 		 * This will match roles which have the Compose Use turned
627 		 * on, and have no patterns set, and match the Current
628 		 * Folder Type.
629 		 */
630 		role = set_role_from_msg(ps_global, rflags, -1L, NULL);
631 
632 		if(confirm_role(rflags, &role))
633 		  role = combine_inherited_role(role);
634 		else{				/* cancel reply */
635 		    role = NULL;
636 		    cmd_cancelled("Composition");
637 		    return;
638 		}
639 	    }
640 	}
641 
642 	if(role)
643 	  q_status_message1(SM_ORDER, 3, 4, _("Composing using role \"%s\""),
644 			    role->nick);
645 
646         outgoing->message_id = generate_message_id(role);
647 	/*
648 	 * The type of storage object allocated below is vitally
649 	 * important.  See SIMPLIFYING ASSUMPTION #37
650 	 */
651 	if((body->contents.text.data = (void *) so_get(PicoText,
652 						      NULL, EDIT_ACCESS)) != NULL){
653 	    char ch;
654 
655 	    if(inc_text_getc){
656 		while((*inc_text_getc)(&ch))
657 		  if(!so_writec(ch, (STORE_S *)body->contents.text.data)){
658 		      break;
659 		  }
660 	    }
661 	}
662 	else{
663 	    q_status_message(SM_ORDER | SM_DING, 3, 4,
664 			     _("Problem creating space for message text."));
665 	    return;
666 	}
667 
668 	if(role && role->template){
669 	    char *filtered;
670 
671 	    impl = 1;	/* leave cursor in header if not explicit */
672 	    filtered = detoken(role, NULL, 0, 0, 0, &redraft_pos, &impl);
673 	    if(filtered){
674 		if(*filtered){
675 		    so_puts((STORE_S *)body->contents.text.data, filtered);
676 		    if(impl == 1)
677 		      template_len = strlen(filtered);
678 		}
679 
680 		fs_give((void **)&filtered);
681 	    }
682 	}
683 	else
684 	  impl = 1;
685 
686 	if((sig = detoken(role, NULL, 2, 0, 1, &redraft_pos, &impl)) != NULL){
687 	    if(impl == 2)
688 	      redraft_pos->offset += template_len;
689 
690 	    if(*sig)
691 	      so_puts((STORE_S *)body->contents.text.data, sig);
692 
693 	    fs_give((void **)&sig);
694 	}
695 
696 	body->type = TYPETEXT;
697 
698 	if(attach)
699 	  create_message_body(&body, attach, 0);
700     }
701 
702     ps_global->prev_screen = compose_screen;
703     if(!(fcc_to_free = fcc) && !(role && role->fcc))
704       fcc = fcc_arg;			/* Didn't pick up fcc, use given  */
705 
706     /*
707      * check whether a build_address-produced fcc is different from
708      * fcc.  If same, do nothing, if different, set sticky bit in pine_send.
709      */
710     if(fcc){
711 	char *tmp_fcc = NULL;
712 
713 	if(outgoing->to){
714   	    tmp_fcc = get_fcc_based_on_to(outgoing->to);
715   	    if(strcmp(fcc, tmp_fcc ? tmp_fcc : ""))
716   	      fcc_is_sticky++;  /* cause sticky bit to get set */
717 
718 	}
719 	else if((tmp_fcc = get_fcc(NULL)) != NULL &&
720 	        !strcmp(fcc, tmp_fcc)){
721 	    /* not sticky */
722   	}
723   	else
724   	  fcc_is_sticky++;
725 
726 	if(tmp_fcc)
727 	  fs_give((void **)&tmp_fcc);
728     }
729 
730     pine_send(outgoing, &body, COMPOSE_MAIL_TITLE, role, fcc,
731 	      reply, redraft_pos, lcc, custom,
732 	      (fcc_is_sticky ? PS_STICKY_FCC : 0) | (to_is_sticky ? PS_STICKY_TO : 0));
733 
734     if(reply){
735 	if(reply->mailbox)
736 	  fs_give((void **) &reply->mailbox);
737 	if(reply->origmbox)
738 	  fs_give((void **) &reply->origmbox);
739 	if(reply->prefix)
740 	  fs_give((void **) &reply->prefix);
741 	if(reply->data.uid.msgs)
742 	  fs_give((void **) &reply->data.uid.msgs);
743   	fs_give((void **) &reply);
744     }
745 
746     if(fcc_to_free)
747       fs_give((void **)&fcc_to_free);
748 
749     if(lcc)
750       fs_give((void **)&lcc);
751 
752     mail_free_envelope(&outgoing);
753     pine_free_body(&body);
754     free_redraft_pos(&redraft_pos);
755     free_action(&role);
756 }
757 
758 
759 /*----------------------------------------------------------------------
760  Args:	stream -- This is where we get the postponed messages from
761 		  We'll expunge and close it here unless it is mail_stream.
762 
763     These are all return values:
764     ================
765 	outgoing --
766 	body --
767 	fcc --
768 	lcc --
769 	reply --
770 	redraft_pos --
771 	custom --
772 	role --
773     ================
774 
775 	flags --
776 
777  ----*/
778 int
redraft(MAILSTREAM ** streamp,ENVELOPE ** outgoing,struct mail_bodystruct ** body,char ** fcc,char ** lcc,REPLY_S ** reply,REDRAFT_POS_S ** redraft_pos,PINEFIELD ** custom,ACTION_S ** role,int flags)779 redraft(MAILSTREAM **streamp, ENVELOPE **outgoing, struct mail_bodystruct **body,
780 	char **fcc, char **lcc, REPLY_S **reply, REDRAFT_POS_S **redraft_pos,
781 	PINEFIELD **custom, ACTION_S **role, int flags)
782 {
783     MAILSTREAM *stream;
784     long	cont_msg = 1L;
785     STORE_S    *so;
786 
787     if(!(streamp && *streamp))
788       return(0);
789 
790     stream = *streamp;
791 
792     /*
793      * If we're manipulating the current folder, don't bother
794      * with index
795      */
796     if(!stream->nmsgs){
797 	if(REDRAFT_PPND&flags)
798 	  q_status_message(SM_ORDER | SM_DING, 3, 5, _("Empty folder! No messages really postponed!"));
799 	else
800 	  q_status_message(SM_ORDER | SM_DING, 3, 5, _("Empty folder! No messages really interrupted!"));
801 
802 	return(redraft_cleanup(streamp, FALSE, flags));
803     }
804     else if(stream == ps_global->mail_stream
805 	    && ps_global->prev_screen == mail_index_screen){
806 	/*
807 	 * Since the user's got this folder already opened and they're
808 	 * on a selected message, pick that one rather than rebuild
809 	 * another index screen...
810 	 */
811 	cont_msg = mn_m2raw(ps_global->msgmap, mn_get_cur(ps_global->msgmap));
812     }
813     else if(stream->nmsgs > 1L){		/* offer browser ? */
814 	int rv;
815 
816 	if(REDRAFT_PPND&flags){			/* set to last message postponed */
817 	    mn_set_cur(sp_msgmap(stream),
818 		       mn_get_revsort(sp_msgmap(stream))
819 			   ? 1L : mn_get_total(sp_msgmap(stream)));
820 	}
821 	else{					/* set to top form letter */
822 	    mn_set_cur(sp_msgmap(stream), 1L);
823 	}
824 
825 	clear_index_cache(stream, 0);
826 	while(1){
827 	    void *ti;
828 
829 	    ti = stop_threading_temporarily();
830 	    rv = index_lister(ps_global, NULL, stream->mailbox,
831 			      stream, sp_msgmap(stream));
832 	    restore_threading(&ti);
833 
834 	    cont_msg = mn_m2raw(sp_msgmap(stream), mn_get_cur(sp_msgmap(stream)));
835 	    if(count_flagged(stream, F_DEL)
836 	       && want_to(INTR_DEL_PMT, 'n', 0, NO_HELP, WT_NORM) == 'n'){
837 		if(REDRAFT_PPND&flags)
838 		  q_status_message(SM_ORDER, 3, 3, _("Undelete messages to remain postponed, and then continue message"));
839 		else
840 		  q_status_message(SM_ORDER, 3, 3, _("Undelete form letters you want to keep, and then continue message"));
841 
842 		continue;
843 	    }
844 
845 	    break;
846 	}
847 
848 	clear_index_cache(stream, 0);
849 
850 	if(rv){
851 	    q_status_message(SM_ORDER, 0, 3, _("Composition cancelled"));
852 	    (void) redraft_cleanup(streamp, FALSE, flags);
853 
854 	    if(!*streamp && !ps_global->mail_stream){
855 		q_status_message2(SM_ORDER, 3, 7,
856 			     "No more %.200s, returning to \"%.200s\"",
857 			     (REDRAFT_PPND&flags) ? "postponed messages"
858 						  : "form letters",
859 			     ps_global->inbox_name);
860 		if(ps_global && ps_global->ttyo){
861 		    blank_keymenu(ps_global->ttyo->screen_rows - 2, 0);
862 		    ps_global->mangled_footer = 1;
863 		}
864 
865 		do_broach_folder(ps_global->inbox_name,
866 				 ps_global->context_list, NULL, DB_INBOXWOCNTXT);
867 
868 		ps_global->next_screen = mail_index_screen;
869 	    }
870 
871 	    return(0);				/* special case */
872 	}
873     }
874 
875     if((so = (void *) so_get(PicoText, NULL, EDIT_ACCESS)) != NULL)
876       return(redraft_work(streamp, cont_msg, outgoing, body,
877 			  fcc, lcc, reply, redraft_pos, custom,
878 			  role, flags, so));
879     else
880       return(0);
881 }
882 
883 
884 int
redraft_prompt(char * type,char * prompt,int failure)885 redraft_prompt(char *type, char *prompt, int failure)
886 {
887     if(background_posting(FALSE)){
888 	q_status_message1(SM_ORDER, 0, 3,
889 			  _("%s folder unavailable while background posting"),
890 			  type);
891 	return(failure);
892     }
893 
894     return(want_to(prompt, 'y', 'x', NO_HELP, WT_NORM));
895 }
896 
897 
898 /* this is for initializing the fixed header elements in pine_send() */
899 /*
900 prompt::name::help::prwid::maxlen::realaddr::
901 builder::affected_entry::next_affected::selector::key_label::fileedit::
902 display_it::break_on_comma::is_attach::rich_header::only_file_chars::
903 single_space::sticky::dirty::start_here::blank::sticky_special::KS_ODATAVAR
904 */
905 static struct headerentry he_template[]={
906   {"",            "X-Auth-Received",  NO_HELP,          10, 0, NULL,
907    NULL,          NULL, NULL, NULL,                 NULL, NULL, NULL,
908    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KS_NONE},
909   {"From    : ",  "From",        h_composer_from,       10, 0, NULL,
910    build_address, NULL, NULL, addr_book_compose,    "To AddrBk", NULL, abook_nickname_complete,
911    0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, KS_TOADDRBOOK},
912   {"Reply-To: ",  "Reply To",    h_composer_reply_to,   10, 0, NULL,
913    build_address, NULL, NULL, addr_book_compose,    "To AddrBk", NULL, abook_nickname_complete,
914    0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, KS_TOADDRBOOK},
915   {"To      : ",  "To",          h_composer_to,         10, 0, NULL,
916    build_address, NULL, NULL, addr_book_compose,    "To AddrBk", NULL, abook_nickname_complete,
917    0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, KS_TOADDRBOOK},
918   {"Cc      : ",  "Cc",          h_composer_cc,         10, 0, NULL,
919    build_address, NULL, NULL, addr_book_compose,    "To AddrBk", NULL, abook_nickname_complete,
920    0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, KS_TOADDRBOOK},
921   {"Bcc     : ",  "Bcc",         h_composer_bcc,        10, 0, NULL,
922    build_address, NULL, NULL, addr_book_compose,    "To AddrBk", NULL, abook_nickname_complete,
923    0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, KS_TOADDRBOOK},
924   {"Newsgrps: ",  "Newsgroups",  h_composer_news,        10, 0, NULL,
925    news_build,    NULL, NULL, news_group_selector,  "To NwsGrps", NULL, NULL,
926    0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, KS_NONE},
927   {"Fcc     : ",  "Fcc",         h_composer_fcc,        10, 0, NULL,
928    NULL,          NULL, NULL, folders_for_fcc,      "To Fldrs", NULL, fcc_tab_complete,
929    0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, KS_NONE},
930   {"Lcc     : ",  "Lcc",         h_composer_lcc,        10, 0, NULL,
931    build_addr_lcc, NULL, NULL, addr_book_compose_lcc,"To AddrBk", NULL, abook_nickname_complete,
932    0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, KS_NONE},
933   {"Attchmnt: ",  "Attchmnt",    h_composer_attachment, 10, 0, NULL,
934    NULL,          NULL, NULL, NULL,                 "To Files", NULL, NULL,
935    0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, KS_NONE},
936   {"Subject : ",  "Subject",     h_composer_subject,    10, 0, NULL,
937    valid_subject, NULL, NULL, NULL,                 NULL, NULL, NULL,
938    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KS_NONE},
939   {"",            "References",  NO_HELP,               10, 0, NULL,
940    NULL,          NULL, NULL, NULL,                 NULL, NULL, NULL,
941    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KS_NONE},
942   {"",            "Date",        NO_HELP,               10, 0, NULL,
943    NULL,          NULL, NULL, NULL,                 NULL, NULL, NULL,
944    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KS_NONE},
945   {"",            "In-Reply-To", NO_HELP,               10, 0, NULL,
946    NULL,          NULL, NULL, NULL,                 NULL, NULL, NULL,
947    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KS_NONE},
948   {"",            "Message-ID",  NO_HELP,               10, 0, NULL,
949    NULL,          NULL, NULL, NULL,                 NULL, NULL, NULL,
950    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KS_NONE},
951   {"",            "X-Priority",  NO_HELP,               10, 0, NULL,
952    NULL,          NULL, NULL, NULL,                 NULL, NULL, NULL,
953    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KS_NONE},
954   {"",            "User-Agent",  NO_HELP,               10, 0, NULL,
955    NULL,          NULL, NULL, NULL,                 NULL, NULL, NULL,
956    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KS_NONE},
957   {"",            "To",          NO_HELP,               10, 0, NULL,
958    NULL,          NULL, NULL, NULL,                 NULL, NULL, NULL,
959    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KS_NONE},
960   {"",            "X-Post-Error",NO_HELP,               10, 0, NULL,
961    NULL,          NULL, NULL, NULL,                 NULL, NULL, NULL,
962    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KS_NONE},
963   {"",            "X-Reply-UID", NO_HELP,               10, 0, NULL,
964    NULL,          NULL, NULL, NULL,                 NULL, NULL, NULL,
965    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KS_NONE},
966   {"",            "X-Reply-Mbox", NO_HELP,              10, 0, NULL,
967    NULL,          NULL, NULL, NULL,                 NULL, NULL, NULL,
968    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KS_NONE},
969   {"",            "X-SMTP-Server", NO_HELP,             10, 0, NULL,
970    NULL,          NULL, NULL, NULL,                 NULL, NULL, NULL,
971    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KS_NONE},
972   {"",            "X-Cursor-Pos", NO_HELP,              10, 0, NULL,
973    NULL,          NULL, NULL, NULL,                 NULL, NULL, NULL,
974    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KS_NONE},
975   {"",            "X-Our-ReplyTo", NO_HELP,             10, 0, NULL,
976    NULL,          NULL, NULL, NULL,                 NULL, NULL, NULL,
977    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KS_NONE},
978   {"",            OUR_HDRS_LIST, NO_HELP,               10, 0, NULL,
979    NULL,          NULL, NULL, NULL,                 NULL, NULL, NULL,
980    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KS_NONE},
981   {"",            "X-Auth-Received", NO_HELP,           10, 0, NULL,
982    NULL,          NULL, NULL, NULL,                 NULL, NULL, NULL,
983    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KS_NONE},
984 #if	!(defined(DOS) || defined(OS2)) || defined(NOAUTH)
985   {"",            "Sender",      NO_HELP,               10, 0, NULL,
986    NULL,          NULL, NULL, NULL,                 NULL, NULL, NULL,
987    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KS_NONE}
988 #endif
989 };
990 
991 
992 static struct headerentry he_custom_addr_templ={
993    NULL,          NULL,          h_composer_custom_addr,10, 0, NULL,
994    build_address, NULL, NULL, addr_book_compose,    "To AddrBk", NULL, abook_nickname_complete,
995    0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, KS_TOADDRBOOK};
996 
997 static struct headerentry he_custom_free_templ={
998    NULL,          NULL,          h_composer_custom_free,10, 0, NULL,
999    NULL,          NULL, NULL, NULL,                 NULL, NULL, NULL,
1000    0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, KS_NONE};
1001 
1002 
1003 /*----------------------------------------------------------------------
1004      Get addressee for message, then post message
1005 
1006   Args:  outgoing -- Partially formatted outgoing ENVELOPE
1007          body     -- Body of outgoing message
1008         prmpt_who -- Optional prompt for optionally_enter call
1009         prmpt_cnf -- Optional prompt for confirmation call
1010     used_tobufval -- The string that the to was eventually set equal to.
1011 		      This gets passed back if non-NULL on entry.
1012         flagsarg  --     SS_PROMPTFORTO - Allow user to change recipient
1013                          SS_NULLRP - Use null return-path so we'll send an
1014 			             SMTP MAIL FROM: <>
1015 
1016   Result: message "To: " field is provided and message is sent or cancelled.
1017 
1018   Fields:
1019      remail                -
1020      return_path           -
1021      date                 added here
1022      from                 added here
1023      sender                -
1024      reply_to              -
1025      subject              passed in, NOT edited but maybe canonized here
1026      to                   possibly passed in, edited and canonized here
1027      cc                    -
1028      bcc                   -
1029      in_reply_to           -
1030      message_id            -
1031 
1032 Can only deal with message bodies that are either TYPETEXT or TYPEMULTIPART
1033 with the first part TYPETEXT! All newlines in the text here also end with
1034 CRLF.
1035 
1036 Returns 0 on success, -1 on failure.
1037   ----*/
1038 int
pine_simple_send(ENVELOPE * outgoing,struct mail_bodystruct ** body,ACTION_S ** rolep,char * prmpt_who,char * prmpt_cnf,char ** used_tobufval,int flagsarg)1039 pine_simple_send(ENVELOPE *outgoing,	/* envelope for outgoing message */
1040 		 struct mail_bodystruct **body,
1041 		 ACTION_S **rolep,
1042 		 char *prmpt_who,
1043 		 char *prmpt_cnf,
1044 		 char **used_tobufval,
1045 		 int flagsarg)
1046 {
1047     char     **tobufp, *p, tmp[MAILTMPLEN];
1048     void      *messagebuf;
1049     int        done = 0, retval = 0, x;
1050     int	       lastrc, rc = 0, ku, i, resize_len, result, fcc_result = 0;
1051     int        og2s_done = 0;
1052     HelpType   help;
1053     static HISTORY_S *history = NULL;
1054     ESCKEY_S   ekey[6];
1055     BUILDER_ARG ba_fcc;
1056     METAENV   *header;
1057     ACTION_S  *role = rolep ? *rolep : NULL;
1058     PAT_STATE  pstate;
1059 
1060     dprint((1,"\n === simple send called === \n"));
1061 
1062     memset(&ba_fcc, 0, sizeof(BUILDER_ARG));
1063 
1064     init_hist(&history, HISTSIZE);
1065 
1066     header = pine_simple_send_header(outgoing, &ba_fcc.tptr, &tobufp);
1067 
1068     /*----- Fill in a few general parts of the envelope ----*/
1069     if(!outgoing->date){
1070 	if(F_ON(F_QUELL_TIMEZONE, ps_global))
1071 	  mail_parameters(NULL, SET_DISABLE822TZTEXT, (void *) TRUE);
1072 
1073 	rfc822_date(tmp_20k_buf);		/* format and copy new date */
1074 	if(F_ON(F_QUELL_TIMEZONE, ps_global))
1075 	  mail_parameters(NULL, SET_DISABLE822TZTEXT, (void *) FALSE);
1076 
1077 	outgoing->date = (unsigned char *) cpystr(tmp_20k_buf);
1078     }
1079 
1080     if(!outgoing->from){
1081 	if(role && role->from){
1082 	    if(ps_global->never_allow_changing_from)
1083 	      q_status_message(SM_ORDER, 3, 3, _("Site policy doesn't allow changing From address so role's From has no effect"));
1084 	    else
1085 	      outgoing->from = copyaddrlist(role->from);
1086 	}
1087 	else
1088 	  outgoing->from = generate_from();
1089     }
1090 
1091     if(!(flagsarg & SS_NULLRP))
1092       outgoing->return_path = rfc822_cpy_adr(outgoing->from);
1093 
1094     ekey[i = 0].ch    = ctrl('T');
1095     ekey[i].rval  = 2;
1096     ekey[i].name  = "^T";
1097     ekey[i++].label = N_("To AddrBk");
1098 
1099     if(F_ON(F_ENABLE_TAB_COMPLETE,ps_global)){
1100 	ekey[i].ch      =  ctrl('I');
1101 	ekey[i].rval    = 11;
1102 	ekey[i].name    = "TAB";
1103 	ekey[i++].label = N_("Complete");
1104     }
1105 
1106     if(nonempty_patterns(ROLE_DO_ROLES, &pstate) && first_pattern(&pstate)){
1107 	ekey[i].ch      = ctrl('R');
1108 	ekey[i].rval    = 15;
1109 	ekey[i].name    = "^R";
1110 	ekey[i++].label = "Set Role";
1111     }
1112 
1113     ekey[i].ch      = KEY_UP;
1114     ekey[i].rval    = 30;
1115     ekey[i].name    = "";
1116     ku = i;
1117     ekey[i++].label = "";
1118 
1119     ekey[i].ch      = KEY_DOWN;
1120     ekey[i].rval    = 31;
1121     ekey[i].name    = "";
1122     ekey[i++].label = "";
1123 
1124     ekey[i].ch    = -1;
1125 
1126     if(outgoing->remail == NULL)
1127 	strcpy(tmp, _("FORWARD (as e-mail) to : "));
1128 
1129     /*----------------------------------------------------------------------
1130        Loop editing the "To: " field until everything goes well
1131      ----*/
1132     help = NO_HELP;
1133 
1134     while(!done){
1135 	int flags;
1136 
1137 	if(outgoing->message_id)
1138 	  fs_give((void **) &outgoing->message_id);
1139 
1140 	outgoing->message_id = generate_message_id(role);
1141 
1142 	if(outgoing->remail){
1143 	   if(role)
1144 	     snprintf(tmp, sizeof(tmp),  _("BOUNCE (redirect) message using role \"%s\" to : "), role->nick);
1145 	   else
1146 	     strncpy(tmp, _("BOUNCE (redirect) message to : "), sizeof(tmp));
1147 	   tmp[sizeof(tmp)-1] = '\0';
1148 	}
1149 
1150 	if(!og2s_done){
1151 	    og2s_done++;
1152 	    outgoing2strings(header, *body, &messagebuf, NULL, 1);
1153 	}
1154 
1155 	lastrc = rc;
1156 	if(flagsarg & SS_PROMPTFORTO){
1157 	    if(!*tobufp)
1158 	      *tobufp = cpystr("");
1159 
1160 	    resize_len = MAX(MAXPATH, strlen(*tobufp));
1161 	    fs_resize((void **) tobufp, resize_len+1);
1162 
1163 	    if(items_in_hist(history) > 0){
1164 		ekey[ku].name  = HISTORY_UP_KEYNAME;
1165 		ekey[ku].label = HISTORY_KEYLABEL;
1166 		ekey[ku+1].name  = HISTORY_DOWN_KEYNAME;
1167 		ekey[ku+1].label = HISTORY_KEYLABEL;
1168 	    }
1169 	    else{
1170 		ekey[ku].name  = "";
1171 		ekey[ku].label = "";
1172 		ekey[ku+1].name  = "";
1173 		ekey[ku+1].label = "";
1174 	    }
1175 
1176 	    flags = OE_APPEND_CURRENT;
1177 
1178 	    rc = optionally_enter(*tobufp, -FOOTER_ROWS(ps_global),
1179 				 0, resize_len,
1180 				 prmpt_who
1181 				   ? prmpt_who
1182 				   : tmp,
1183 				 ekey, help, &flags);
1184 	}
1185 	else
1186 	  rc = 0;
1187 
1188 	switch(rc){
1189 	  case -1:
1190 	    q_status_message(SM_ORDER | SM_DING, 3, 4,
1191 			     "Internal problem encountered");
1192 	    retval = -1;
1193 	    done++;
1194 	    break;
1195 
1196 	  case 15 : /* set a role */
1197 	   {void    (*prev_screen)(struct pine *) = NULL, (*redraw)(void) = NULL;
1198 
1199 	    redraw = ps_global->redrawer;
1200 	    ps_global->redrawer = NULL;
1201 	    prev_screen = ps_global->prev_screen;
1202 	    role = NULL;
1203 	    ps_global->next_screen = SCREEN_FUN_NULL;
1204 
1205 	    if(role_select_screen(ps_global, &role,
1206 		outgoing->remail ? MC_BOUNCE : MC_FORWARD) < 0)
1207 	        cmd_cancelled(_("Set Role"));
1208 	    else{
1209 	       if(role)
1210 		  role = combine_inherited_role(role);
1211 	       else{
1212 		  role = (ACTION_S *) fs_get(sizeof(*role));
1213 		  memset((void *) role, 0, sizeof(*role));
1214 		  role->nick = cpystr("Default Role");
1215 	       }
1216 	    }
1217 
1218 	    if(redraw)
1219 	       (*redraw)();
1220 
1221 	    ps_global->next_screen = prev_screen;
1222 	    ps_global->redrawer = redraw;
1223 	    ps_global->mangled_screen = 1;
1224 
1225 	    if(role && role->from && !ps_global->never_allow_changing_from){
1226 		mail_free_address (&outgoing->from);
1227 	        outgoing->from = copyaddrlist(role->from);
1228 		if(!(flagsarg & SS_NULLRP)){
1229 		   fs_give((void **) &outgoing->return_path);
1230 		   outgoing->return_path = rfc822_cpy_adr(outgoing->from);
1231 		}
1232 	    }
1233 	    if(rolep) *rolep = role;
1234 	   }
1235 	   break;
1236 
1237 	  case 30 :
1238 	    if((p = get_prev_hist(history, *tobufp, 0, NULL)) != NULL){
1239 		strncpy(*tobufp, p, resize_len);
1240 		(*tobufp)[resize_len-1] = '\0';
1241 	    }
1242 	    else
1243 	      Writechar(BELL, 0);
1244 
1245 	    break;
1246 
1247 	  case 31 :
1248 	    if((p = get_next_hist(history, *tobufp, 0, NULL)) != NULL){
1249 		strncpy(*tobufp, p, resize_len);
1250 		(*tobufp)[resize_len-1] = '\0';
1251 	    }
1252 	    else
1253 	      Writechar(BELL, 0);
1254 
1255 	    break;
1256 
1257 	  case 2: /* ^T */
1258 	  case 0:
1259 	   {void (*redraw) (void) = ps_global->redrawer;
1260 	    char  *returned_addr = NULL;
1261 	    int    len, l;
1262 
1263 	    if(rc == 2){
1264 		int got_something = 0;
1265 
1266 		push_titlebar_state();
1267 		returned_addr = addr_book_bounce();
1268 
1269 		/*
1270 		 * Just make it look like user typed this list in.
1271 		 */
1272 		if(returned_addr){
1273 		    got_something++;
1274 		    if((l=resize_len) < (len = strlen(returned_addr)) + 1){
1275 			l = len;
1276 			fs_resize((void **) tobufp, (size_t) (l+1));
1277 		    }
1278 
1279 		    strncpy(*tobufp, returned_addr, l);
1280 		    (*tobufp)[l] = '\0';
1281 		    fs_give((void **)&returned_addr);
1282 		}
1283 
1284 		ClearScreen();
1285 		pop_titlebar_state();
1286 		redraw_titlebar();
1287 		if((ps_global->redrawer = redraw) != NULL) /* reset old value, and test */
1288 		  (*ps_global->redrawer)();
1289 
1290 		if(!got_something)
1291 		  continue;
1292 	    }
1293 
1294 	    if(*tobufp && **tobufp != '\0'){
1295 		char *errbuf, *addr;
1296 		int   tolen;
1297 
1298 		save_hist(history, *tobufp, 0, NULL);
1299 
1300 		errbuf = NULL;
1301 
1302 		/*
1303 		 * If role has an fcc, use it instead of what build_address
1304 		 * tells us.
1305 		 */
1306 		if(role && role->fcc){
1307 		    if(ba_fcc.tptr)
1308 		      fs_give((void **) &ba_fcc.tptr);
1309 
1310 		    ba_fcc.tptr = cpystr(role->fcc);
1311 		}
1312 
1313 		if(build_address(*tobufp, &addr, &errbuf,
1314 		    (role && role->fcc) ? NULL : &ba_fcc, NULL) >= 0){
1315 		    int sendit = 0;
1316 
1317 		    if(errbuf)
1318 		      fs_give((void **)&errbuf);
1319 
1320 		    if((l=strlen(*tobufp)) < (tolen = strlen(addr)) + 1){
1321 			l = tolen;
1322 			fs_resize((void **) tobufp, (size_t) (l+1));
1323 		    }
1324 
1325 		    strncpy(*tobufp, addr, l);
1326 		    (*tobufp)[l] = '\0';
1327 		    if(used_tobufval)
1328 		      *used_tobufval = cpystr(addr);
1329 
1330 		    /* confirm address */
1331 		    if(flagsarg & SS_PROMPTFORTO){
1332 			char dsn_string[30];
1333 			int  dsn_label = 0, dsn_show, i;
1334 			int  verbose_label = 0;
1335 			ESCKEY_S opts[13];
1336 
1337 			strings2outgoing(header, body, NULL, 0);
1338 
1339 			if((flagsarg & SS_PROMPTFORTO)
1340 			   && ((x = check_addresses(header)) == CA_BAD
1341 			       || (x == CA_EMPTY && F_OFF(F_FCC_ON_BOUNCE,
1342 							  ps_global))))
1343 			  /*--- Addresses didn't check out---*/
1344 			  continue;
1345 
1346 			i = 0;
1347 			opts[i].ch      = 'y';
1348 			opts[i].rval    = 'y';
1349 			opts[i].name    = "Y";
1350 			opts[i++].label = N_("Yes");
1351 
1352 			opts[i].ch      = 'n';
1353 			opts[i].rval    = 'n';
1354 			opts[i].name    = "N";
1355 			opts[i++].label = N_("No");
1356 
1357 			call_mailer_flags &= ~CM_VERBOSE;	/* clear verbose */
1358 			if(F_ON(F_VERBOSE_POST, ps_global)){
1359 			    /* setup keymenu slot to toggle verbose mode */
1360 			    opts[i].ch    = ctrl('W');
1361 			    opts[i].rval  = 12;
1362 			    opts[i].name  = "^W";
1363 			    verbose_label = i++;
1364 			    if(F_ON(F_DSN, ps_global)){
1365 				opts[i].ch      = 0;
1366 				opts[i].rval    = 0;
1367 				opts[i].name    = "";
1368 				opts[i++].label = "";
1369 			    }
1370 			}
1371 
1372 			/* clear DSN flags */
1373 			call_mailer_flags &= ~(CM_DSN_NEVER | CM_DSN_DELAY | CM_DSN_SUCCESS | CM_DSN_FULL);
1374 			if(F_ON(F_DSN, ps_global)){
1375 			    /* setup keymenu slots to toggle dsn bits */
1376 			    opts[i].ch      = 'd';
1377 			    opts[i].rval    = 'd';
1378 			    opts[i].name    = "D";
1379 			    opts[i].label   = "DSNOpts";
1380 			    dsn_label       = i++;
1381 			    opts[i].ch      = -2;
1382 			    opts[i].rval    = 's';
1383 			    opts[i].name    = "S";
1384 			    opts[i++].label = "";
1385 			    opts[i].ch      = -2;
1386 			    opts[i].rval    = 'x';
1387 			    opts[i].name    = "X";
1388 			    opts[i++].label = "";
1389 			    opts[i].ch      = -2;
1390 			    opts[i].rval    = 'h';
1391 			    opts[i].name    = "H";
1392 			    opts[i++].label = "";
1393 			}
1394 
1395 			opts[i].ch = -1;
1396 
1397 			while(1){
1398 			    int rv;
1399 
1400 			    dsn_show = (call_mailer_flags & CM_DSN_SHOW);
1401 			    snprintf(tmp_20k_buf, SIZEOF_20KBUF,
1402 				    "%s%s%s%s%s%sto \"%s\" ? ",
1403 				    prmpt_cnf ? prmpt_cnf : "Send message ",
1404 				    ((call_mailer_flags & CM_VERBOSE)
1405 				      || (dsn_show))
1406 				      ? "(" : "",
1407 				    (call_mailer_flags & CM_VERBOSE)
1408 				      ? "in verbose mode" : "",
1409 				    (dsn_show && (call_mailer_flags & CM_VERBOSE))
1410 				      ? ", " : "",
1411 				    (dsn_show) ? dsn_string : "",
1412 				    ((call_mailer_flags & CM_VERBOSE) || dsn_show)
1413 				      ? ") " : "",
1414 				    (addr && *addr)
1415 					? addr
1416 					: (F_ON(F_FCC_ON_BOUNCE, ps_global)
1417 					   && ba_fcc.tptr && ba_fcc.tptr[0])
1418 					    ? ba_fcc.tptr
1419 					    : "");
1420 			    tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
1421 
1422 			    if((strlen(tmp_20k_buf) >
1423 					ps_global->ttyo->screen_cols - 2) &&
1424 			       ps_global->ttyo->screen_cols >= 7)
1425 			      strncpy(tmp_20k_buf+ps_global->ttyo->screen_cols-7,
1426 				     "...? ", SIZEOF_20KBUF-ps_global->ttyo->screen_cols-7);
1427 
1428 			    tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
1429 
1430 			    if(verbose_label)
1431 			      opts[verbose_label].label =
1432 				      /* TRANSLATORS: several possible key labels follow */
1433 				      (call_mailer_flags & CM_VERBOSE) ? N_("Normal") : N_("Verbose");
1434 
1435 			    if(F_ON(F_DSN, ps_global)){
1436 				if(call_mailer_flags & CM_DSN_SHOW){
1437 				    opts[dsn_label].label   =
1438 						(call_mailer_flags & CM_DSN_DELAY)
1439 						   ? N_("NoDelay") : N_("Delay");
1440 				    opts[dsn_label+1].ch    = 's';
1441 				    opts[dsn_label+1].label =
1442 						(call_mailer_flags & CM_DSN_SUCCESS)
1443 						   ? N_("NoSuccess") : N_("Success");
1444 				    opts[dsn_label+2].ch    = 'x';
1445 				    opts[dsn_label+2].label =
1446 						(call_mailer_flags & CM_DSN_NEVER)
1447 						   ? N_("ErrRets") : N_("NoErrRets");
1448 				    opts[dsn_label+3].ch    = 'h';
1449 				    opts[dsn_label+3].label =
1450 						(call_mailer_flags & CM_DSN_FULL)
1451 						   ? N_("RetHdrs") : N_("RetFull");
1452 				}
1453 			    }
1454 
1455 			    rv = radio_buttons(tmp_20k_buf,
1456 					       -FOOTER_ROWS(ps_global), opts,
1457 					       'y', 'z', NO_HELP, RB_NORM);
1458 			    if(rv == 'y'){		/* user ACCEPTS! */
1459 				sendit = 1;
1460 				break;
1461 			    }
1462 			    else if(rv == 'n'){		/* Declined! */
1463 				break;
1464 			    }
1465 			    else if(rv == 'z'){		/* Cancelled! */
1466 				break;
1467 			    }
1468 			    else if(rv == 12){		/* flip verbose bit */
1469 				if(call_mailer_flags & CM_VERBOSE)
1470 				  call_mailer_flags &= ~CM_VERBOSE;
1471 				else
1472 				  call_mailer_flags |= CM_VERBOSE;
1473 			    }
1474 			    else if(call_mailer_flags & CM_DSN_SHOW){
1475 				if(rv == 's'){		/* flip success bit */
1476 				    call_mailer_flags ^= CM_DSN_SUCCESS;
1477 				    /* turn off related bits */
1478 				    if(call_mailer_flags & CM_DSN_SUCCESS)
1479 				      call_mailer_flags &= ~(CM_DSN_NEVER);
1480 				}
1481 				else if(rv == 'd'){	/* flip delay bit */
1482 				    call_mailer_flags ^= CM_DSN_DELAY;
1483 				    /* turn off related bits */
1484 				    if(call_mailer_flags & CM_DSN_DELAY)
1485 				      call_mailer_flags &= ~(CM_DSN_NEVER);
1486 				}
1487 				else if(rv == 'x'){	/* flip never bit */
1488 				    call_mailer_flags ^= CM_DSN_NEVER;
1489 				    /* turn off related bits */
1490 				    if(call_mailer_flags & CM_DSN_NEVER)
1491 				      call_mailer_flags &= ~(CM_DSN_SUCCESS | CM_DSN_DELAY);
1492 				}
1493 				else if(rv == 'h'){	/* flip full bit */
1494 				    call_mailer_flags ^= CM_DSN_FULL;
1495 				}
1496 			    }
1497 			    else if(rv == 'd'){		/* show dsn options */
1498 				call_mailer_flags |= (CM_DSN_SHOW | CM_DSN_SUCCESS | CM_DSN_DELAY | CM_DSN_FULL);
1499 			    }
1500 
1501 			    snprintf(dsn_string, sizeof(dsn_string), _("DSN requested[%s%s%s%s]"),
1502 				    (call_mailer_flags & CM_DSN_NEVER)
1503 				      ? _("Never") : "F",
1504 				    (call_mailer_flags & CM_DSN_DELAY)
1505 				      ? "D" : "",
1506 				    (call_mailer_flags & CM_DSN_SUCCESS)
1507 				      ? "S" : "",
1508 				    (call_mailer_flags & CM_DSN_NEVER)
1509 				      ? ""
1510 				      : (call_mailer_flags & CM_DSN_FULL) ? "-Full"
1511 								   : "-Hdrs");
1512 			    dsn_string[sizeof(dsn_string)-1] = '\0';
1513 			}
1514 		    }
1515 
1516 		    if(addr)
1517 		      fs_give((void **)&addr);
1518 
1519 		    if(!(flagsarg & SS_PROMPTFORTO) || sendit){
1520 			char *fcc = NULL;
1521 			CONTEXT_S *fcc_cntxt = NULL;
1522 
1523 			if(F_ON(F_FCC_ON_BOUNCE, ps_global)){
1524 			    if(ba_fcc.tptr)
1525 			      fcc = cpystr(ba_fcc.tptr);
1526 
1527 			    set_last_fcc(fcc);
1528 
1529 			    /*
1530 			     * If special name "inbox" then replace it with the
1531 			     * real inbox path.
1532 			     */
1533 			    if(ps_global->VAR_INBOX_PATH
1534 			       && strucmp(fcc, ps_global->inbox_name) == 0){
1535 				char *replace_fcc;
1536 
1537 				replace_fcc = cpystr(ps_global->VAR_INBOX_PATH);
1538 				fs_give((void **) &fcc);
1539 				fcc = replace_fcc;
1540 			    }
1541 			}
1542 
1543 			/*---- Check out fcc -----*/
1544 			if(fcc && *fcc){
1545 			    (void) commence_fcc(fcc, &fcc_cntxt, FALSE);
1546 			    if(!lmc.so){
1547 				dprint((4,"can't open fcc, cont\n"));
1548 				if(!(flagsarg & SS_PROMPTFORTO)){
1549 				    retval = -1;
1550 				    fs_give((void **)&fcc);
1551 				    fcc = NULL;
1552 				    goto finish;
1553 				}
1554 				else
1555 				  continue;
1556 			    }
1557 			    else
1558 			      so_truncate(lmc.so, fcc_size_guess(*body) + 2048);
1559 			}
1560 			else
1561 			  lmc.so = NULL;
1562 
1563 			if(!(outgoing->to || outgoing->cc || outgoing->bcc
1564 			     || lmc.so)){
1565 			    q_status_message(SM_ORDER, 3, 5, _("No recipients specified!"));
1566 			    continue;
1567 			}
1568 
1569 			if(outgoing->to || outgoing->cc || outgoing->bcc){
1570 			    char **alt_smtp = NULL;
1571 
1572 			    if(role && role->smtp){
1573 				if(ps_global->FIX_SMTP_SERVER
1574 				   && ps_global->FIX_SMTP_SERVER[0])
1575 				  q_status_message(SM_ORDER | SM_DING, 5, 5, _("Use of a role-defined smtp-server is administratively prohibited"));
1576 				else
1577 				  alt_smtp = role->smtp;
1578 			    }
1579 
1580 			    result = call_mailer(header, *body, alt_smtp,
1581 						 call_mailer_flags,
1582 						 call_mailer_file_result,
1583 						 pipe_callback);
1584 			    mark_address_failure_for_pico(header);
1585 			}
1586 			else
1587 			  result = 0;
1588 
1589 			if(result == 1 && !lmc.so)
1590 			  q_status_message(SM_ORDER, 0, 3, _("Message sent"));
1591 
1592 			/*----- Was there an fcc involved? -----*/
1593 			if(lmc.so){
1594 			    if(result == 1
1595 			       || (result == 0
1596 			   && pine_rfc822_output(header, *body, NULL, NULL))){
1597 				char label[50];
1598 
1599 				strncpy(label, "Fcc", sizeof(label));
1600 				label[sizeof(label)-1] = '\0';
1601 				if(strcmp(fcc, ps_global->VAR_DEFAULT_FCC)){
1602 				    snprintf(label + 3, sizeof(label)-3, " to %s", fcc);
1603 				    label[sizeof(label)-1] = '\0';
1604 				}
1605 
1606 				/* Now actually copy to fcc folder and close */
1607 				fcc_result =
1608 				  write_fcc(fcc, fcc_cntxt, lmc.so, NULL,
1609 					    label,
1610 					    F_ON(F_MARK_FCC_SEEN, ps_global)
1611 						? "\\SEEN" : NULL);
1612 			    }
1613 			    else if(result == 0){
1614 				q_status_message(SM_ORDER,3,5,
1615 				    _("Fcc Failed!.  No message saved."));
1616 				retval = -1;
1617 				dprint((1, "explicit fcc write failed!\n"));
1618 			    }
1619 
1620 			    so_give(&lmc.so);
1621 			}
1622 
1623 			if(result < 0){
1624 			    dprint((1, "Bounce failed\n"));
1625 			    if(!(flagsarg & SS_PROMPTFORTO))
1626 			      retval = -1;
1627 			    else
1628 			      continue;
1629 			}
1630 			else if(result == 1){
1631 			  if(!fcc)
1632 			    q_status_message(SM_ORDER, 0, 3,
1633 					     _("Message sent"));
1634 			  else{
1635 			      int avail = ps_global->ttyo->screen_cols-2;
1636 			      int need, fcclen;
1637 			      char *part1 = "Message sent and ";
1638 			      char *part2 = fcc_result ? "" : "NOT ";
1639 			      char *part3 = "copied to ";
1640 			      fcclen = strlen(fcc);
1641 
1642 			      need = 2 + strlen(part1) + strlen(part2) +
1643 				     strlen(part3) + fcclen;
1644 
1645 			      if(need > avail && fcclen > 6)
1646 				fcclen -= MIN(fcclen-6, need-avail);
1647 
1648 			      q_status_message4(SM_ORDER, 0, 3,
1649 						"%s%s%s\"%s\"",
1650 						part1, part2, part3,
1651 						short_str(fcc,
1652 							  (char *)tmp_20k_buf,
1653 							  SIZEOF_20KBUF,
1654 							  fcclen, FrontDots));
1655 			  }
1656 			}
1657 
1658 			if(fcc)
1659 			  fs_give((void **)&fcc);
1660 		    }
1661 		    else{
1662 			q_status_message(SM_ORDER, 0, 3, _("Send cancelled"));
1663 			retval = -1;
1664 		    }
1665 		}
1666 		else{
1667 		    q_status_message1(SM_ORDER | SM_DING, 3, 5,
1668 				      _("Error in address: %s"), errbuf);
1669 		    if(errbuf)
1670 		      fs_give((void **)&errbuf);
1671 
1672 		    if(!(flagsarg & SS_PROMPTFORTO))
1673 		      retval = -1;
1674 		    else
1675 		      continue;
1676 		}
1677 
1678 	    }
1679 	    else{
1680 		q_status_message(SM_ORDER | SM_DING, 3, 5,
1681 				 _("No addressee!  No e-mail sent."));
1682 		retval = -1;
1683 	    }
1684 	   }
1685 
1686 	    done++;
1687 	    break;
1688 
1689 	  case 1:
1690 	    q_status_message(SM_ORDER, 0, 3, _("Send cancelled"));
1691 	    done++;
1692 	    retval = -1;
1693 	    break;
1694 
1695 	  case 3:
1696 	    help = (help == NO_HELP)
1697 			    ? (outgoing->remail == NULL
1698 				? h_anon_forward
1699 				: h_bounce)
1700 			    : NO_HELP;
1701 	    break;
1702 
1703 	  case 11:
1704 	    if(**tobufp){
1705 	      char *new_nickname = NULL;
1706 	      int l;
1707 	      int ambiguity;
1708 
1709 	      ambiguity = abook_nickname_complete(*tobufp, &new_nickname,
1710 			      (lastrc==rc && !(flags & OE_USER_MODIFIED)), ANC_AFTERCOMMA);
1711 	      if(new_nickname){
1712 		if(*new_nickname){
1713 		  if((l=strlen(new_nickname)) > resize_len){
1714 		    resize_len = l;
1715 		    fs_resize((void **) tobufp, resize_len+1);
1716 		  }
1717 
1718 		  strncpy(*tobufp, new_nickname, l);
1719 		  (*tobufp)[l] = '\0';
1720 	        }
1721 
1722 		fs_give((void **) &new_nickname);
1723 	      }
1724 
1725 	      if(ambiguity != 2)
1726 		Writechar(BELL, 0);
1727 	    }
1728 
1729 	    break;
1730 
1731 	  case 4:				/* can't suspend */
1732 	  default:
1733 	    break;
1734 	}
1735     }
1736 
1737 finish:
1738     if(ba_fcc.tptr)
1739       fs_give((void **)&ba_fcc.tptr);
1740 
1741     pine_free_env(&header);
1742 
1743     return(retval);
1744 }
1745 
1746 
1747 /*
1748  * pine_simple_send_header - generate header suitable for simple_sending
1749  */
1750 METAENV *
pine_simple_send_header(ENVELOPE * outgoing,char ** fccp,char *** tobufpp)1751 pine_simple_send_header(ENVELOPE *outgoing, char **fccp, char ***tobufpp)
1752 {
1753     METAENV   *header;
1754     PINEFIELD *pf;
1755     static struct headerentry he_dummy;
1756 
1757     header = pine_new_env(outgoing, fccp, tobufpp, NULL);
1758 
1759     /* assign he_dummy to "To:" field "he" for strings2outgoing */
1760     for(pf = header->local; pf && pf->name; pf = pf->next)
1761       if(pf->type == Address && !strucmp(pf->name, "to")){
1762 	  memset((void *) &he_dummy, 0, sizeof(he_dummy));
1763 	  pf->extdata   = (void *) &he_dummy;
1764 	  HE(pf)->dirty	= 1;
1765 	  break;
1766       }
1767 
1768     return(header);
1769 }
1770 
1771 
1772 
1773 /*----------------------------------------------------------------------
1774      Prepare data structures for pico, call pico, then post message
1775 
1776   Args:  outgoing     -- Partially formatted outgoing ENVELOPE
1777          body         -- Body of outgoing message
1778          editor_title -- Title for anchor line in composer
1779          fcc_arg      -- The file carbon copy field
1780 	 reply        -- Struct describing set of msgs being replied-to
1781 	 lcc_arg      --
1782 	 custom       -- custom header list.
1783 	 sticky_fcc   --
1784 
1785   Result: message is edited, then postponed, cancelled or sent.
1786 
1787   Fields:
1788      remail                -
1789      return_path           -
1790      date                 added here
1791      from                 added here
1792      sender                -
1793      reply_to              -
1794      subject              passed in, edited and cannonized here
1795      to                   possibly passed in, edited and cannonized here
1796      cc                   possibly passed in, edited and cannonized here
1797      bcc                  edited and cannonized here
1798      in_reply_to          generated in reply() and passed in
1799      message_id            -
1800 
1801  Storage for these fields comes from anywhere outside. It is remalloced
1802  here so the composer can realloc them if needed. The copies here are also
1803  freed here.
1804 
1805 Can only deal with message bodies that are either TYPETEXT or TYPEMULTIPART
1806 with the first part TYPETEXT! All newlines in the text here also end with
1807 CRLF.
1808 
1809 There's a further assumption that the text in the TYPETEXT part is
1810 stored in a storage object (see filter.c).
1811   ----*/
1812 void
pine_send(ENVELOPE * outgoing,struct mail_bodystruct ** body,char * editor_title,ACTION_S * role,char * fcc_arg,REPLY_S * reply,REDRAFT_POS_S * redraft_pos,char * lcc_arg,PINEFIELD * custom,int flags)1813 pine_send(ENVELOPE *outgoing, struct mail_bodystruct **body,
1814 	  char *editor_title, ACTION_S *role, char *fcc_arg,
1815 	  REPLY_S *reply, REDRAFT_POS_S *redraft_pos, char *lcc_arg,
1816 	  PINEFIELD *custom, int flags)
1817 {
1818     int			i, fixed_cnt, total_cnt, index,
1819 			editor_result = 0, body_start = 0, use_news_order = 0;
1820     char	       *p, *addr, *fcc, *fcc_to_free = NULL;
1821     char	       *start_here_name = NULL;
1822     char               *suggested_nntp_server = NULL;
1823     char	       *title = NULL;
1824     struct headerentry *he, *headents, *he_to = NULL, *he_fcc = NULL, *he_news = NULL, *he_lcc = NULL,
1825 		       *he_from = NULL;
1826     PINEFIELD          *pfields, *pf, *pf_nobody = NULL, *pf_to = NULL,
1827                        *pf_smtp_server = NULL, *pf_nntp_server = NULL,
1828 		       *pf_fcc = NULL, *pf_err = NULL, *pf_uid = NULL, *pf_mbox = NULL, *pf_curpos = NULL,
1829 		       *pf_ourrep = NULL, *pf_ourhdrs = NULL, **sending_order;
1830     METAENV             header;
1831     ADDRESS            *lcc_addr = NULL;
1832     ADDRESS            *nobody_addr = NULL;
1833     BODY_PARTICULARS_S *bp;
1834     STORE_S	       *orig_so = NULL;
1835     PICO	        pbuf1, *save_previous_pbuf;
1836     CustomType          ct;
1837     REDRAFT_POS_S      *local_redraft_pos = NULL;
1838 
1839     dprint((1,"\n=== send called ===\n"));
1840 
1841     save_previous_pbuf = pbf;
1842     pbf = &pbuf1;
1843     standard_picobuf_setup(pbf);
1844 
1845     /*
1846      * Cancel any pending initial commands since pico uses a different
1847      * input routine.  If we didn't cancel them, they would happen after
1848      * we returned from the editor, which would be confusing.
1849      */
1850     if(ps_global->in_init_seq){
1851 	ps_global->in_init_seq = 0;
1852 	ps_global->save_in_init_seq = 0;
1853 	clear_cursor_pos();
1854 	if(ps_global->initial_cmds){
1855 	    if(ps_global->free_initial_cmds)
1856 	      fs_give((void **)&(ps_global->free_initial_cmds));
1857 
1858 	    ps_global->initial_cmds = 0;
1859 	}
1860 
1861 	F_SET(F_USE_FK,ps_global,ps_global->orig_use_fkeys);
1862     }
1863 
1864 #if defined(DOS) || defined(OS2)
1865     if(!dos_valid_from()){
1866 	pbf = save_previous_pbuf;
1867 	return;
1868     }
1869 
1870     pbf->upload        = NULL;
1871 #else
1872     pbf->upload        = (ps_global->VAR_UPLOAD_CMD
1873 			  && ps_global->VAR_UPLOAD_CMD[0])
1874 			  ? upload_msg_to_pico : NULL;
1875 #endif
1876 
1877     pbf->msgntext      = message_format_for_pico;
1878     pbf->mimetype      = mime_type_for_pico;
1879     pbf->exittest      = send_exit_for_pico;
1880     pbf->user_says_noflow = dont_flow_this_time;
1881     pbf->newthread     = new_thread_on_blank_subject;
1882     ps_global->newthread = 0;	/* reset this value */
1883     if(F_OFF(F_CANCEL_CONFIRM, ps_global))
1884       pbf->canceltest    = cancel_for_pico;
1885 #ifdef _WINDOWS
1886     pbf->dict	       = (ps_global->VAR_DICTIONARY
1887 			    && ps_global->VAR_DICTIONARY[0]
1888 			    && ps_global->VAR_DICTIONARY[0][0])
1889 				? ps_global->VAR_DICTIONARY : NULL;
1890     pbf->chosen_dict  = -1;	/* not chosen yet */
1891 #endif /* _WINDOWS */
1892     pbf->alt_ed        = (ps_global->VAR_EDITOR && ps_global->VAR_EDITOR[0] &&
1893 			    ps_global->VAR_EDITOR[0][0])
1894 				? ps_global->VAR_EDITOR : NULL;
1895     pbf->alt_spell     = (ps_global->VAR_SPELLER && ps_global->VAR_SPELLER[0])
1896 				? ps_global->VAR_SPELLER : NULL;
1897     pbf->always_spell_check = F_ON(F_ALWAYS_SPELL_CHECK, ps_global);
1898     pbf->quote_str     = reply && reply->prefix ? reply->prefix : "> ";
1899     /* We actually want to set this only if message we're sending is flowed */
1900     pbf->strip_ws_before_send = F_ON(F_STRIP_WS_BEFORE_SEND, ps_global);
1901     pbf->allow_flowed_text = (F_OFF(F_QUELL_FLOWED_TEXT, ps_global)
1902 			      && F_OFF(F_STRIP_WS_BEFORE_SEND, ps_global)
1903 			      && (strcmp(pbf->quote_str, "> ") == 0
1904 				  || strcmp(pbf->quote_str, ">") == 0));
1905     pbf->edit_offset   = 0;
1906     title               = cpystr(set_titlebar(editor_title,
1907 				    ps_global->mail_stream,
1908 				    ps_global->context_current,
1909 				    ps_global->cur_folder,ps_global->msgmap,
1910 				    0, FolderName, 0, 0, NULL));
1911     pbf->pine_anchor   = title;
1912 
1913 #if	defined(DOS) || defined(OS2)
1914     if(!pbf->oper_dir && ps_global->VAR_FILE_DIR){
1915 	pbf->oper_dir    = ps_global->VAR_FILE_DIR;
1916     }
1917 #endif
1918 
1919     if(redraft_pos && editor_title && !strcmp(editor_title, COMPOSE_MAIL_TITLE))
1920       pbf->pine_flags |= P_CHKPTNOW;
1921 
1922     /* NOTE: initial cursor position set below */
1923 
1924     dprint((9, "flags: %x\n", pbf->pine_flags));
1925 
1926     /*
1927      * When user runs compose and the current folder is a newsgroup,
1928      * offer to post to the current newsgroup.
1929      */
1930     if(!(outgoing->to || (outgoing->newsgroups && *outgoing->newsgroups))
1931        && IS_NEWS(ps_global->mail_stream)){
1932 	char prompt[200], news_group[MAILTMPLEN];
1933 
1934 	pine_send_newsgroup_name(ps_global->mail_stream->mailbox, news_group,
1935 				 sizeof(news_group));
1936 
1937 	/*
1938 	 * Replies don't get this far because To or Newsgroups will already
1939 	 * be filled in.  So must be either ordinary compose or forward.
1940 	 * Forward sets subject, so use that to tell the difference.
1941 	 */
1942 	if(news_group[0] && !outgoing->subject){
1943 	    int ch = 'y';
1944 	    int ret_val;
1945 	    char *errmsg = NULL;
1946 	    BUILDER_ARG	 *fcc_build = NULL;
1947 
1948 	    if(F_OFF(F_COMPOSE_TO_NEWSGRP,ps_global)){
1949 		snprintf(prompt, sizeof(prompt),
1950 		    _("Post to current newsgroup (%s)"), news_group);
1951 		prompt[sizeof(prompt)-1] = '\0';
1952 		ch = want_to(prompt, 'y', 'x', NO_HELP, WT_NORM);
1953 	    }
1954 
1955 	    switch(ch){
1956 	      case 'y':
1957 		if(outgoing->newsgroups)
1958 		  fs_give((void **)&outgoing->newsgroups);
1959 
1960 		if(!fcc_arg && !(role && role->fcc)){
1961 		    fcc_build = (BUILDER_ARG *)fs_get(sizeof(BUILDER_ARG));
1962 		    memset((void *)fcc_build, 0, sizeof(BUILDER_ARG));
1963 		    fcc_build->tptr = fcc_to_free;
1964 		}
1965 
1966 		ret_val = news_build(news_group, &outgoing->newsgroups,
1967 				     &errmsg, fcc_build, NULL);
1968 
1969 		if(ret_val == -1){
1970 		    if(outgoing->newsgroups)
1971 		      fs_give((void **)&outgoing->newsgroups);
1972 
1973 		    outgoing->newsgroups = cpystr(news_group);
1974 		}
1975 
1976 		if(!fcc_arg && !(role && role->fcc)){
1977 		    fcc_arg = fcc_to_free = fcc_build->tptr;
1978 		    fs_give((void **)&fcc_build);
1979 		}
1980 
1981 		if(errmsg){
1982 		    if(*errmsg){
1983 			q_status_message(SM_ORDER, 3, 3, errmsg);
1984 			display_message(NO_OP_COMMAND);
1985 		    }
1986 
1987 		    fs_give((void **)&errmsg);
1988 		}
1989 
1990 		break;
1991 
1992 	      case 'x': /* ^C */
1993 		q_status_message(SM_ORDER, 0, 3, _("Message cancelled"));
1994 		dprint((4, "=== send: cancelled\n"));
1995 		pbf = save_previous_pbuf;
1996 		return;
1997 
1998 	      case 'n':
1999 		break;
2000 
2001 	      default:
2002 		break;
2003 	    }
2004 	}
2005     }
2006     if(F_ON(F_PREDICT_NNTP_SERVER, ps_global)
2007        && outgoing->newsgroups && *outgoing->newsgroups
2008        && IS_NEWS(ps_global->mail_stream)){
2009 	NETMBX news_mb;
2010 
2011 	if(mail_valid_net_parse(ps_global->mail_stream->original_mailbox,
2012 				&news_mb))
2013 	  if(!strucmp(news_mb.service, "nntp")){
2014 	      if(*ps_global->mail_stream->original_mailbox == '{'){
2015 		  char *svcp = NULL, *psvcp;
2016 
2017 		  suggested_nntp_server =
2018 		    cpystr(ps_global->mail_stream->original_mailbox + 1);
2019 		  if((p = strindex(suggested_nntp_server, '}')) != NULL)
2020 		    *p = '\0';
2021 		  for(p = strindex(suggested_nntp_server, '/'); p && *p;
2022 		      p = strindex(p, '/')){
2023 		      /* take out /nntp, which gets added in nntp_open */
2024 		      if(!struncmp(p, "/nntp", 5))
2025 			svcp = p + 5;
2026 		      else if(!struncmp(p, "/service=nntp", 13))
2027 			svcp = p + 13;
2028 		      else if(!struncmp(p, "/service=\"nntp\"", 15))
2029 			svcp = p + 15;
2030 		      else
2031 			p++;
2032 		      if(svcp){
2033 			  if(*svcp == '\0')
2034 			    *p = '\0';
2035 			  else if(*svcp == '/' || *svcp == ':'){
2036 			      for(psvcp = p; *svcp; svcp++, psvcp++)
2037 				*psvcp = *svcp;
2038 			      *psvcp = '\0';
2039 			  }
2040 			  svcp = NULL;
2041 		      }
2042 		  }
2043 	      }
2044 	      else
2045 		suggested_nntp_server = cpystr(news_mb.orighost);
2046 	  }
2047     }
2048 
2049     /*
2050      * If we don't already have custom headers set and the role has custom
2051      * headers, then incorporate those custom headers into "custom".
2052      */
2053     if(!custom){
2054 	PINEFIELD *dflthdrs = NULL, *rolehdrs = NULL;
2055 
2056 	dflthdrs = parse_custom_hdrs(ps_global->VAR_CUSTOM_HDRS, UseAsDef);
2057 /*
2058  * If we allow the Combine argument here, we're saying that we want to
2059  * combine the values from the envelope and the role for the fields To,
2060  * Cc, Bcc, and Newsgroups. For example, if we are replying to a message
2061  * we'll have a To in the envelope because we're replying. If our role also
2062  * has a To action, then Combine would combine those two and offer both
2063  * to the user. We've decided against doing this. Instead, we always use
2064  * Replace, and the role's header value replaces the value from the
2065  * envelope. It might also make sense in some cases to do the opposite,
2066  * which would be treating the role headers as defaults, just like
2067  * customized-hdrs.
2068  */
2069 #ifdef WANT_TO_COMBINE_ADDRESSES
2070 	if(role && role->cstm)
2071 	  rolehdrs = parse_custom_hdrs(role->cstm, Combine);
2072 #else
2073 	if(role && role->cstm)
2074 	  rolehdrs = parse_custom_hdrs(role->cstm, Replace);
2075 #endif
2076 
2077 	if(rolehdrs){
2078 	    custom = combine_custom_headers(dflthdrs, rolehdrs);
2079 	    if(dflthdrs){
2080 		free_prompts(dflthdrs);
2081 		free_customs(dflthdrs);
2082 	    }
2083 
2084 	    if(rolehdrs){
2085 		free_prompts(rolehdrs);
2086 		free_customs(rolehdrs);
2087 	    }
2088 	}
2089         else
2090 	  custom = dflthdrs;
2091     }
2092 
2093     g_rolenick = role ? role->nick : NULL;
2094 
2095     /* how many fixed fields are there? */
2096     for(fixed_cnt = 0; pf_template && pf_template[fixed_cnt].name; fixed_cnt++)
2097       ;
2098 
2099     total_cnt = fixed_cnt + count_custom_hdrs_pf(custom,1);
2100 
2101     /* the fixed part of the PINEFIELDs */
2102     i       = fixed_cnt * sizeof(PINEFIELD);
2103     pfields = (PINEFIELD *)fs_get((size_t) i);
2104     memset(pfields, 0, (size_t) i);
2105 
2106     /* temporary headerentry array for pico */
2107     i        = (total_cnt + 1) * sizeof(struct headerentry);
2108     headents = (struct headerentry *)fs_get((size_t) i);
2109     memset(headents, 0, (size_t) i);
2110 
2111     i             = total_cnt * sizeof(PINEFIELD *);
2112     sending_order = (PINEFIELD **)fs_get((size_t) i);
2113     memset(sending_order, 0, (size_t) i);
2114 
2115     pbf->headents        = headents;
2116     header.env           = outgoing;
2117     header.local         = pfields;
2118     header.sending_order = sending_order;
2119 
2120     /* custom part of PINEFIELDs */
2121     header.custom = custom;
2122 
2123     he = headents;
2124     pf = pfields;
2125 
2126     /*
2127      * For Address types, pf->addr points to an ADDRESS *.
2128      * If that address is in the "outgoing" envelope, it will
2129      * be freed by the caller, otherwise, it should be freed here.
2130      * Pf->textbuf for an Address is used a little to set up a default,
2131      * but then is freed right away below.  Pf->scratch is used for a
2132      * pointer to some alloced space for pico to edit in.  Addresses in
2133      * the custom area are freed by free_customs().
2134      *
2135      * For FreeText types, pf->addr is not used.  Pf->text points to a
2136      * pointer that points to the text.  Pf->textbuf points to a copy of
2137      * the text that must be freed before we leave, otherwise, it is
2138      * probably a pointer into the envelope and that gets freed by the
2139      * caller.
2140      *
2141      * He->realaddr is the pointer to the text that pico actually edits.
2142      */
2143 
2144 #if	!(defined(DOS) || defined(OS2)) || defined(NOAUTH)
2145 # define NN 4
2146 #else
2147 # define NN 3
2148 #endif
2149 
2150     if(outgoing->newsgroups && *outgoing->newsgroups)
2151       use_news_order++;
2152 
2153     /* initialize the fixed header elements of the two temp arrays */
2154     for(i=0; i < fixed_cnt; i++, pf++){
2155 	static int news_order[] = {
2156 	    N_AUTHRCVD,N_FROM, N_REPLYTO, N_NEWS, N_TO, N_CC, N_BCC,
2157 	    N_FCC, N_LCC, N_ATTCH, N_SUBJ, N_REF, N_DATE, N_INREPLY,
2158 	    N_MSGID, N_PRIORITY, N_USERAGENT, N_NOBODY, N_POSTERR, N_RPLUID, N_RPLMBOX,
2159 	    N_SMTP, N_NNTP, N_CURPOS, N_OURREPLYTO, N_OURHDRS
2160 #if	!(defined(DOS) || defined(OS2)) || defined(NOAUTH)
2161 	    , N_SENDER
2162 #endif
2163 	};
2164 
2165 	index = i;
2166 	/* slightly different editing order if sending to news */
2167 	if(use_news_order &&
2168 	   index >= 0 && index < sizeof(news_order)/sizeof(news_order[0]))
2169 	  index = news_order[i];
2170 
2171 	/* copy the templates */
2172 	*he             = he_template[index];
2173 
2174 	pf->name        = cpystr(pf_template[index].name);
2175 	if(index == N_SENDER && F_ON(F_USE_SENDER_NOT_X, ps_global)){
2176 	  /* slide string over so it is Sender instead of X-X-Sender */
2177 	  for(p = pf->name+4; *p != '\0'; p++)
2178 	     *(p-4)  = *p;
2179 	  *(p-4) = '\0';
2180 	}
2181 	pf->type        = pf_template[index].type;
2182 	pf->canedit     = pf_template[index].canedit;
2183 	pf->rcptto      = pf_template[index].rcptto;
2184 	pf->writehdr    = pf_template[index].writehdr;
2185 	pf->localcopy   = pf_template[index].localcopy;
2186 	pf->extdata     = he;
2187 	pf->next        = pf + 1;
2188 
2189 	he->rich_header = view_as_rich(pf->name, he->rich_header);
2190 	if(F_OFF(F_ENABLE_TAB_COMPLETE,ps_global))
2191 	  he->nickcmpl = NULL;
2192 
2193 	switch(pf->type){
2194 	  case FreeText:   		/* realaddr points to c-client env */
2195 	    if(index == N_NEWS){
2196 		sending_order[1]	= pf;
2197 		he->realaddr		= &outgoing->newsgroups;
2198 	        he_news			= he;
2199 
2200 		switch(set_default_hdrval(pf, custom)){
2201 		  case Replace:
2202 		    if(*he->realaddr)
2203 		      fs_give((void **)he->realaddr);
2204 
2205 		    *he->realaddr = pf->textbuf;
2206 		    pf->textbuf = NULL;
2207 		    he->sticky = 1;
2208 		    break;
2209 
2210 		  case Combine:
2211 		    if(*he->realaddr){		/* combine values */
2212 			if(pf->textbuf && *pf->textbuf){
2213 			    char *combined_hdr;
2214 			    size_t l;
2215 
2216 			    l = strlen(*he->realaddr) + strlen(pf->textbuf) + 1;
2217 			    combined_hdr = (char *) fs_get((l+1) * sizeof(char));
2218 			    strncpy(combined_hdr, *he->realaddr, l);
2219 			    combined_hdr[l] = '\0';
2220 			    strncat(combined_hdr, ",", l+1-1-strlen(combined_hdr));
2221 			    combined_hdr[l] = '\0';
2222 			    strncat(combined_hdr, pf->textbuf, l+1-1-strlen(combined_hdr));
2223 			    combined_hdr[l] = '\0';
2224 
2225 			    fs_give((void **)he->realaddr);
2226 			    *he->realaddr = combined_hdr;
2227 			    q_status_message(SM_ORDER, 3, 3,
2228 					     "Adding newsgroup from role");
2229 			    he->sticky = 1;
2230 			}
2231 		    }
2232 		    else{
2233 			*he->realaddr = pf->textbuf;
2234 			pf->textbuf   = NULL;
2235 		    }
2236 
2237 		    break;
2238 
2239 		  case UseAsDef:
2240 		    /* if no value, use default */
2241 		    if(!*he->realaddr){
2242 			*he->realaddr = pf->textbuf;
2243 			pf->textbuf   = NULL;
2244 		    }
2245 
2246 		    break;
2247 
2248 		  case NoMatch:
2249 		    break;
2250 		}
2251 
2252 		/* If there is a newsgroup, we'd better show it */
2253 		if(outgoing->newsgroups && *outgoing->newsgroups)
2254 		  he->rich_header = 0; /* force on by default */
2255 
2256 		if(pf->textbuf)
2257 		  fs_give((void **)&pf->textbuf);
2258 
2259 		pf->text = he->realaddr;
2260 	    }
2261 	    else if(index == N_DATE){
2262 		sending_order[2]	= pf;
2263 		pf->text		= (char **) &outgoing->date;
2264 		pf->extdata			= NULL;
2265 	    }
2266 	    else if(index == N_INREPLY){
2267 		sending_order[NN+9]	= pf;
2268 		pf->text		= &outgoing->in_reply_to;
2269 		pf->extdata			= NULL;
2270 	    }
2271 	    else if(index == N_MSGID){
2272 		sending_order[NN+10]	= pf;
2273 		pf->text		= &outgoing->message_id;
2274 		pf->extdata			= NULL;
2275 	    }
2276 	    else if(index == N_REF){
2277 		sending_order[NN+11]	= pf;
2278 		pf->text		= &outgoing->references;
2279 		pf->extdata			= NULL;
2280 	    }
2281 	    else if(index == N_PRIORITY){
2282 		sending_order[NN+12]	= pf;
2283 		pf->text		= &pf->textbuf;
2284 		pf->extdata			= NULL;
2285 	    }
2286 	    else if(index == N_USERAGENT){
2287 		sending_order[NN+13]	= pf;
2288 		pf->text		= &pf->textbuf;
2289 		pf->textbuf		= generate_user_agent();
2290 		pf->extdata			= NULL;
2291 	    }
2292 	    else if(index == N_POSTERR){
2293 		sending_order[NN+14]	= pf;
2294 		pf_err			= pf;
2295 		pf->text		= &pf->textbuf;
2296 		pf->extdata			= NULL;
2297 	    }
2298 	    else if(index == N_RPLUID){
2299 		sending_order[NN+15]	= pf;
2300 		pf_uid			= pf;
2301 		pf->text		= &pf->textbuf;
2302 		pf->extdata			= NULL;
2303 	    }
2304 	    else if(index == N_RPLMBOX){
2305   		sending_order[NN+16]	= pf;
2306 		pf_mbox			= pf;
2307 		pf->text		= &pf->textbuf;
2308 		pf->extdata			= NULL;
2309 	    }
2310 	    else if(index == N_SMTP){
2311 		sending_order[NN+17]	= pf;
2312 		pf_smtp_server		= pf;
2313 		pf->text		= &pf->textbuf;
2314 		pf->extdata			= NULL;
2315 	    }
2316 	    else if(index == N_NNTP){
2317 		sending_order[NN+18]	= pf;
2318 		pf_nntp_server		= pf;
2319 		pf->text		= &pf->textbuf;
2320 		pf->extdata			= NULL;
2321 	    }
2322 	    else if(index == N_CURPOS){
2323 		sending_order[NN+19]	= pf;
2324 		pf_curpos		= pf;
2325 		pf->text		= &pf->textbuf;
2326 		pf->extdata			= NULL;
2327 	    }
2328 	    else if(index == N_OURREPLYTO){
2329 		sending_order[NN+20]	= pf;
2330 		pf_ourrep		= pf;
2331 		pf->text		= &pf->textbuf;
2332 		pf->extdata			= NULL;
2333 	    }
2334 	    else if(index == N_OURHDRS){
2335 		sending_order[NN+21]	= pf;
2336 		pf_ourhdrs		= pf;
2337 		pf->text		= &pf->textbuf;
2338 		pf->extdata			= NULL;
2339 	    }
2340 	    else if(index == N_AUTHRCVD){
2341 		sending_order[0]	= pf;
2342 		pf_ourhdrs		= pf;
2343 		pf->text		= &pf->textbuf;
2344 		pf->extdata			= NULL;
2345 	    }
2346 	    else{
2347 		q_status_message(SM_ORDER | SM_DING, 3, 7,
2348 			    "Botched: Unmatched FreeText header in pine_send");
2349 	    }
2350 
2351 	    break;
2352 
2353 	  /* can't do a default for this one */
2354 	  case Attachment:
2355 	    /* If there is an attachment already, we'd better show them */
2356             if(body && *body && (*body)->type != TYPETEXT)
2357 	      he->rich_header = 0; /* force on by default */
2358 
2359 	    break;
2360 
2361 	  case Address:
2362 	    switch(index){
2363 	      case N_FROM:
2364 		sending_order[3]	= pf;
2365 		pf->addr		= &outgoing->from;
2366 		if(role && role->from){
2367 		    if(ps_global->never_allow_changing_from)
2368 		      q_status_message(SM_ORDER, 3, 3, _("Site policy doesn't allow changing From address so role's From has no effect"));
2369 		    else{
2370 			outgoing->from = copyaddrlist(role->from);
2371 			he->display_it  = 1;  /* show it */
2372 			he->rich_header = 0;
2373 		    }
2374 		}
2375 
2376 		he_from			= he;
2377 		break;
2378 
2379 	      case N_TO:
2380 		sending_order[NN+2]	= pf;
2381 		pf->addr		= &outgoing->to;
2382 		/* If already set, make it act like we typed it in */
2383 		if(outgoing->to
2384 		   && outgoing->to->mailbox
2385 		   && outgoing->to->mailbox[0]
2386 		   && flags & PS_STICKY_TO)
2387 		  he->sticky = 1;
2388 
2389 		he_to			= he;
2390 		pf_to			= pf;
2391 		break;
2392 
2393 	      case N_NOBODY:
2394 		sending_order[NN+5]	= pf;
2395 		pf_nobody		= pf;
2396 		if(ps_global->VAR_EMPTY_HDR_MSG
2397 		   && !ps_global->VAR_EMPTY_HDR_MSG[0]){
2398 		    pf->addr		= NULL;
2399 		}
2400 		else{
2401 		    nobody_addr          = mail_newaddr();
2402 		    nobody_addr->next    = mail_newaddr();
2403 		    nobody_addr->mailbox = cpystr(rfc1522_encode(tmp_20k_buf,
2404 			    SIZEOF_20KBUF,
2405 			    (unsigned char *)(ps_global->VAR_EMPTY_HDR_MSG
2406 						? ps_global->VAR_EMPTY_HDR_MSG
2407 						: "undisclosed-recipients"),
2408 			    ps_global->posting_charmap));
2409 		    pf->addr		= &nobody_addr;
2410 		}
2411 
2412 		break;
2413 
2414 	      case N_CC:
2415 		sending_order[NN+3]	= pf;
2416 		pf->addr		= &outgoing->cc;
2417 		break;
2418 
2419 	      case N_BCC:
2420 		sending_order[NN+4]	= pf;
2421 		pf->addr		= &outgoing->bcc;
2422 		/* if bcc exists, make sure it's exposed so nothing's
2423 		 * sent by mistake...
2424 		 */
2425 		if(outgoing->bcc)
2426 		  he->display_it = 1;
2427 
2428 		break;
2429 
2430 	      case N_REPLYTO:
2431 		sending_order[NN+1]	= pf;
2432 		pf->addr		= &outgoing->reply_to;
2433 		if(role && role->replyto){
2434 		    if(outgoing->reply_to)
2435 		      mail_free_address(&outgoing->reply_to);
2436 
2437 		    outgoing->reply_to = copyaddrlist(role->replyto);
2438 		    he->display_it  = 1;  /* show it */
2439 		    he->rich_header = 0;
2440 		}
2441 
2442 		break;
2443 
2444 	      case N_LCC:
2445 		sending_order[NN+7]	= pf;
2446 		pf->addr		= &lcc_addr;
2447 		he_lcc			= he;
2448 		if(lcc_arg){
2449 		    build_address(lcc_arg, &addr, NULL, NULL, NULL);
2450 		    rfc822_parse_adrlist(&lcc_addr, addr,
2451 					 ps_global->maildomain);
2452 		    fs_give((void **)&addr);
2453 		    he->display_it = 1;
2454 		}
2455 
2456 		break;
2457 
2458 #if	!(defined(DOS) || defined(OS2)) || defined(NOAUTH)
2459               case N_SENDER:
2460 		sending_order[4]	= pf;
2461 		pf->addr		= &outgoing->sender;
2462                 break;
2463 #endif
2464 
2465 	      default:
2466 		q_status_message1(SM_ORDER,3,7,
2467 		    "Internal error: Address header %s", comatose(index));
2468 		break;
2469 	    }
2470 
2471 	    /*
2472 	     * If this is a reply to news, don't show the regular email
2473 	     * recipient headers (unless they are non-empty).
2474 	     */
2475 	    if((outgoing->newsgroups && *outgoing->newsgroups)
2476 	       && (index == N_TO || index == N_CC
2477 		   || index == N_BCC || index == N_LCC)
2478 	       && (pf->addr && !*pf->addr)){
2479 		if((ct=set_default_hdrval(pf, custom)) >= UseAsDef &&
2480 		   pf->textbuf && *pf->textbuf){
2481 		    removing_trailing_white_space(pf->textbuf);
2482 		    (void)removing_double_quotes(pf->textbuf);
2483 		    build_address(pf->textbuf, &addr, NULL, NULL, NULL);
2484 		    rfc822_parse_adrlist(pf->addr, addr,
2485 					 ps_global->maildomain);
2486 		    fs_give((void **)&addr);
2487 		    if(ct > UseAsDef)
2488 		      he->sticky = 1;
2489 		}
2490 		else
2491 		  he->rich_header = 1; /* hide */
2492 	    }
2493 
2494 	    /*
2495 	     * If this address doesn't already have a value, then we check
2496 	     * for a default value assigned by the user.
2497 	     */
2498 	    else if(pf->addr && !*pf->addr){
2499 		if((ct=set_default_hdrval(pf, custom)) >= UseAsDef &&
2500 		   (index != N_FROM ||
2501 		    (!ps_global->never_allow_changing_from &&
2502 		     F_ON(F_ALLOW_CHANGING_FROM, ps_global))) &&
2503 		   pf->textbuf && *pf->textbuf){
2504 
2505 		    removing_trailing_white_space(pf->textbuf);
2506 		    (void)removing_double_quotes(pf->textbuf);
2507 
2508 		    /*
2509 		     * Try to set To based on Lcc. Don't attempt Fcc.
2510 		     */
2511 		    if(index == N_LCC && !he_to->sticky && pf_to && pf_to->addr){
2512 			BUILDER_ARG *barg = NULL;
2513 			char *ppp = NULL;
2514 
2515 			if(*pf_to->addr)
2516 			  ppp = addr_list_string(*pf_to->addr, NULL, 1);
2517 
2518 			if(!ppp)
2519 			  ppp = cpystr("");
2520 
2521 			barg = (BUILDER_ARG *) fs_get(sizeof(*barg));
2522 			memset(barg, 0, sizeof(*barg));
2523 			barg->me = &(he->bldr_private);
2524 			barg->aff = &(he_to->bldr_private);
2525 			barg->tptr = cpystr(ppp);
2526 
2527 			build_addr_lcc(pf->textbuf, &addr, NULL, barg, NULL);
2528 			he->display_it = 1;
2529 
2530 			rfc822_parse_adrlist(pf->addr, addr,
2531 					     ps_global->maildomain);
2532 			if(addr)
2533 			  fs_give((void **) &addr);
2534 
2535 			if(ct > UseAsDef)
2536 			  he->sticky = 1;
2537 
2538 			if(barg && barg->tptr && strcmp(ppp, barg->tptr)){
2539 			    ADDRESS *a = NULL;
2540 
2541 			    rfc822_parse_adrlist(&a, barg->tptr,
2542 						 ps_global->maildomain);
2543 			    if(a){
2544 				if(pf_to->addr)
2545 				  mail_free_address(pf_to->addr);
2546 
2547 				*pf_to->addr = a;
2548 			    }
2549 			}
2550 
2551 			if(barg){
2552 			    if(barg->tptr)
2553 			      fs_give((void **) &barg->tptr);
2554 
2555 			    fs_give((void **) &barg);
2556 			}
2557 
2558 			if(ppp)
2559 			  fs_give((void **) &ppp);
2560 		    }
2561 		    else{
2562 			build_address(pf->textbuf, &addr, NULL, NULL, NULL);
2563 			rfc822_parse_adrlist(pf->addr, addr,
2564 					     ps_global->maildomain);
2565 			if(addr)
2566 			  fs_give((void **) &addr);
2567 
2568 			if(ct > UseAsDef)
2569 			  he->sticky = 1;
2570 		    }
2571 		}
2572 
2573 		/* if we still don't have a from */
2574 		if(index == N_FROM && !*pf->addr)
2575 		  *pf->addr = generate_from();
2576 	    }
2577 
2578 	    /*
2579 	     * Addr is already set in the rest of the cases.
2580 	     */
2581 	    else if((index == N_FROM || index == N_REPLYTO) && pf->addr){
2582 		ADDRESS *adr = NULL;
2583 
2584 		/*
2585 		 * We get to this case of the ifelse if the from or reply-to
2586 		 * addr was set by a role above.
2587 		 */
2588 
2589 		/* figure out the default value */
2590 		(void)set_default_hdrval(pf, custom);
2591 		if(pf->textbuf && *pf->textbuf){
2592 		    removing_trailing_white_space(pf->textbuf);
2593 		    (void)removing_double_quotes(pf->textbuf);
2594 		    build_address(pf->textbuf, &addr, NULL, NULL, NULL);
2595 		    rfc822_parse_adrlist(&adr, addr,
2596 					 ps_global->maildomain);
2597 		    fs_give((void **)&addr);
2598 		}
2599 
2600 		/* if value set by role is different from default, show it */
2601 		if(adr && !address_is_same(*pf->addr, adr))
2602 		  he->display_it = 1;  /* start this off showing */
2603 
2604 		/* malformed */
2605 		if(!(*pf->addr)->mailbox){
2606 		    fs_give((void **)pf->addr);
2607 		    he->display_it = 1;
2608 		}
2609 
2610 		if(adr)
2611 		  mail_free_address(&adr);
2612 	    }
2613 	    else if((index == N_TO || index == N_CC || index == N_BCC)
2614 		    && pf->addr){
2615 		ADDRESS *a = NULL, **tail;
2616 
2617 		/*
2618 		 * These three are different from the others because we
2619 		 * might add the addresses to what is already there instead
2620 		 * of replacing.
2621 		 */
2622 
2623 		switch(set_default_hdrval(pf, custom)){
2624 		  case Replace:
2625 		    if(*pf->addr)
2626 		      mail_free_address(pf->addr);
2627 
2628 		    removing_trailing_white_space(pf->textbuf);
2629 		    (void)removing_double_quotes(pf->textbuf);
2630 		    build_address(pf->textbuf, &addr, NULL, NULL, NULL);
2631 		    rfc822_parse_adrlist(pf->addr, addr, ps_global->maildomain);
2632 		    fs_give((void **)&addr);
2633 		    he->sticky = 1;
2634 		    break;
2635 
2636 		  case Combine:
2637 		    removing_trailing_white_space(pf->textbuf);
2638 		    (void)removing_double_quotes(pf->textbuf);
2639 		    build_address(pf->textbuf, &addr, NULL, NULL, NULL);
2640 		    rfc822_parse_adrlist(&a, addr, ps_global->maildomain);
2641 		    fs_give((void **)&addr);
2642 		    he->sticky = 1;
2643 		    if(a){
2644 			for(tail = pf->addr; *tail; tail = &(*tail)->next)
2645 			  ;
2646 			*tail = reply_cp_addr(ps_global, 0, NULL, NULL,
2647 					      *pf->addr, NULL, a, RCA_ALL);
2648 			q_status_message(SM_ORDER, 3, 3,
2649 					 "Adding addresses from role");
2650 			mail_free_address(&a);
2651 		    }
2652 
2653 		    break;
2654 
2655 		  case UseAsDef:
2656 		  case NoMatch:
2657 		    break;
2658 		}
2659 
2660 		he->display_it = 1;  /* start this off showing */
2661 	    }
2662 	    else if(pf->addr){
2663 		switch(set_default_hdrval(pf, custom)){
2664 		  case Replace:
2665 		  case Combine:
2666 		    if(*pf->addr)
2667 		      mail_free_address(pf->addr);
2668 
2669 		    removing_trailing_white_space(pf->textbuf);
2670 		    (void)removing_double_quotes(pf->textbuf);
2671 		    build_address(pf->textbuf, &addr, NULL, NULL, NULL);
2672 		    rfc822_parse_adrlist(pf->addr, addr, ps_global->maildomain);
2673 		    fs_give((void **)&addr);
2674 		    he->sticky = 1;
2675 		    break;
2676 
2677 		  case UseAsDef:
2678 		  case NoMatch:
2679 		    break;
2680 		}
2681 
2682 		he->display_it = 1;
2683 	    }
2684 
2685 	    if(pf->addr && *pf->addr && !(*pf->addr)->mailbox){
2686 		mail_free_address(pf->addr);
2687 		he->display_it = 1;  /* start this off showing */
2688 	    }
2689 
2690 	    if(pf->textbuf)		/* free default value in any case */
2691 	      fs_give((void **)&pf->textbuf);
2692 
2693 	    /* outgoing2strings will alloc the string pf->scratch below */
2694 	    he->realaddr = &pf->scratch;
2695 	    break;
2696 
2697 	  case Fcc:
2698 	    sending_order[NN+8] = pf;
2699 	    pf_fcc              = pf;
2700 	    if(role && role->fcc)
2701 	      fcc = role->fcc;
2702 	    else
2703 	      fcc = get_fcc(fcc_arg);
2704 
2705 	    if(fcc_to_free){
2706 		fs_give((void **)&fcc_to_free);
2707 		fcc_arg = NULL;
2708 	    }
2709 
2710 	    if(((flags & PS_STICKY_FCC) && fcc[0]) || (role && role->fcc))
2711 	      he->sticky = 1;
2712 
2713 	    if(role)
2714 	      role->fcc = NULL;
2715 
2716 	    if(strcmp(fcc, ps_global->VAR_DEFAULT_FCC) != 0)
2717 	      he->display_it = 1;  /* start this off showing */
2718 
2719 	    he->realaddr  = &fcc;
2720 	    pf->text      = &fcc;
2721 	    he_fcc        = he;
2722 	    break;
2723 
2724 	  case Subject :
2725 	    sending_order[NN+6]	= pf;
2726 
2727 	    switch(set_default_hdrval(pf, custom)){
2728 	      case Replace:
2729 	      case Combine:
2730 		pf->scratch = pf->textbuf;
2731 		pf->textbuf = NULL;
2732 		he->sticky = 1;
2733 		if(outgoing->subject)
2734 		  fs_give((void **)&outgoing->subject);
2735 
2736 		break;
2737 
2738 	      case UseAsDef:
2739 	      case NoMatch:
2740 		/* if no value, use default */
2741 		if(outgoing->subject){
2742 		    pf->scratch = cpystr(outgoing->subject);
2743 		}
2744 		else{
2745 		    pf->scratch = pf->textbuf;
2746 		    pf->textbuf   = NULL;
2747 		}
2748 
2749 		break;
2750 	    }
2751 
2752 	    he->realaddr = &pf->scratch;
2753 	    pf->text	 = &outgoing->subject;
2754 	    break;
2755 
2756 	  default:
2757 	    q_status_message1(SM_ORDER,3,7,
2758 			      "Unknown header type %d in pine_send",
2759 			      (void *)pf->type);
2760 	    break;
2761 	}
2762 
2763 	/*
2764 	 * We may or may not want to give the user the chance to edit
2765 	 * the From and Reply-To lines.  If they are listed in either
2766 	 * Default-composer-hdrs or Customized-hdrs, then they can edit
2767 	 * them, else no.
2768 	 * If canedit is not set, that means that this header is not in
2769 	 * the user's customized-hdrs.  If rich_header is set, that
2770 	 * means that this header is not in the user's
2771 	 * default-composer-hdrs (since From and Reply-To are rich
2772 	 * by default).  So, don't give it an he to edit with in that case.
2773 	 *
2774 	 * For other types, just not setting canedit will cause it to be
2775 	 * uneditable, regardless of what the user does.
2776 	 */
2777 	switch(index){
2778 	  case N_FROM:
2779     /* to allow it, we let this fall through to the reply-to case below */
2780 	    if(ps_global->never_allow_changing_from ||
2781 	       (F_OFF(F_ALLOW_CHANGING_FROM, ps_global) &&
2782 	        !(role && role->from))){
2783 		if(pf->canedit || !he->rich_header)
2784 		  q_status_message(SM_ORDER, 3, 3,
2785 			_("Not allowed to change header \"From\""));
2786 
2787 		memset(he, 0, (size_t)sizeof(*he));
2788 		pf->extdata = NULL;
2789 		break;
2790 	    }
2791 
2792 	  case N_REPLYTO:
2793 	    if(!pf->canedit && he->rich_header){
2794 	        memset(he, 0, (size_t)sizeof(*he));
2795 		pf->extdata = NULL;
2796 	    }
2797 	    else{
2798 		pf->canedit = 1;
2799 		he++;
2800 	    }
2801 
2802 	    break;
2803 
2804 	  default:
2805 	    if(!pf->canedit){
2806 	        memset(he, 0, (size_t)sizeof(*he));
2807 		pf->extdata = NULL;
2808 	    }
2809 	    else
2810 	      he++;
2811 
2812 	    break;
2813 	}
2814     }
2815 
2816     /*
2817      * This is so the builder can tell the composer to fill the affected
2818      * field based on the value in the field on the left.
2819      *
2820      * Note that this mechanism isn't completely general.  Each entry has
2821      * only a single next_affected, so if some other entry points an
2822      * affected entry at an entry with a next_affected, they all inherit
2823      * that next_affected.  Since this isn't used much a careful ordering
2824      * of the affected fields should make it a sufficient mechanism.
2825      */
2826     he_to->affected_entry   = he_fcc;
2827     he_news->affected_entry = he_fcc;
2828     he_lcc->affected_entry  = he_to;
2829     he_to->next_affected    = he_fcc;
2830 
2831     (--pf)->next = (total_cnt != fixed_cnt) ? header.custom : NULL;
2832 
2833     i--;  /* subtract one because N_ATTCH doesn't get a sending_order slot */
2834     /*
2835      * Set up headerentries for custom fields.
2836      * NOTE: "i" is assumed to now index first custom field in sending
2837      *       order.
2838      */
2839     for(pf = pf->next; pf && pf->name; pf = pf->next){
2840 	char *addr;
2841 
2842 	if(pf->standard)
2843 	  continue;
2844 
2845 	pf->extdata          = he;
2846 	pf->canedit     = 1;
2847 	pf->rcptto      = 0;
2848 	pf->writehdr    = 1;
2849 	pf->localcopy   = 1;
2850 
2851 	switch(pf->type){
2852 	  case Address:
2853 	    if(pf->addr){				/* better be set */
2854 		sending_order[i++] = pf;
2855 		*he = he_custom_addr_templ;
2856 		/* change default text into an ADDRESS */
2857 		/* strip quotes around whole default */
2858 		removing_trailing_white_space(pf->textbuf);
2859 		(void)removing_double_quotes(pf->textbuf);
2860 		build_address(pf->textbuf, &addr, NULL, NULL, NULL);
2861 		rfc822_parse_adrlist(pf->addr, addr, ps_global->maildomain);
2862 		fs_give((void **)&addr);
2863 		if(pf->textbuf)
2864 		  fs_give((void **)&pf->textbuf);
2865 
2866 		he->realaddr = &pf->scratch;
2867 		if(F_OFF(F_ENABLE_TAB_COMPLETE,ps_global))
2868 		  he->nickcmpl = NULL;
2869 	    }
2870 
2871 	    break;
2872 
2873 	  case FreeText:
2874 	    sending_order[i++] = pf;
2875 	    *he                = he_custom_free_templ;
2876 	    he->realaddr       = &pf->textbuf;
2877 	    pf->text           = &pf->textbuf;
2878 	    if(((!pf->val || !pf->val[0]) && pf->textbuf && pf->textbuf[0]) ||
2879 	       (pf->val && (!pf->textbuf || strcmp(pf->textbuf, pf->val))))
2880 	      he->display_it  = 1;  /* show it */
2881 
2882 	    break;
2883 
2884 	  default:
2885 	    q_status_message1(SM_ORDER,0,7,"Unknown custom header type %d",
2886 							(void *)pf->type);
2887 	    break;
2888 	}
2889 
2890 	he->name = pf->name;
2891 
2892 	/* use first 8 characters for prompt */
2893 	he->prompt = cpystr("        : ");
2894 	strncpy(he->prompt, he->name, MIN(strlen(he->name), he->prwid - 2));
2895 
2896 	he->rich_header = view_as_rich(he->name, he->rich_header);
2897 	he++;
2898     }
2899 
2900     /*
2901      * Make sure at least *one* field is displayable...
2902      */
2903     for(index = -1, i=0, pf=header.local; pf && pf->name; pf=pf->next, i++)
2904       if(HE(pf) && !HE(pf)->rich_header){
2905 	  index = i;
2906 	  break;
2907       }
2908 
2909     /*
2910      * None displayable!!!  Warn and display defaults.
2911      */
2912     if(index == -1){
2913 	q_status_message(SM_ORDER,0,5,
2914 		     "No default-composer-hdrs matched, displaying defaults");
2915 	for(i = 0, pf = header.local; pf; pf = pf->next, i++)
2916 	  if((i == N_TO || i == N_CC || i == N_SUBJ || i == N_ATTCH)
2917 	      && HE(pf))
2918 	    HE(pf)->rich_header = 0;
2919     }
2920 
2921     /*
2922      * Save information about body which set_mime_type_by_grope might change.
2923      * Then, if we get an error sending, we reset these things so that
2924      * grope can do it's thing again after we edit some more.
2925      */
2926     if ((*body)->type == TYPEMULTIPART)
2927 	bp = save_body_particulars(&(*body)->nested.part->body);
2928     else
2929         bp = save_body_particulars(*body);
2930 
2931 
2932     local_redraft_pos = redraft_pos;
2933 
2934     /*----------------------------------------------------------------------
2935        Loop calling the editor until everything goes well
2936      ----*/
2937     while(1){
2938 	int saved_user_timeout;
2939 
2940 	/* Reset body to what it was when we started. */
2941 	if ((*body)->type == TYPEMULTIPART)
2942 	    reset_body_particulars(bp, &(*body)->nested.part->body);
2943 	else
2944 	    reset_body_particulars(bp,*body);
2945 	/*
2946 	 * set initial cursor position based on how many times we've been
2947 	 * thru the loop...
2948 	 */
2949 	if(reply && reply->pseudo){
2950 	    pbf->pine_flags |= reply->data.pico_flags;
2951 	}
2952 	else if(body_start){
2953 	    pbf->pine_flags |= P_BODY;
2954 	    body_start = 0;		/* maybe not next time */
2955 	}
2956 	else if(local_redraft_pos){
2957 	    pbf->edit_offset = local_redraft_pos->offset;
2958 	    /* set the start_here bit in correct header */
2959 	    for(pf = header.local; pf && pf->name; pf = pf->next)
2960 	      if(strcmp(pf->name, local_redraft_pos->hdrname) == 0
2961 		  && HE(pf)){
2962 		  HE(pf)->start_here = 1;
2963 		  break;
2964 	      }
2965 
2966 	    /* If didn't find it, we start in body. */
2967 	    if(!pf || !pf->name)
2968 	      pbf->pine_flags |= P_BODY;
2969 	}
2970 	else if(reply && (!reply->forw && !reply->forwarded)){
2971 	    pbf->pine_flags |= P_BODY;
2972 	}
2973 
2974 	/* in case these were turned on in previous pass through loop */
2975 	if(pf_nobody){
2976 	    pf_nobody->writehdr  = 0;
2977 	    pf_nobody->localcopy = 0;
2978 	}
2979 
2980 	if(pf_fcc)
2981 	  pf_fcc->localcopy = 0;
2982 
2983 	/*
2984 	 * If a sending attempt failed after we passed the message text
2985 	 * thru a user-defined filter, "orig_so" points to the original
2986 	 * text.  Replace the body's encoded data with the original...
2987 	 */
2988 	if(orig_so){
2989 	    STORE_S **so = (STORE_S **)(((*body)->type == TYPEMULTIPART)
2990 				? &(*body)->nested.part->body.contents.text.data
2991 				: &(*body)->contents.text.data);
2992 	    so_give(so);
2993 	    *so     = orig_so;
2994 	    orig_so = NULL;
2995 	}
2996 
2997         /*
2998          * Convert the envelope and body to the string format that
2999          * pico can edit
3000          */
3001         outgoing2strings(&header, *body, &pbf->msgtext, &pbf->attachments, 0);
3002 
3003 	for(pf = header.local; pf && pf->name; pf = pf->next){
3004 	    /*
3005 	     * If this isn't the first time through this loop, we may have
3006 	     * freed some of the FreeText headers below so that they wouldn't
3007 	     * show up as empty headers in the finished message.  Need to
3008 	     * alloc them again here so they can be edited.
3009 	     */
3010 	    if(pf->type == FreeText && HE(pf) && !*HE(pf)->realaddr)
3011 	      *HE(pf)->realaddr = cpystr("");
3012 
3013 	    if(pf->type != Attachment && HE(pf) && *HE(pf)->realaddr)
3014 	      HE(pf)->maxlen = strlen(*HE(pf)->realaddr);
3015 	}
3016 
3017 	/*
3018 	 * If From is exposed, probably by a role, then start the cursor
3019 	 * on the first line which isn't filled in. If it isn't, then we
3020 	 * don't move the cursor, mostly for back-compat.
3021 	 */
3022 	if((!reply || reply->forw || reply->forwarded) &&
3023 	   !local_redraft_pos && !(pbf->pine_flags & P_BODY) && he_from &&
3024 	   (he_from->display_it || !he_from->rich_header)){
3025 	    for(pf = header.local; pf && pf->name; pf = pf->next)
3026 	      if(HE(pf) &&
3027 		 (HE(pf)->display_it || !HE(pf)->rich_header) &&
3028 		 HE(pf)->realaddr &&
3029 		 (!*HE(pf)->realaddr || !**HE(pf)->realaddr)){
3030 		  HE(pf)->start_here = 1;
3031 		  break;
3032 	      }
3033 	}
3034 
3035 #ifdef _WINDOWS
3036 	mswin_setwindowmenu (MENU_COMPOSER);
3037 #endif
3038 
3039 	cancel_busy_cue(-1);
3040         flush_status_messages(1);
3041 
3042 	/* turn off user input timeout when in composer */
3043 	saved_user_timeout = ps_global->hours_to_timeout;
3044 	ps_global->hours_to_timeout = 0;
3045 	dprint((1, "\n  ---- COMPOSER ----\n"));
3046 	editor_result = pico(pbf);
3047 	dprint((4, "... composer returns (0x%x)\n", editor_result));
3048 	ps_global->hours_to_timeout = saved_user_timeout;
3049 
3050 #ifdef _WINDOWS
3051 	mswin_setwindowmenu (MENU_DEFAULT);
3052 #endif
3053 	fix_windsize(ps_global);
3054 
3055 	/*
3056 	 * Only reinitialize signals if we didn't receive an interesting
3057 	 * one while in pico, since pico's return is part of processing that
3058 	 * signal and it should continue to be ignored.
3059 	 */
3060 	if(!(editor_result & COMP_GOTHUP))
3061 	  init_signals();        /* Pico has it's own signal stuff */
3062 
3063 	/*
3064 	 * We're going to save in DEADLETTER.  Dump attachments first.
3065 	 */
3066 	if(editor_result & COMP_CANCEL)
3067 	  free_attachment_list(&pbf->attachments);
3068 
3069         /* Turn strings back into structures */
3070         strings2outgoing(&header, body, pbf->attachments, flowing_requested);
3071 
3072         /* Make newsgroups NULL if it is "" (so won't show up in headers) */
3073 	if(outgoing->newsgroups){
3074 	    sqzspaces(outgoing->newsgroups);
3075 	    if(!outgoing->newsgroups[0])
3076 	      fs_give((void **)&(outgoing->newsgroups));
3077 	}
3078 
3079         /* Make subject NULL if it is "" (so won't show up in headers) */
3080         if(outgoing->subject && !outgoing->subject[0])
3081           fs_give((void **)&(outgoing->subject));
3082 
3083 	/* remove custom fields that are empty */
3084 	for(pf = header.local; pf && pf->name; pf = pf->next){
3085 	  if(pf->type == FreeText && pf->textbuf){
3086 	    if(pf->textbuf[0] == '\0'){
3087 		fs_give((void **)&pf->textbuf);
3088 		pf->text = NULL;
3089 	    }
3090 	  }
3091 	}
3092 
3093         removing_trailing_white_space(fcc);
3094 
3095 	/*-------- Stamp it with a current date -------*/
3096 	if(outgoing->date)			/* update old date */
3097 	  fs_give((void **)&(outgoing->date));
3098 
3099 	if(F_ON(F_QUELL_TIMEZONE, ps_global))
3100 	  mail_parameters(NULL, SET_DISABLE822TZTEXT, (void *) TRUE);
3101 
3102 	rfc822_date(tmp_20k_buf);		/* format and copy new date */
3103 	if(F_ON(F_QUELL_TIMEZONE, ps_global))
3104 	  mail_parameters(NULL, SET_DISABLE822TZTEXT, (void *) FALSE);
3105 
3106 	outgoing->date = (unsigned char *) cpystr(tmp_20k_buf);
3107 
3108 	/* Set return_path based on From which is going to be used */
3109 	if(outgoing->return_path)
3110 	  mail_free_address(&outgoing->return_path);
3111 
3112 	outgoing->return_path = rfc822_cpy_adr(outgoing->from);
3113 
3114 	/*
3115 	 * Don't ever believe the sender that is there.
3116 	 * If From doesn't look quite right, generate our own sender.
3117 	 */
3118 	if(outgoing->sender)
3119 	  mail_free_address(&outgoing->sender);
3120 
3121 	/*
3122 	 * If the LHS of the address doesn't match, or the RHS
3123 	 * doesn't match one of localdomain or hostname,
3124 	 * then add a sender line (really X-X-Sender).
3125 	 *
3126 	 * Don't add a personal_name since the user can change that.
3127 	 */
3128 	if(F_OFF(F_DISABLE_SENDER, ps_global)
3129 	   &&
3130 	   (!outgoing->from
3131 	    || !outgoing->from->mailbox
3132 	    || strucmp(outgoing->from->mailbox, ps_global->VAR_USER_ID) != 0
3133 	    || !outgoing->from->host
3134 	    || !(strucmp(outgoing->from->host, ps_global->localdomain) == 0
3135 	    || strucmp(outgoing->from->host, ps_global->hostname) == 0))){
3136 
3137 	    outgoing->sender	      = mail_newaddr();
3138 	    outgoing->sender->mailbox = cpystr(ps_global->VAR_USER_ID);
3139 	    outgoing->sender->host    = cpystr(ps_global->hostname);
3140 	}
3141 
3142 	if(ps_global->newthread){
3143 	   if(outgoing->in_reply_to) fs_give((void **)&outgoing->in_reply_to);
3144 	   if(outgoing->references) fs_give((void **)&outgoing->references);
3145 	}
3146 
3147         /*----- Message is edited, now decide what to do with it ----*/
3148 	if(editor_result & (COMP_SUSPEND | COMP_GOTHUP | COMP_CANCEL)){
3149             /*=========== Postpone or Interrupted message ============*/
3150 	    CONTEXT_S *fcc_cntxt = NULL;
3151 	    char       folder[MAXPATH+1];
3152 	    int	       fcc_result = 0;
3153 	    char       label[50];
3154 
3155 	    dprint((4, "pine_send:%s handling\n",
3156 		       (editor_result & COMP_SUSPEND)
3157 			   ? "SUSPEND"
3158 			   : (editor_result & COMP_GOTHUP)
3159 			       ? "HUP"
3160 			       : (editor_result & COMP_CANCEL)
3161 				   ? "CANCEL" : "HUH?"));
3162 	    if((editor_result & COMP_CANCEL)
3163 	       && (F_ON(F_QUELL_DEAD_LETTER, ps_global)
3164 	           || ps_global->deadlets == 0)){
3165 		q_status_message(SM_ORDER, 0, 3, "Message cancelled");
3166 		break;
3167 	    }
3168 
3169 	    /*
3170 	     * The idea here is to use the Fcc: writing facility
3171 	     * to append to the special postponed message folder...
3172 	     *
3173 	     * NOTE: the strategy now is to write the message and
3174 	     * all attachments as they exist at composition time.
3175 	     * In other words, attachments are postponed by value
3176 	     * and not reference.  This may change later, but we'll
3177 	     * need a local "message/external-body" type that
3178 	     * outgoing2strings knows how to properly set up for
3179 	     * the composer.  Maybe later...
3180 	     */
3181 
3182 	    label[0] = '\0';
3183 
3184 	    if(F_ON(F_COMPOSE_REJECTS_UNQUAL, ps_global)
3185 	       && (editor_result & COMP_SUSPEND)
3186 	       && (check_addresses(&header) == CA_BAD)){
3187 		/*--- Addresses didn't check out---*/
3188 		q_status_message(SM_ORDER, 7, 7,
3189 	      _("Not allowed to postpone message until addresses are qualified"));
3190 		continue;
3191             }
3192 
3193 	    /*
3194 	     * Build the local message copy so.
3195 	     *
3196 	     * In the HUP case, we'll write the bezerk delimiter by
3197 	     * hand and output the message directly into the folder.
3198 	     * It's not only faster, we don't have to worry about
3199 	     * c-client reentrance and less hands paw over the data so
3200 	     * there's less chance of a problem.
3201 	     *
3202 	     * In the Postpone case, just create it if the user wants to
3203 	     * and create a temporary storage object to write into.  */
3204   fake_hup:
3205 	    fcc_result = 0;
3206 	    lmc.all_written = lmc.text_only = lmc.text_written = 0;
3207 	    if(editor_result & (COMP_GOTHUP | COMP_CANCEL)){
3208 		int    newfile = 1;
3209 		time_t now = time((time_t *)0);
3210 
3211 #if defined(DOS) || defined(OS2)
3212 		/*
3213 		 * we can't assume anything about root or home dirs, so
3214 		 * just plunk it down in the same place as the pinerc
3215 		 */
3216 		if(!getenv("HOME")){
3217 		    char *lc = last_cmpnt(ps_global->pinerc);
3218 		    folder[0] = '\0';
3219 		    if(lc != NULL){
3220 			strncpy(folder,ps_global->pinerc,
3221 				MIN(lc-ps_global->pinerc,sizeof(folder)-1));
3222 			folder[MIN(lc-ps_global->pinerc,sizeof(folder)-1)]='\0';
3223 		    }
3224 
3225 		    strncat(folder, (editor_result & COMP_GOTHUP)
3226 				     ? INTERRUPTED_MAIL : DEADLETTER,
3227 			   sizeof(folder)-strlen(folder)-1);
3228 		}
3229 		else
3230 #endif
3231 		build_path(folder,
3232 			   ps_global->VAR_OPER_DIR
3233 			     ? ps_global->VAR_OPER_DIR : ps_global->home_dir,
3234 			   (editor_result & COMP_GOTHUP)
3235 			     ? INTERRUPTED_MAIL : DEADLETTER,
3236 			   sizeof(folder));
3237 
3238 		if(editor_result & COMP_CANCEL){
3239 		  char filename[MAXPATH+1], newfname[MAXPATH+1], nbuf[5];
3240 
3241 		  if(strlen(folder) + 1 < sizeof(filename))
3242 		    for(i = ps_global->deadlets - 1; i > 0 && i < 9; i--){
3243 			strncpy(filename, folder, sizeof(filename));
3244 			filename[sizeof(filename)-1] = '\0';
3245 			strncpy(newfname, filename, sizeof(newfname));
3246 			newfname[sizeof(newfname)-1] = '\0';
3247 
3248 			if(i > 1){
3249 			    snprintf(nbuf, sizeof(nbuf), "%d", i);
3250 			    nbuf[sizeof(nbuf)-1] = '\0';
3251 			    strncat(filename, nbuf,
3252 				    sizeof(filename)-strlen(filename)-1);
3253 			    filename[sizeof(filename)-1] = '\0';
3254 			}
3255 
3256 			snprintf(nbuf,  sizeof(nbuf), "%d", i+1);
3257 			nbuf[sizeof(nbuf)-1] = '\0';
3258 			strncat(newfname, nbuf,
3259 				sizeof(newfname)-strlen(newfname)-1);
3260 			newfname[sizeof(newfname)-1] = '\0';
3261 			(void) rename_file(filename, newfname);
3262 		    }
3263 
3264 		  our_unlink(folder);
3265 		}
3266 		else
3267 		  newfile = can_access(folder, ACCESS_EXISTS);
3268 
3269 		if((lmc.so = so_get(FCC_SOURCE, NULL, WRITE_ACCESS)) != NULL){
3270 		  if (outgoing->from){
3271 		    snprintf(tmp_20k_buf, SIZEOF_20KBUF, "%sFrom %s@%s %.24s\015\012",
3272 			      newfile ? "" : "\015\012",
3273 			      outgoing->from->mailbox,
3274 			      outgoing->from->host, ctime(&now));
3275 		    tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
3276 		    if(!so_puts(lmc.so, tmp_20k_buf)){
3277 		      if(editor_result & COMP_CANCEL)
3278 			q_status_message2(SM_ORDER | SM_DING, 3, 3,
3279 					  "Can't write \"%s\": %s",
3280 					  folder, error_description(errno));
3281 		      else
3282 			dprint((1, "* * * CAN'T WRITE %s: %s\n",
3283 			       folder ? folder : "?",
3284 			       error_description(errno)));
3285 		    }
3286 		  }
3287 		}
3288 	    }
3289 	    else{			/* Must be COMP_SUSPEND */
3290 		if(!ps_global->VAR_POSTPONED_FOLDER
3291 		   || !ps_global->VAR_POSTPONED_FOLDER[0]){
3292 		    q_status_message(SM_ORDER | SM_DING, 3, 3,
3293 				     _("No postponed file defined"));
3294 		    continue;
3295 		}
3296 
3297 		/*
3298 		 * Store the cursor position
3299 		 *
3300 		 * First find the header entry with the start_here
3301 		 * bit set, if any. This means the editor is telling
3302 		 * us to start on this header field next time.
3303 		 */
3304 		start_here_name = NULL;
3305 		for(pf = header.local; pf && pf->name; pf = pf->next)
3306 		  if(HE(pf) && HE(pf)->start_here){
3307 		      start_here_name = pf->name;
3308 		      break;
3309 		  }
3310 
3311 		/* If there wasn't one, ":" means we start in the body. */
3312 		if(!start_here_name || !*start_here_name)
3313 		  start_here_name = ":";
3314 
3315 		if(ps_global->VAR_FORM_FOLDER
3316 		   && ps_global->VAR_FORM_FOLDER[0]
3317 		   && postpone_prompt() == 'f'){
3318 		    strncpy(folder, ps_global->VAR_FORM_FOLDER,
3319 			    sizeof(folder)-1);
3320 		    folder[sizeof(folder)-1] = '\0';
3321 		    strncpy(label, "form letter", sizeof(label));
3322 		    label[sizeof(label)-1] = '\0';
3323 		}
3324 		else{
3325 		    strncpy(folder, ps_global->VAR_POSTPONED_FOLDER,
3326 			    sizeof(folder)-1);
3327 		    folder[sizeof(folder)-1] = '\0';
3328 		    strncpy(label, "postponed message", sizeof(label));
3329 		    label[sizeof(label)-1] = '\0';
3330 		}
3331 
3332 		lmc.so = open_fcc(folder,&fcc_cntxt, 1, NULL, NULL);
3333 	    }
3334 
3335 	    if(lmc.so){
3336 		size_t sz;
3337 		char *lmq = NULL;
3338 
3339 		/* copy fcc line to postponed or interrupted folder */
3340 	        if(pf_fcc)
3341 		  pf_fcc->localcopy = 1;
3342 
3343 		/* plug error into header for later display to user */
3344 		if((editor_result & ~0xff) && (lmq = last_message_queued()) != NULL){
3345 		    pf_err->writehdr  = 1;
3346 		    pf_err->localcopy = 1;
3347 		    pf_err->textbuf   = lmq;
3348 		}
3349 
3350 		/*
3351 		 * if reply, write (UID)folder header field so we can
3352 		 * later flag the replied-to message \\ANSWERED
3353 		 * DON'T save MSGNO's.
3354 		 */
3355 		if(reply && reply->uid){
3356 		    char uidbuf[MAILTMPLEN], *p;
3357 		    long i;
3358 
3359 		    for(i = 0L, p = tmp_20k_buf; reply->data.uid.msgs[i]; i++){
3360 			if(i)
3361 			  sstrncpy(&p, ",", SIZEOF_20KBUF-(p-tmp_20k_buf));
3362 
3363 			sstrncpy(&p,ulong2string(reply->data.uid.msgs[i]),SIZEOF_20KBUF-(p-tmp_20k_buf));
3364 		    }
3365 
3366 		    tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
3367 
3368 		    pf_uid->writehdr  = 1;
3369 		    pf_uid->localcopy = 1;
3370 		    snprintf(uidbuf, sizeof(uidbuf), "(%s%s%s)(%ld %lu %s)%s",
3371 			     reply->prefix ? int2string(strlen(reply->prefix))
3372 					   : (reply->forwarded) ? "": "0 ",
3373 			     reply->prefix ? " " : "",
3374 			     reply->prefix ? reply->prefix : "",
3375 			     i, reply->data.uid.validity,
3376 			     tmp_20k_buf, reply->mailbox);
3377 		    uidbuf[sizeof(uidbuf)-1] = '\0';
3378 		    pf_uid->textbuf   = cpystr(uidbuf);
3379 
3380 		    /*
3381 		     * Logically, this ought to be part of pf_uid, but this
3382 		     * was added later and so had to be in a separate header
3383 		     * for backwards compatibility.
3384 		     */
3385 		    pf_mbox->writehdr  = 1;
3386 		    pf_mbox->localcopy = 1;
3387 		    pf_mbox->textbuf   = cpystr(reply->origmbox
3388 						  ? reply->origmbox
3389 						  : reply->mailbox);
3390 		}
3391 
3392 		/* Save cursor position */
3393 		if(start_here_name && *start_here_name){
3394 		    char curposbuf[MAILTMPLEN];
3395 
3396 		    pf_curpos->writehdr  = 1;
3397 		    pf_curpos->localcopy = 1;
3398 		    snprintf(curposbuf, sizeof(curposbuf), "%s %ld", start_here_name,
3399 						 pbf->edit_offset);
3400 		    curposbuf[sizeof(curposbuf)-1] = '\0';
3401 		    pf_curpos->textbuf   = cpystr(curposbuf);
3402 		}
3403 
3404 		/*
3405 		 * Work around c-client reply-to bug. C-client will
3406 		 * return a reply_to in an envelope even if there is
3407 		 * no reply-to header field. We want to note here whether
3408 		 * the reply-to is real or not.
3409 		 */
3410 		if(outgoing->reply_to || hdr_is_in_list("reply-to", custom)){
3411 		    pf_ourrep->writehdr  = 1;
3412 		    pf_ourrep->localcopy = 1;
3413 		    if(outgoing->reply_to)
3414 		      pf_ourrep->textbuf   = cpystr("Full");
3415 		    else
3416 		      pf_ourrep->textbuf   = cpystr("Empty");
3417 		}
3418 
3419 		/* Save the role-specific smtp server */
3420 		if(role && role->smtp && role->smtp[0]){
3421 		    char  *q, *smtp = NULL;
3422 		    char **lp;
3423 		    size_t len = 0;
3424 
3425 		    /*
3426 		     * Turn the list of smtp servers into a space-
3427 		     * delimited list in a single string.
3428 		     */
3429 		    for(lp = role->smtp; (q = *lp) != NULL; lp++)
3430 		      len += (strlen(q) + 1);
3431 
3432 		    if(len){
3433 			smtp = (char *) fs_get(len * sizeof(char));
3434 			smtp[0] = '\0';
3435 			for(lp = role->smtp; (q = *lp) != NULL; lp++){
3436 			    if(lp != role->smtp)
3437 			      strncat(smtp, " ", len-strlen(smtp)-1);
3438 
3439 			    strncat(smtp, q, len-strlen(smtp)-1);
3440 			}
3441 
3442 			smtp[len-1] = '\0';
3443 		    }
3444 
3445 		    pf_smtp_server->writehdr  = 1;
3446 		    pf_smtp_server->localcopy = 1;
3447 		    if(smtp)
3448 		      pf_smtp_server->textbuf = smtp;
3449 		    else
3450 		      pf_smtp_server->textbuf = cpystr("");
3451 		}
3452 
3453 		/* Save the role-specific nntp server */
3454 		if(suggested_nntp_server ||
3455 		   (role && role->nntp && role->nntp[0])){
3456 		    char  *q, *nntp = NULL;
3457 		    char **lp;
3458 		    size_t len = 0;
3459 
3460 		    if(role && role->nntp && role->nntp[0]){
3461 			/*
3462 			 * Turn the list of nntp servers into a space-
3463 			 * delimited list in a single string.
3464 			 */
3465 			for(lp = role->nntp; (q = *lp) != NULL; lp++)
3466 			  len += (strlen(q) + 1);
3467 
3468 			if(len){
3469 			    nntp = (char *) fs_get(len * sizeof(char));
3470 			    nntp[0] = '\0';
3471 			    for(lp = role->nntp; (q = *lp) != NULL; lp++){
3472 				if(lp != role->nntp)
3473 				  strncat(nntp, " ", len-strlen(nntp)-1);
3474 
3475 				strncat(nntp, q, len-strlen(nntp)-1);
3476 			    }
3477 
3478 			    nntp[len-1] = '\0';
3479 			}
3480 		    }
3481 		    else
3482 		      nntp = cpystr(suggested_nntp_server);
3483 
3484 		    pf_nntp_server->writehdr  = 1;
3485 		    pf_nntp_server->localcopy = 1;
3486 		    if(nntp)
3487 		      pf_nntp_server->textbuf = nntp;
3488 		    else
3489 		      pf_nntp_server->textbuf = cpystr("");
3490 		}
3491 
3492 		/*
3493 		 * Write the list of custom headers to the
3494 		 * X-Our-Headers header so that we can recover the
3495 		 * list in redraft.
3496 		 */
3497 		sz = 0;
3498 		for(pf = header.custom; pf && pf->name; pf = pf->next)
3499 		  sz += strlen(pf->name) + 1;
3500 
3501 		if(sz){
3502 		    char *q;
3503 
3504 		    pf_ourhdrs->writehdr  = 1;
3505 		    pf_ourhdrs->localcopy = 1;
3506 		    pf_ourhdrs->textbuf = (char *)fs_get(sz);
3507 		    memset(pf_ourhdrs->textbuf, 0, sz);
3508 		    q = pf_ourhdrs->textbuf;
3509 		    for(pf = header.custom; pf && pf->name; pf = pf->next){
3510 			if(pf != header.custom)
3511 			  sstrncpy(&q, ",", sz-(q-pf_ourhdrs->textbuf));
3512 
3513 			sstrncpy(&q, pf->name, sz-(q-pf_ourhdrs->textbuf));
3514 		    }
3515 
3516 		    pf_ourhdrs->textbuf[sz-1] = '\0';;
3517 		}
3518 
3519 		/*
3520 		 * We need to make sure any header values that got cleared
3521 		 * get written to the postponed message (they won't if
3522 		 * pf->text is NULL).  Otherwise, we can't tell previously
3523 		 * non-existent custom headers or default values from
3524 		 * custom (or other) headers that got blanked in the
3525 		 * composer...
3526 		 */
3527 		for(pf = header.local; pf && pf->name; pf = pf->next)
3528 		  if(pf->type == FreeText && HE(pf) && !*(HE(pf)->realaddr))
3529 		    *(HE(pf)->realaddr) = cpystr("");
3530 
3531 		/*
3532 		 * We're saving the message for use later. It may be that the
3533 		 * characters in the message are not all convertible to the
3534 		 * user's posting_charmap. We'll save it as UTF-8 instead
3535 		 * and worry about that the next time they try to send it.
3536 		 * Use a different save pointer just to be sure we don't
3537 		 * mess up the other stuff. We should probably make the
3538 		 * charset an argument.
3539 		 *
3540 		 * We also need to fix the charset of the body part
3541 		 * the user is editing so that we can read it back
3542 		 * successfully when we resume the composition.
3543 		 */
3544 		ps_global->post_utf8 = 1;
3545 
3546 		{
3547 		    PARAMETER *pm;
3548 		    BODY *bp;
3549 		    if((*body)->type == TYPEMULTIPART)
3550 		      bp = &(*body)->nested.part->body;
3551 		    else
3552 		      bp = *body;
3553 
3554 		    for(pm = bp->parameter;
3555 			pm && strucmp(pm->attribute, "charset") != 0;
3556 			pm = pm->next)
3557 		      ;
3558 
3559 		    if(pm){
3560 			if(pm->value)
3561 			  fs_give((void **) &pm->value);
3562 
3563 			pm->value = cpystr("UTF-8");
3564 		    }
3565 		}
3566 
3567 		if(pine_rfc822_output(&header,*body,NULL,NULL) >= 0L){
3568 		    if(editor_result & (COMP_GOTHUP | COMP_CANCEL)){
3569 			char	*err;
3570 			STORE_S *hup_so;
3571 			gf_io_t	 gc, pc;
3572 			int      we_cancel = 0;
3573 
3574 			if(editor_result & COMP_CANCEL){
3575 			    snprintf(tmp_20k_buf, SIZEOF_20KBUF,
3576 				    "Saving to \"%s\"", folder);
3577 			    tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
3578 			    we_cancel = busy_cue((char *)tmp_20k_buf, NULL, 1);
3579 			}
3580 
3581 			if((hup_so =
3582 			    so_get(FileStar, folder, WRITE_ACCESS|OWNER_ONLY)) != NULL){
3583 			    gf_set_so_readc(&gc, lmc.so);
3584 			    gf_set_so_writec(&pc, hup_so);
3585 			    so_seek(lmc.so, 0L, 0); 	/* read msg copy and */
3586 			    so_seek(hup_so, 0L, 2);	/* append to folder  */
3587 			    gf_filter_init();
3588 			    gf_link_filter(gf_nvtnl_local, NULL);
3589 			    if(!(fcc_result = !(err = gf_pipe(gc, pc))))
3590 			      dprint((1, "*** PIPE FAILED: %s\n",
3591 					 err ? err : "?"));
3592 
3593 			    gf_clear_so_readc(lmc.so);
3594 			    gf_clear_so_writec(hup_so);
3595 			    so_give(&hup_so);
3596 			}
3597 			else
3598 			  dprint((1, "*** CAN'T CREATE %s: %s\n",
3599 				     folder ? folder : "?",
3600 				     error_description(errno)));
3601 
3602 			if(we_cancel)
3603 			  cancel_busy_cue(-1);
3604 		    }
3605 		    else
3606 		      fcc_result = write_fcc(folder, fcc_cntxt,
3607 					     lmc.so, NULL, label, NULL);
3608 		}
3609 
3610 		/* discontinue coerced UTF-8 posting */
3611 		ps_global->post_utf8 = 0;
3612 
3613 		so_give(&lmc.so);
3614 	    }
3615 	    else
3616 	      dprint((1, "***CAN'T ALLOCATE temp store: %s ",
3617 			 error_description(errno)));
3618 
3619 	    if(editor_result & COMP_GOTHUP){
3620 		/*
3621 		 * Special Hack #291: if any hi-byte bits are set in
3622 		 *		      editor's result, we put them there.
3623 		 */
3624 		if(editor_result & 0xff00)
3625 		  exit(editor_result >> 8);
3626 
3627 		dprint((1, "Save composition on HUP %sED\n",
3628 			   fcc_result ? "SUCCEED" : "FAIL"));
3629 		hup_signal();		/* Do what we normally do on SIGHUP */
3630 	    }
3631 	    else if((editor_result & COMP_SUSPEND) && fcc_result){
3632 		if(ps_global->VAR_FORM_FOLDER
3633 		   && ps_global->VAR_FORM_FOLDER[0]
3634 		   && !strcmp(folder, ps_global->VAR_FORM_FOLDER))
3635 		  q_status_message(SM_ORDER, 0, 3,
3636 	   _("Composition saved to Form Letter Folder. Select Compose to send."));
3637 		else
3638 		  q_status_message(SM_ORDER, 0, 3,
3639 			 _("Composition postponed. Select Compose to resume."));
3640 
3641                 break; /* postpone went OK, get out of here */
3642 	    }
3643 	    else if(editor_result & COMP_CANCEL){
3644 		char *lc = NULL;
3645 
3646 		if(fcc_result && folder)
3647 		  lc = last_cmpnt(folder);
3648 
3649 		q_status_message3(SM_ORDER, 0, 3,
3650 				  _("Message cancelled%s%s%s"),
3651 				  (lc && *lc) ? " and copied to \"" : "",
3652 				  (lc && *lc) ? lc : "",
3653 				  (lc && *lc) ? "\" file" : "");
3654 		break;
3655             }
3656 	    else{
3657 		q_status_message(SM_ORDER, 0, 4,
3658 		    _("Continuing composition.  Message not postponed or sent"));
3659 		body_start = 1;
3660 		continue; /* postpone failed, jump back in to composer */
3661             }
3662 	}
3663 	else{
3664 	    /*------ Must be sending mail or posting ! -----*/
3665 	    int	       result, valid_addr, continue_with_only_fcc = 0;
3666 	    CONTEXT_S *fcc_cntxt = NULL;
3667 
3668 	    result = 0;
3669 	    dprint((4, "=== sending: "));
3670 
3671             /* --- If posting, confirm with user ----*/
3672 	    if(outgoing->newsgroups && *outgoing->newsgroups
3673 	       && F_OFF(F_QUELL_EXTRA_POST_PROMPT, ps_global)
3674 	       && want_to(POST_PMT, 'n', 'n', NO_HELP, WT_NORM) == 'n'){
3675 		q_status_message(SM_ORDER, 0, 3, _("Message not posted"));
3676 		dprint((4, "no post, continuing\n"));
3677 		continue;
3678 	    }
3679 
3680 	    if(!(outgoing->to || outgoing->cc || outgoing->bcc || lcc_addr
3681 		 || outgoing->newsgroups)){
3682 		if(fcc && fcc[0]){
3683 		    if(F_OFF(F_AUTO_FCC_ONLY, ps_global) &&
3684 		       want_to(_("No recipients, really copy only to Fcc "),
3685 			       'n', 'n', h_send_fcc_only, WT_NORM) != 'y')
3686 		      continue;
3687 
3688 		    continue_with_only_fcc++;
3689 		}
3690 		else{
3691 		    q_status_message(SM_ORDER, 3, 4,
3692 				     _("No recipients specified!"));
3693 		    dprint((4, "no recip, continuing\n"));
3694 		    continue;
3695 		}
3696 	    }
3697 
3698 	    if((valid_addr = check_addresses(&header)) == CA_BAD){
3699 		/*--- Addresses didn't check out---*/
3700 		dprint((4, "addrs failed, continuing\n"));
3701 		continue;
3702 	    }
3703 
3704 	    if(F_ON(F_WARN_ABOUT_NO_TO_OR_CC, ps_global)
3705 	       && !continue_with_only_fcc
3706 	       && !(outgoing->to || outgoing->cc || lcc_addr
3707 		    || outgoing->newsgroups)
3708 	       && (want_to(_("No To, Cc, or Newsgroup specified, send anyway "),
3709 			   'n', 'n', h_send_check_to_cc, WT_NORM) != 'y')){
3710 		dprint((4, "No To or CC or Newsgroup, continuing\n"));
3711 		if(local_redraft_pos && local_redraft_pos != redraft_pos)
3712 		  free_redraft_pos(&local_redraft_pos);
3713 
3714 		local_redraft_pos
3715 			= (REDRAFT_POS_S *) fs_get(sizeof(*local_redraft_pos));
3716 		memset((void *) local_redraft_pos,0,sizeof(*local_redraft_pos));
3717 		local_redraft_pos->hdrname = cpystr(TONAME);
3718 		continue;
3719 	    }
3720 
3721 	    if(F_ON(F_WARN_ABOUT_NO_SUBJECT, ps_global)
3722 	       && check_for_subject(&header) == CF_MISSING){
3723 		dprint((4, "No subject, continuing\n"));
3724 		if(local_redraft_pos && local_redraft_pos != redraft_pos)
3725 		  free_redraft_pos(&local_redraft_pos);
3726 
3727 		local_redraft_pos
3728 			= (REDRAFT_POS_S *) fs_get(sizeof(*local_redraft_pos));
3729 		memset((void *) local_redraft_pos,0,sizeof(*local_redraft_pos));
3730 		local_redraft_pos->hdrname = cpystr(SUBJNAME);
3731 		continue;
3732 	    }
3733 
3734 	    if(F_ON(F_WARN_ABOUT_NO_FCC, ps_global)
3735 	       && check_for_fcc(fcc) == CF_MISSING){
3736 		dprint((4, "No fcc, continuing\n"));
3737 		if(local_redraft_pos && local_redraft_pos != redraft_pos)
3738 		  free_redraft_pos(&local_redraft_pos);
3739 
3740 		local_redraft_pos
3741 			= (REDRAFT_POS_S *) fs_get(sizeof(*local_redraft_pos));
3742 		memset((void *) local_redraft_pos,0,sizeof(*local_redraft_pos));
3743 		local_redraft_pos->hdrname = cpystr("Fcc");
3744 		continue;
3745 	    }
3746 
3747 	    set_last_fcc(fcc);
3748 
3749             /*---- Check out fcc -----*/
3750             if(fcc && *fcc){
3751 		/*
3752 		 * If special name "inbox" then replace it with the
3753 		 * real inbox path.
3754 		 */
3755 		if(ps_global->VAR_INBOX_PATH
3756 		   && strucmp(fcc, ps_global->inbox_name) == 0){
3757 		    char *replace_fcc;
3758 
3759 		    replace_fcc = cpystr(ps_global->VAR_INBOX_PATH);
3760 		    fs_give((void **)&fcc);
3761 		    fcc = replace_fcc;
3762 		}
3763 
3764 		lmc.all_written = lmc.text_written = 0;
3765 		/* lmc.text_only set on command line */
3766 	        if(!(lmc.so = open_fcc(fcc, &fcc_cntxt, 0, NULL, NULL))){
3767 		    /* ---- Open or allocation of fcc failed ----- */
3768 		    dprint((4,"can't open/allocate fcc, cont'g\n"));
3769 
3770 		    /*
3771 		     * Find field entry associated with fcc, and start
3772 		     * composer on it...
3773 		     */
3774 		    for(pf = header.local; pf && pf->name; pf = pf->next)
3775 		      if(pf->type == Fcc && HE(pf))
3776 			HE(pf)->start_here = 1;
3777 
3778 		    continue;
3779 		}
3780 		else
3781 		  so_truncate(lmc.so, fcc_size_guess(*body) + 2048);
3782             }
3783 	    else
3784 	      lmc.so = NULL;
3785 
3786             /*---- Take care of any requested prefiltering ----*/
3787 	    if(sending_filter_requested
3788 	       && !filter_message_text(sending_filter_requested, outgoing,
3789 				       *body, &orig_so, &header)){
3790 		q_status_message1(SM_ORDER, 3, 3,
3791 				 _("Problem filtering!  Nothing sent%s."),
3792 				 fcc ? " or saved to fcc" : "");
3793 		continue;
3794 	    }
3795 
3796             /*------ Actually post  -------*/
3797             if(outgoing->newsgroups){
3798 		char **alt_nntp = NULL, *alt_nntp_p[2];
3799 		if(((role && role->nntp)
3800 		    || suggested_nntp_server)){
3801 		    if(ps_global->FIX_NNTP_SERVER
3802 		       && ps_global->FIX_NNTP_SERVER[0])
3803 		      q_status_message(SM_ORDER | SM_DING, 5, 5,
3804 				       "Using nntp-server that is administratively fixed");
3805 		    else if(role && role->nntp)
3806 		      alt_nntp = role->nntp;
3807 		    else{
3808 			alt_nntp_p[0] = suggested_nntp_server;
3809 			alt_nntp_p[1] = NULL;
3810 			alt_nntp = alt_nntp_p;
3811 		    }
3812 		}
3813 		if(news_poster(&header, *body, alt_nntp, pipe_callback) < 0){
3814 		    dprint((1, "Post failed, continuing\n"));
3815 		    if(outgoing->message_id)
3816 		      fs_give((void **) &outgoing->message_id);
3817 
3818 		    outgoing->message_id = generate_message_id(role);
3819 
3820 		    continue;
3821 		}
3822 		else
3823 		  result |= P_NEWS_WIN;
3824 	    }
3825 
3826 	    /*
3827 	     * BUG: IF we've posted the message *and* an fcc was specified
3828 	     * then we've already got a neatly formatted message in the
3829 	     * lmc.so.  It'd be nice not to have to re-encode everything
3830 	     * to insert it into the smtp slot...
3831 	     */
3832 
3833 	    /*
3834 	     * Turn on "undisclosed recipients" header if no To or cc.
3835 	     */
3836             if(!(outgoing->to || outgoing->cc)
3837 	      && (outgoing->bcc || lcc_addr) && pf_nobody && pf_nobody->addr){
3838 		pf_nobody->writehdr  = 1;
3839 		pf_nobody->localcopy = 1;
3840 	    }
3841 
3842 	    if(priority_requested){
3843 		(void) set_priority_header(&header, priority_requested);
3844 		fs_give((void **) &priority_requested);
3845 	    }
3846 
3847 #if	defined(BACKGROUND_POST) && defined(SIGCHLD)
3848 	    /*
3849 	     * If requested, launch background posting...
3850 	     */
3851 	    if(background_requested && !(call_mailer_flags & CM_VERBOSE)){
3852 		ps_global->post = (POST_S *)fs_get(sizeof(POST_S));
3853 		memset(ps_global->post, 0, sizeof(POST_S));
3854 		if(fcc)
3855 		  ps_global->post->fcc = cpystr(fcc);
3856 
3857 		if((ps_global->post->pid = fork()) == 0){
3858 		    /*
3859 		     * Put us in new process group...
3860 		     */
3861 		    setpgrp(0, ps_global->post->pid);
3862 
3863 		    /* BUG: should fix argv[0] to indicate what we're up to */
3864 
3865 		    /*
3866 		     * If there are any live streams, pretend we never
3867 		     * knew them.  Problem is two processes writing
3868 		     * same server process.
3869 		     * This is not clean but we're just going to exit
3870 		     * right away anyway. We just want to be sure to leave
3871 		     * the stuff that the parent is going to use alone.
3872 		     * The next three lines will disable the re-use of the
3873 		     * existing streams and cause us to open a new one if
3874 		     * needed.
3875 		     */
3876 		    ps_global->mail_stream = NULL;
3877 		    ps_global->s_pool.streams = NULL;
3878 		    ps_global->s_pool.nstream = 0;
3879 
3880 		    /* quell any display output */
3881 		    ps_global->in_init_seq = 1;
3882 
3883 		    /*------- Actually mail the message ------*/
3884 		    if(valid_addr == CA_OK
3885 		       && (outgoing->to || outgoing->cc
3886 			   || outgoing->bcc || lcc_addr)){
3887 			char **alt_smtp = NULL;
3888 
3889 			if(role && role->smtp){
3890 			    if(ps_global->FIX_SMTP_SERVER
3891 			       && ps_global->FIX_SMTP_SERVER[0])
3892 			      q_status_message(SM_ORDER | SM_DING, 5, 5, "Use of a role-defined smtp-server is administratively prohibited");
3893 			    else
3894 			      alt_smtp = role->smtp;
3895 			}
3896 
3897 		        result |= (call_mailer(&header, *body, alt_smtp,
3898 					       call_mailer_flags,
3899 					       call_mailer_file_result,
3900 					       pipe_callback) > 0)
3901 				    ? P_MAIL_WIN : P_MAIL_LOSE;
3902 
3903 			if(result & P_MAIL_LOSE)
3904 			  mark_address_failure_for_pico(&header);
3905 		    }
3906 
3907 		    /*----- Was there an fcc involved? -----*/
3908 		    if(lmc.so){
3909 			/*------ Write it if at least something worked ------*/
3910 			if((result & (P_MAIL_WIN | P_NEWS_WIN))
3911 			   || (!(result & (P_MAIL_BITS | P_NEWS_BITS))
3912 			       && pine_rfc822_output(&header, *body,
3913 						     NULL, NULL))){
3914 			    char label[50];
3915 
3916 			    strncpy(label, "Fcc", sizeof(label));
3917 			    label[sizeof(label)-1] = '\0';
3918 			    if(strcmp(fcc, ps_global->VAR_DEFAULT_FCC)){
3919 				snprintf(label + 3, sizeof(label)-3, " to %s", fcc);
3920 				label[sizeof(label)-1] = '\0';
3921 			    }
3922 
3923 			    /*-- Now actually copy to fcc folder and close --*/
3924 			    result |= (write_fcc(fcc, fcc_cntxt, lmc.so,
3925 						 NULL, label,
3926 					      F_ON(F_MARK_FCC_SEEN, ps_global)
3927 						  ? "\\SEEN" : NULL))
3928 					? P_FCC_WIN : P_FCC_LOSE;
3929 			}
3930 			else if(!(result & (P_MAIL_BITS | P_NEWS_BITS))){
3931 			    q_status_message(SM_ORDER, 3, 5,
3932 					    _("Fcc Failed!.  No message saved."));
3933 			    dprint((1,
3934 				       "explicit fcc write failed!\n"));
3935 			    result |= P_FCC_LOSE;
3936 			}
3937 
3938 			so_give(&lmc.so);
3939 		    }
3940 
3941 		    if(result & (P_MAIL_LOSE | P_NEWS_LOSE | P_FCC_LOSE)){
3942 			/*
3943 			 * Encode child's result in hi-byte of
3944 			 * editor's result
3945 			 */
3946 			editor_result = ((result << 8) | COMP_GOTHUP);
3947 			goto fake_hup;
3948 		    }
3949 
3950 		    exit(result);
3951 		}
3952 
3953 		if(ps_global->post->pid > 0){
3954 		    q_status_message(SM_ORDER, 3, 3,
3955 				     _("Message handed off for posting"));
3956 		    break;		/* up to our child now */
3957 		}
3958 		else{
3959 		    q_status_message1(SM_ORDER | SM_DING, 3, 3,
3960 				      "Can't fork for send: %s",
3961 				      error_description(errno));
3962 		    if(ps_global->post->fcc)
3963 		      fs_give((void **) &ps_global->post->fcc);
3964 
3965 		    fs_give((void **) &ps_global->post);
3966 		}
3967 
3968 		if(lmc.so)	/* throw away unused store obj */
3969 		  so_give(&lmc.so);
3970 
3971 		if(outgoing->message_id)
3972 		  fs_give((void **) &outgoing->message_id);
3973 
3974 		outgoing->message_id = generate_message_id(role);
3975 
3976 		continue;		/* if we got here, there was a prob */
3977 	    }
3978 #endif /* BACKGROUND_POST */
3979 
3980             /*------- Actually mail the message ------*/
3981             if(valid_addr == CA_OK
3982 	       && (outgoing->to || outgoing->cc || outgoing->bcc || lcc_addr)){
3983 		char **alt_smtp = NULL;
3984 
3985 		if(role && role->smtp){
3986 		    if(ps_global->FIX_SMTP_SERVER
3987 		       && ps_global->FIX_SMTP_SERVER[0])
3988 		      q_status_message(SM_ORDER | SM_DING, 5, 5, "Use of a role-defined smtp-server is administratively prohibited");
3989 		    else
3990 		      alt_smtp = role->smtp;
3991 		}
3992 
3993 		result |= (call_mailer(&header, *body, alt_smtp,
3994 				       call_mailer_flags,
3995 				       call_mailer_file_result,
3996 				       pipe_callback) > 0)
3997 			    ? P_MAIL_WIN : P_MAIL_LOSE;
3998 
3999 		if(result & P_MAIL_LOSE)
4000 		  mark_address_failure_for_pico(&header);
4001 	    }
4002 
4003 	    /*----- Was there an fcc involved? -----*/
4004             if(lmc.so){
4005 		/*------ Write it if at least something worked ------*/
4006 		if((result & (P_MAIL_WIN | P_NEWS_WIN))
4007 		   || (!(result & (P_MAIL_BITS | P_NEWS_BITS))
4008 		       && pine_rfc822_output(&header, *body, NULL, NULL))){
4009 		    char label[50];
4010 
4011 		    strncpy(label, "Fcc", sizeof(label));
4012 		    label[sizeof(label)-1] = '\0';
4013 		    if(strcmp(fcc, ps_global->VAR_DEFAULT_FCC)){
4014 			snprintf(label + 3, sizeof(label)-3, " to %s", fcc);
4015 			label[sizeof(label)-1] = '\0';
4016 		    }
4017 
4018 		    /*-- Now actually copy to fcc folder and close --*/
4019 		    result |= (write_fcc(fcc, fcc_cntxt, lmc.so, NULL, label,
4020 					 F_ON(F_MARK_FCC_SEEN, ps_global)
4021 					    ? "\\SEEN" : NULL))
4022 				? P_FCC_WIN : P_FCC_LOSE;
4023 		}
4024 		else if(!(result & (P_MAIL_BITS | P_NEWS_BITS))){
4025 		    q_status_message(SM_ORDER,3,5,
4026 			_("Fcc Failed!.  No message saved."));
4027 		    dprint((1, "explicit fcc write failed!\n"));
4028 		    result |= P_FCC_LOSE;
4029 		}
4030 
4031 		so_give(&lmc.so);
4032 	    }
4033 
4034             /*----- Mail Post FAILED, back to composer -----*/
4035             if(result & (P_MAIL_LOSE | P_FCC_LOSE)){
4036 		dprint((1, "Send failed, continuing\n"));
4037 
4038 		if(result & P_FCC_LOSE){
4039 		    /*
4040 		     * Find field entry associated with fcc, and start
4041 		     * composer on it...
4042 		     */
4043 		    for(pf = header.local; pf && pf->name; pf = pf->next)
4044 		      if(pf->type == Fcc && HE(pf))
4045 			HE(pf)->start_here = 1;
4046 
4047 		    q_status_message(SM_ORDER | SM_DING, 3, 3,
4048 				     pine_send_status(result, fcc,
4049 						      tmp_20k_buf, SIZEOF_20KBUF, NULL));
4050 		}
4051 
4052 		if(outgoing->message_id)
4053 		  fs_give((void **) &outgoing->message_id);
4054 
4055 		outgoing->message_id = generate_message_id(role);
4056 
4057 		continue;
4058 	    }
4059 
4060 	    /*
4061 	     * If message sent *completely* successfully, there's a
4062 	     * reply struct AND we're allowed to write back state, do it.
4063 	     * But also protect against shifted message numbers due
4064 	     * to new mail arrival.  Since the number passed is based
4065 	     * on the real imap msg no, AND we're sure no expunge has
4066 	     * been done, just fix up the sorted number...
4067 	     */
4068 	    update_answered_flags(reply);
4069 
4070             /*----- Signed, sealed, delivered! ------*/
4071 	    q_status_message(SM_ORDER, 0, 3,
4072 			     pine_send_status(result, fcc, tmp_20k_buf, SIZEOF_20KBUF, NULL));
4073 
4074             break; /* All's well, pop out of here */
4075         }
4076     }
4077 
4078     if(orig_so)
4079       so_give(&orig_so);
4080 
4081     if(fcc)
4082       fs_give((void **)&fcc);
4083 
4084     free_body_particulars(bp);
4085 
4086     free_attachment_list(&pbf->attachments);
4087 
4088     standard_picobuf_teardown(pbf);
4089 
4090     for(i=0; i < fixed_cnt; i++){
4091 	if(pfields[i].textbuf)
4092 	  fs_give((void **)&pfields[i].textbuf);
4093 
4094 	fs_give((void **)&pfields[i].name);
4095     }
4096 
4097     if(lcc_addr)
4098       mail_free_address(&lcc_addr);
4099 
4100     if(nobody_addr)
4101       mail_free_address(&nobody_addr);
4102 
4103     free_prompts(header.custom);
4104     free_customs(header.custom);
4105     fs_give((void **)&pfields);
4106     free_headents(&headents);
4107     fs_give((void **)&sending_order);
4108     if(suggested_nntp_server)
4109       fs_give((void **)&suggested_nntp_server);
4110     if(title)
4111       fs_give((void **)&title);
4112 
4113     if(local_redraft_pos && local_redraft_pos != redraft_pos)
4114       free_redraft_pos(&local_redraft_pos);
4115 
4116     pbf = save_previous_pbuf;
4117     g_rolenick = NULL;
4118 
4119     dprint((4, "=== send returning ===\n"));
4120 }
4121 
4122 
4123 /*
4124  * Check for subject in outgoing message.
4125  *
4126  * Asks user whether to proceed with no subject.
4127  */
4128 int
check_for_subject(METAENV * header)4129 check_for_subject(METAENV *header)
4130 {
4131     PINEFIELD *pf;
4132     int        rv = CF_OK;
4133 
4134     for(pf = header->local; pf && pf->name; pf = pf->next)
4135       if(pf->type == Subject){
4136 	  if(pf->text && *pf->text && **pf->text)
4137 	    rv = CF_OK;
4138 	  else{
4139 	      if(want_to("No Subject, send anyway ",
4140 		         'n', 'n', h_send_check_subj, WT_NORM) == 'y')
4141 		rv = CF_OK;
4142 	      else
4143 		rv = CF_MISSING;
4144 	  }
4145 
4146 	  break;
4147       }
4148 
4149 
4150     return(rv);
4151 }
4152 
4153 
4154 /*
4155  * Check for fcc in outgoing message.
4156  *
4157  * Asks user whether to proceed with no fcc.
4158  */
4159 int
check_for_fcc(char * fcc)4160 check_for_fcc(char *fcc)
4161 {
4162     int        rv = CF_OK;
4163 
4164     if(fcc && *fcc)
4165       rv = CF_OK;
4166     else{
4167 	if(want_to("No Fcc, send anyway ", 'n', 'n', h_send_check_fcc, WT_NORM) == 'y')
4168 	  rv = CF_OK;
4169 	else
4170 	  rv = CF_MISSING;
4171     }
4172 
4173     return(rv);
4174 }
4175 
4176 
4177 /*
4178  * Confirm that the user wants to send to MAILER-DAEMON
4179  */
4180 int
confirm_daemon_send(void)4181 confirm_daemon_send(void)
4182 {
4183     return(want_to("Really send this message to the MAILER-DAEMON",
4184 		   'n', 'n', NO_HELP, WT_NORM) == 'y');
4185 }
4186 
4187 
4188 void
free_prompts(PINEFIELD * head)4189 free_prompts(PINEFIELD *head)
4190 {
4191     PINEFIELD *pf;
4192 
4193     for(pf = head; pf && pf->name; pf = pf->next){
4194 	if(HE(pf) && HE(pf)->prompt)
4195 	  fs_give((void **)& HE(pf)->prompt);
4196     }
4197 }
4198 
4199 
4200 int
postpone_prompt(void)4201 postpone_prompt(void)
4202 {
4203     static ESCKEY_S pstpn_form_opt[] = { {'p', 'p', "P", N_("Postponed Folder")},
4204 					 {'f', 'f', "F", N_("Form Letter Folder")},
4205 					 {-1, 0, NULL, NULL} };
4206 
4207     return(radio_buttons(PSTPN_FORM_PMT, -FOOTER_ROWS(ps_global),
4208 			 pstpn_form_opt, 'p', 0, NO_HELP, RB_FLUSH_IN));
4209 }
4210 
4211 
4212 /*
4213  * call__mailer_file_result - some results from call_mailer might be in a file.
4214  *			      dislplay that file.
4215  */
4216 void
call_mailer_file_result(char * filename,int style)4217 call_mailer_file_result(char *filename, int style)
4218 {
4219     if(filename){
4220 	if(style & CM_BR_VERBOSE){
4221 	    display_output_file(filename, "Verbose SMTP Interaction", NULL, DOF_BRIEF);
4222 	}
4223 	else{
4224 	    display_output_file(filename, "POSTING ERRORS", "Posting Error", DOF_EMPTY);
4225 	}
4226     }
4227 }
4228 
4229 void
mark_address_failure_for_pico(METAENV * header)4230 mark_address_failure_for_pico(METAENV *header)
4231 {
4232     PINEFIELD	       *pf;
4233     ADDRESS	       *a;
4234     int			error_count = 0;
4235     struct headerentry *last_he = NULL;
4236 
4237     for(pf = header->local; pf && pf->name; pf = pf->next)
4238       if(pf->type == Address && pf->rcptto && pf->addr && *pf->addr)
4239 	for(a = *pf->addr; a != NULL; a = a->next)
4240 	  if(a->error != NULL
4241 	     && error_count++ < MAX_ADDR_ERROR
4242 	     && (HE(pf))){
4243 	      if(last_he)	/* start last reported err */
4244 		last_he->start_here = 0;
4245 
4246 	      (last_he = HE(pf))->start_here = 1;
4247 	  }
4248 }
4249 
4250 
4251 
4252 /*
4253  * This is specialized routine. It assumes that the only things that we
4254  * care about restoring are the body type, subtype, encoding and the
4255  * state of the charset parameter. It also assumes that if the charset
4256  * parameter exists when we save it, it won't be removed later.
4257  */
4258 BODY_PARTICULARS_S *
save_body_particulars(struct mail_bodystruct * body)4259 save_body_particulars(struct mail_bodystruct *body)
4260 {
4261     BODY_PARTICULARS_S *bp;
4262     PARAMETER *pm;
4263 
4264     bp = (BODY_PARTICULARS_S *)fs_get(sizeof(BODY_PARTICULARS_S));
4265 
4266     bp->type      = body->type;
4267     bp->encoding  = body->encoding;
4268     bp->subtype   = body->subtype ? cpystr(body->subtype) : NULL;
4269     bp->parameter = body->parameter;
4270     for(pm = bp->parameter;
4271 	pm && strucmp(pm->attribute, "charset") != 0;
4272 	pm = pm->next)
4273       ;/* searching for possible charset parameter */
4274 
4275     if(pm){					/* found one */
4276 	bp->had_csp = 1;		/* saved body had charset parameter */
4277 	bp->charset = pm->value ? cpystr(pm->value) : NULL;
4278     }
4279     else{
4280 	bp->had_csp = 0;
4281 	bp->charset = NULL;
4282     }
4283 
4284     return(bp);
4285 }
4286 
4287 
4288 void
reset_body_particulars(BODY_PARTICULARS_S * bp,struct mail_bodystruct * body)4289 reset_body_particulars(BODY_PARTICULARS_S *bp, struct mail_bodystruct *body)
4290 {
4291     body->type     = bp->type;
4292     body->encoding = bp->encoding;
4293     if(body->subtype)
4294       fs_give((void **)&body->subtype);
4295 
4296     body->subtype  = bp->subtype ? cpystr(bp->subtype) : NULL;
4297 
4298     if(bp->parameter){
4299 	PARAMETER *pm, *pm_prev = NULL;
4300 
4301 	for(pm = body->parameter;
4302 	    pm && strucmp(pm->attribute, "charset") != 0;
4303 	    pm = pm->next)
4304 	  pm_prev = pm;
4305 
4306 	if(pm){				/* body has charset parameter */
4307 	    if(bp->had_csp){		/* reset to what it used to be */
4308 		if(pm->value)
4309 		  fs_give((void **)&pm->value);
4310 
4311 		pm->value = bp->charset ? cpystr(bp->charset) : NULL;
4312 	    }
4313 	    else{			/* remove charset parameter */
4314 		if(pm_prev)
4315 		  pm_prev->next = pm->next;
4316 		else
4317 		  body->parameter = pm->next;
4318 
4319 		mail_free_body_parameter(&pm);
4320 	    }
4321 	}
4322 	else{
4323 	    if(bp->had_csp){
4324 		/*
4325 		 * This can't happen because grope never removes
4326 		 * the charset parameter.
4327 		 */
4328 		q_status_message(SM_ORDER | SM_DING, 5, 5,
4329 "Programmer error: saved charset but no current charset param in pine_send");
4330 	    }
4331 	    /*
4332 	    else{
4333 		ok, still no parameter
4334 	    }
4335 	    */
4336 	}
4337     }
4338     else{
4339 	if(body->parameter)
4340 	  mail_free_body_parameter(&body->parameter);
4341 
4342 	body->parameter = NULL;
4343     }
4344 }
4345 
4346 
4347 void
free_body_particulars(BODY_PARTICULARS_S * bp)4348 free_body_particulars(BODY_PARTICULARS_S *bp)
4349 {
4350     if(bp){
4351 	if(bp->subtype)
4352 	  fs_give((void **)&bp->subtype);
4353 
4354 	if(bp->charset)
4355 	  fs_give((void **)&bp->charset);
4356 
4357 	fs_give((void **)&bp);
4358     }
4359 }
4360 
4361 
4362 /*----------------------------------------------------------------------
4363    Build a status message suitable for framing
4364 
4365 Returns: pointer to resulting buffer
4366   ---*/
4367 char *
pine_send_status(int result,char * fcc_name,char * buf,size_t buflen,int * goodorbad)4368 pine_send_status(int result, char *fcc_name, char *buf, size_t buflen, int *goodorbad)
4369 {
4370     int   avail = ps_global->ttyo->screen_cols - 2;
4371     int   fixedneed, need, lenfcc;
4372     char *part1, *part2, *part3, *part4, *part5;
4373     char  fbuf[MAILTMPLEN+1];
4374 
4375     part1 = (result & P_NEWS_WIN)
4376 	     ? "posted"
4377 	     : (result & P_NEWS_LOSE)
4378 	      ? "NOT POSTED"
4379 	      : "";
4380     part2 = ((result & P_NEWS_BITS) && (result & P_MAIL_BITS)
4381 	     && (result & P_FCC_BITS))
4382 	     ? ", "
4383 	     : ((result & P_NEWS_BITS) && (result & (P_MAIL_BITS | P_FCC_BITS)))
4384 	      ? " and "
4385 	      : "";
4386     part3 = (result & P_MAIL_WIN)
4387 	     ? "sent"
4388 	     : (result & P_MAIL_LOSE)
4389 	      ? "NOT SENT"
4390 	      : "";
4391     part4 = ((result & P_MAIL_BITS) && (result & P_FCC_BITS))
4392 	     ? " and "
4393 	     : "";
4394     part5 = ((result & P_FCC_WIN) && !(result & (P_MAIL_WIN | P_NEWS_WIN)))
4395 	     ? "ONLY copied to "
4396 	     : (result & P_FCC_WIN)
4397 	      ? "copied to "
4398 	      : (result & P_FCC_LOSE)
4399 	       ? "NOT copied to "
4400 	       : "";
4401     lenfcc = MIN(sizeof(fbuf)-1, (result & P_FCC_BITS) ? strlen(fcc_name) : 0);
4402 
4403     fixedneed = 9 + strlen(part1) + strlen(part2) + strlen(part3) +
4404 	strlen(part4) + strlen(part5);
4405     need = fixedneed + ((result & P_FCC_BITS) ? 2 : 0) + lenfcc;
4406 
4407     if(need > avail && fixedneed + 3 >= avail){
4408 	/* dots on end of fixed, no fcc */
4409 	snprintf(fbuf, sizeof(fbuf), "Message %s%s%s%s%s     ",
4410 		part1, part2, part3, part4, part5);
4411 	short_str(fbuf, buf, buflen, avail, EndDots);
4412     }
4413     else if(need > avail){
4414 	/* include whole fixed part, quotes and dots at end of fcc name */
4415 	if(lenfcc > 0)
4416 	  lenfcc = MAX(1, lenfcc-(need-avail));
4417 
4418 	snprintf(buf, buflen, "Message %s%s%s%s%s%s%s%s.",
4419 		part1, part2, part3, part4, part5,
4420 		(result & P_FCC_BITS) ? "\"" : "",
4421 		short_str((result & P_FCC_BITS) ? fcc_name : "",
4422 			  fbuf, sizeof(fbuf), lenfcc, FrontDots),
4423 		(result & P_FCC_BITS) ? "\"" : "");
4424     }
4425     else{
4426 	/* whole thing */
4427 	snprintf(buf, buflen, "Message %s%s%s%s%s%s%s%s.",
4428 		part1, part2, part3, part4, part5,
4429 		(result & P_FCC_BITS) ? "\"" : "",
4430 		(result & P_FCC_BITS) ? fcc_name : "",
4431 		(result & P_FCC_BITS) ? "\"" : "");
4432     }
4433 
4434     if(goodorbad)
4435       *goodorbad = (result & (P_MAIL_LOSE | P_NEWS_LOSE | P_FCC_LOSE)) == 0;
4436 
4437     return(buf);
4438 }
4439 
4440 /* Callback from Pico to set the conditions for Alpine to start a new thread
4441  */
4442 
4443 void
new_thread_on_blank_subject(void)4444 new_thread_on_blank_subject(void)
4445 {
4446   ps_global->newthread = F_ON(F_NEW_THREAD_ON_BLANK_SUBJECT, ps_global);
4447 }
4448 
4449 
4450 
4451 /*----------------------------------------------------------------------
4452     Call back for pico to insert the specified message's text
4453 
4454 Args: n -- message number to format
4455       f -- function to use to output the formatted message
4456 
4457 
4458 Returns: returns msg number formatted on success, zero on error.
4459 ----*/
4460 long
message_format_for_pico(long int n,int (* f)(int))4461 message_format_for_pico(long int n, int (*f) (int))
4462 {
4463     ENVELOPE *e;
4464     BODY     *b;
4465     char     *old_quote = NULL;
4466     long      rv = n;
4467 
4468     if(!(n > 0L && n <= mn_get_total(ps_global->msgmap)
4469        && (e = pine_mail_fetchstructure(ps_global->mail_stream,
4470 				        mn_m2raw(ps_global->msgmap, n), &b)))){
4471 	q_status_message(SM_ORDER|SM_DING,3,3,"Error inserting Message");
4472 	flush_status_messages(0);
4473 	return(0L);
4474     }
4475 
4476     /* temporarily assign a new quote string */
4477     old_quote = pbf->quote_str;
4478     pbf->quote_str = reply_quote_str(e);
4479 
4480     /* build separator line */
4481     reply_delimiter(e, NULL, f);
4482 
4483     /* actually write message text */
4484     if(!format_message(mn_m2raw(ps_global->msgmap, n), e, b, NULL,
4485 		       FM_NEW_MESS | FM_DISPLAY | FM_NOCOLOR | FM_NOINDENT, f)){
4486 	q_status_message(SM_ORDER|SM_DING,3,3,"Error inserting Message");
4487 	flush_status_messages(0);
4488 	rv = 0L;
4489     }
4490 
4491     fs_give((void **)&pbf->quote_str);
4492     pbf->quote_str = old_quote;
4493     return(rv);
4494 }
4495 
4496 
4497 /*----------------------------------------------------------------------
4498     Call back for pico to prompt the user for exit confirmation
4499 
4500 Args: dflt -- default answer for confirmation prompt
4501 
4502 Returns: either NULL if the user accepts exit, or string containing
4503 	 reason why the user declined.
4504 ----*/
4505 int
send_exit_for_pico(struct headerentry * he,void (* redraw_pico)(void),int allow_flowed,char ** result)4506 send_exit_for_pico(struct headerentry *he, void (*redraw_pico)(void), int allow_flowed,
4507 		   char **result)
4508 {
4509     int	       i, rv, c, verbose_label = 0, bg_label = 0, old_suspend;
4510     int        dsn_label = 0, fcc_label = 0, lparen;
4511     int        flowing_label = 0, double_rad;
4512     char      *rstr = NULL, *p, *lc, *optp;
4513     char       dsn_string[30];
4514     void     (*redraw)(void) = ps_global->redrawer;
4515     ESCKEY_S   opts[18];
4516     struct filters {
4517 	char  *filter;
4518 	int    index;
4519 	struct filters *prev, *next;
4520     } *filters = NULL, *fp;
4521 
4522     sending_filter_requested = NULL;
4523     call_mailer_flags	     = 0;
4524     background_requested     = 0;
4525     flowing_requested        = allow_flowed ? 1 : 0;
4526     lmc.text_only            = F_ON(F_NO_FCC_ATTACH, ps_global) != 0;
4527     if(priority_requested)
4528       fs_give((void **) &priority_requested);
4529 
4530     if(background_posting(FALSE)){
4531 	if(result)
4532 	  *result = "Can't send while background posting. Use postpone.";
4533 
4534 	return(1);
4535     }
4536 
4537     if(F_ON(F_SEND_WO_CONFIRM, ps_global)){
4538 	if(result)
4539 	  *result = NULL;
4540 
4541 	return(0);
4542     }
4543 
4544     ps_global->redrawer = redraw_pico;
4545 
4546     if((old_suspend = F_ON(F_CAN_SUSPEND, ps_global)) != 0)
4547       (void) F_SET(F_CAN_SUSPEND, ps_global, 0);
4548 
4549     /*
4550      * Build list of available filters...
4551      */
4552     for(i=0; ps_global->VAR_SEND_FILTER && ps_global->VAR_SEND_FILTER[i]; i++){
4553 	for(p = ps_global->VAR_SEND_FILTER[i];
4554 	    *p && !isspace((unsigned char)*p); p++)
4555 	  ;
4556 
4557 	c  = *p;
4558 	*p = '\0';
4559 	if(!(is_absolute_path(ps_global->VAR_SEND_FILTER[i])
4560 	     && can_access(ps_global->VAR_SEND_FILTER[i],EXECUTE_ACCESS) ==0)){
4561 	    *p = c;
4562 	    continue;
4563 	}
4564 
4565 	fp	   = (struct filters *)fs_get(sizeof(struct filters));
4566 	fp->index  = i;
4567 	if((lc = last_cmpnt(ps_global->VAR_SEND_FILTER[i])) != NULL){
4568 	    fp->filter = cpystr(lc);
4569 	}
4570 	else if((p - ps_global->VAR_SEND_FILTER[i]) > 20){
4571 	    snprintf(tmp_20k_buf, SIZEOF_20KBUF, "...%s", p - 17);
4572 	    tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
4573 	    fp->filter = cpystr(tmp_20k_buf);
4574 	}
4575 	else
4576 	  fp->filter = cpystr(ps_global->VAR_SEND_FILTER[i]);
4577 
4578 	*p = c;
4579 
4580 	if(filters){
4581 	    fp->next	   = filters;
4582 	    fp->prev	   = filters->prev;
4583 	    fp->prev->next = filters->prev = fp;
4584 	}
4585 	else{
4586 	    filters = (struct filters *)fs_get(sizeof(struct filters));
4587 	    filters->index  = -1;
4588 	    filters->filter = NULL;
4589 	    filters->next = filters->prev = fp;
4590 	    fp->next = fp->prev = filters;
4591 	}
4592     }
4593 
4594     i = 0;
4595     opts[i].ch      = 'y';
4596     opts[i].rval    = 'y';
4597     opts[i].name    = "Y";
4598     opts[i++].label = N_("Yes");
4599 
4600     opts[i].ch      = 'n';
4601     opts[i].rval    = 'n';
4602     opts[i].name    = "N";
4603     opts[i++].label = N_("No");
4604 
4605     if(filters){
4606 	/* set global_filter_pointer to desired filter or NULL if none */
4607 	/* prepare two keymenu slots for selecting filter */
4608 	opts[i].ch      = ctrl('P');
4609 	opts[i].rval    = 10;
4610 	opts[i].name    = "^P";
4611 	opts[i++].label = N_("Prev Filter");
4612 
4613 	opts[i].ch      = ctrl('N');
4614 	opts[i].rval    = 11;
4615 	opts[i].name    = "^N";
4616 	opts[i++].label = N_("Next Filter");
4617 
4618 	if(F_ON(F_FIRST_SEND_FILTER_DFLT, ps_global))
4619 	  filters = filters->next;
4620     }
4621 
4622     if(F_ON(F_VERBOSE_POST, ps_global)){
4623 	/* setup keymenu slot to toggle verbose mode */
4624 	opts[i].ch    = ctrl('W');
4625 	opts[i].rval  = 12;
4626 	opts[i].name  = "^W";
4627 	verbose_label = i++;
4628     }
4629 
4630     if(allow_flowed){
4631 	/* setup keymenu slot to toggle flowed mode */
4632 	opts[i].ch    = ctrl('V');
4633 	opts[i].rval  = 22;
4634 	opts[i].name  = "^V";
4635 	flowing_label = i++;
4636 	flowing_requested = 1;
4637     }
4638 
4639     if(F_ON(F_NO_FCC_ATTACH, ps_global)){
4640 	/* setup keymenu slot to toggle attacment on fcc */
4641 	opts[i].ch      = ctrl('F');
4642 	opts[i].rval    = 21;
4643 	opts[i].name    = "^F";
4644 	fcc_label       = i++;
4645     }
4646 
4647 #if	defined(BACKGROUND_POST) && defined(SIGCHLD)
4648     if(F_ON(F_BACKGROUND_POST, ps_global)){
4649 	opts[i].ch    = ctrl('R');
4650 	opts[i].rval  = 15;
4651 	opts[i].name  = "^R";
4652 	bg_label = i++;
4653     }
4654 #endif
4655 
4656     opts[i].ch      = 'p';
4657     opts[i].rval    = 'p';
4658     opts[i].name    = "P";
4659     opts[i++].label = N_("Priority");
4660 
4661 #ifdef SMIME
4662     if(F_OFF(F_DONT_DO_SMIME, ps_global)){
4663     	opts[i].ch  	= 'e';
4664 	opts[i].rval	= 'e';
4665 	opts[i].name	= "E";
4666 	opts[i++].label	= "Encrypt";
4667 
4668     	opts[i].ch  	= 'g';
4669 	opts[i].rval	= 'g';
4670 	opts[i].name	= "G";
4671 	opts[i++].label	= "Sign";
4672 
4673 	if(ps_global->smime){
4674 	    ps_global->smime->do_encrypt = F_ON(F_ENCRYPT_DEFAULT_ON, ps_global);
4675 	    ps_global->smime->do_sign = F_ON(F_SIGN_DEFAULT_ON, ps_global);
4676 	}
4677     }
4678 #endif
4679 
4680     double_rad = i;
4681 
4682     if(F_ON(F_DSN, ps_global)){
4683 	/* setup keymenu slots to toggle dsn bits */
4684 	opts[i].ch      = 'd';
4685 	opts[i].rval    = 'd';
4686 	opts[i].name    = "D";
4687 	opts[i].label   = N_("DSNOpts");
4688 	dsn_label       = i++;
4689 	opts[i].ch      = -2;
4690 	opts[i].rval    = 's';
4691 	opts[i].name    = "S";
4692 	opts[i++].label = "";
4693 	opts[i].ch      = -2;
4694 	opts[i].rval    = 'x';
4695 	opts[i].name    = "X";
4696 	opts[i++].label = "";
4697 	opts[i].ch      = -2;
4698 	opts[i].rval    = 'h';
4699 	opts[i].name    = "H";
4700 	opts[i++].label = "";
4701     }
4702 
4703     if(filters){
4704 	opts[i].ch      = KEY_UP;
4705 	opts[i].rval    = 10;
4706 	opts[i].name    = "";
4707 	opts[i++].label = "";
4708 
4709 	opts[i].ch      = KEY_DOWN;
4710 	opts[i].rval    = 11;
4711 	opts[i].name    = "";
4712 	opts[i++].label = "";
4713     }
4714 
4715     opts[i].ch = -1;
4716 
4717     fix_windsize(ps_global);
4718 
4719     while(1){
4720 	if(filters && filters->filter && (p = strindex(filters->filter, ' ')))
4721 	  *p = '\0';
4722 	else
4723 	  p = NULL;
4724 
4725 	lparen = 0;
4726 	strncpy(tmp_20k_buf, "Send message", SIZEOF_20KBUF);
4727 	tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
4728 	optp = tmp_20k_buf + strlen(tmp_20k_buf);
4729 
4730 	if(F_ON(F_NO_FCC_ATTACH, ps_global) && !lmc.text_only)
4731 	  sstrncpy(&optp, " and Fcc Atmts", SIZEOF_20KBUF-(optp-tmp_20k_buf));
4732 
4733 	if(allow_flowed && !flowing_requested){
4734 	    if((optp-tmp_20k_buf)+2 < SIZEOF_20KBUF){
4735 		if(!lparen){
4736 		  *optp++ = ' ';
4737 		  *optp++ = '(';
4738 		  lparen++;
4739 		}
4740 		else
4741 		  *optp++ = ' ';
4742 	    }
4743 
4744 	    sstrncpy(&optp, "not flowed", SIZEOF_20KBUF-(optp-tmp_20k_buf));
4745 	}
4746 
4747 	if(filters){
4748 	    if((optp-tmp_20k_buf)+2 < SIZEOF_20KBUF){
4749 		if(!lparen){
4750 		  *optp++ = ' ';
4751 		  *optp++ = '(';
4752 		  lparen++;
4753 		}
4754 		else{
4755 		    *optp++ = ',';
4756 		    *optp++ = ' ';
4757 		}
4758 	    }
4759 
4760 	    if(filters->filter){
4761 		sstrncpy(&optp, "filtered thru \"", SIZEOF_20KBUF-(optp-tmp_20k_buf));
4762 		sstrncpy(&optp, filters->filter, SIZEOF_20KBUF-(optp-tmp_20k_buf));
4763 		if((optp-tmp_20k_buf) < SIZEOF_20KBUF)
4764 		  *optp++ = '\"';
4765 	    }
4766 	    else
4767 	      sstrncpy(&optp, "unfiltered", SIZEOF_20KBUF-(optp-tmp_20k_buf));
4768 	}
4769 
4770 	if((call_mailer_flags & CM_VERBOSE) || background_requested){
4771 	    if((optp-tmp_20k_buf)+2 < SIZEOF_20KBUF){
4772 		if(!lparen){
4773 		  *optp++ = ' ';
4774 		  *optp++ = '(';
4775 		  lparen++;
4776 		}
4777 		else
4778 		  *optp++ = ' ';
4779 	    }
4780 
4781 	    sstrncpy(&optp, "in ", SIZEOF_20KBUF-(optp-tmp_20k_buf));
4782 	    if(call_mailer_flags & CM_VERBOSE)
4783 	      sstrncpy(&optp, "verbose ", SIZEOF_20KBUF-(optp-tmp_20k_buf));
4784 
4785 	    if(background_requested)
4786 	      sstrncpy(&optp, "background ", SIZEOF_20KBUF-(optp-tmp_20k_buf));
4787 
4788 	    sstrncpy(&optp, "mode", SIZEOF_20KBUF-(optp-tmp_20k_buf));
4789 	}
4790 
4791 	if(g_rolenick && !(he && he[N_FROM].dirty)){
4792 	    if((optp-tmp_20k_buf)+2 < SIZEOF_20KBUF){
4793 		if(!lparen){
4794 		  *optp++ = ' ';
4795 		  *optp++ = '(';
4796 		  lparen++;
4797 		}
4798 		else
4799 		  *optp++ = ' ';
4800 	    }
4801 
4802 	    sstrncpy(&optp, "as \"", SIZEOF_20KBUF-(optp-tmp_20k_buf));
4803 	    sstrncpy(&optp, g_rolenick, SIZEOF_20KBUF-(optp-tmp_20k_buf));
4804 	    sstrncpy(&optp, "\"", SIZEOF_20KBUF-(optp-tmp_20k_buf));
4805 	}
4806 
4807 	if(call_mailer_flags & CM_DSN_SHOW){
4808 	    if((optp-tmp_20k_buf)+2 < SIZEOF_20KBUF){
4809 		if(!lparen){
4810 		  *optp++ = ' ';
4811 		  *optp++ = '(';
4812 		  lparen++;
4813 		}
4814 		else{
4815 		    *optp++ = ',';
4816 		    *optp++ = ' ';
4817 		}
4818 	    }
4819 
4820 	    sstrncpy(&optp, dsn_string, SIZEOF_20KBUF-(optp-tmp_20k_buf));
4821 	}
4822 
4823 #ifdef SMIME
4824     	if(ps_global->smime && ps_global->smime->do_encrypt){
4825 	    if((optp-tmp_20k_buf)+2 < SIZEOF_20KBUF){
4826 		if(!lparen){
4827 		    *optp++ = ' ';
4828 		    *optp++ = '(';
4829 		    lparen++;
4830 		}
4831 		else{
4832 		    *optp++ = ',';
4833 		    *optp++ = ' ';
4834 		}
4835 	    }
4836 
4837 	    sstrncpy(&optp, "Encrypted", SIZEOF_20KBUF-(optp-tmp_20k_buf));
4838 	}
4839 
4840     	if(ps_global->smime && ps_global->smime->do_sign){
4841 	    if((optp-tmp_20k_buf)+2 < SIZEOF_20KBUF){
4842 		if(!lparen){
4843 		    *optp++ = ' ';
4844 		    *optp++ = '(';
4845 		    lparen++;
4846 		}
4847 		else{
4848 		    *optp++ = ',';
4849 		    *optp++ = ' ';
4850 		}
4851 	    }
4852 
4853 	    sstrncpy(&optp, "Signed", SIZEOF_20KBUF-(optp-tmp_20k_buf));
4854 	}
4855 #endif
4856 
4857 	if(lparen && (optp-tmp_20k_buf) < SIZEOF_20KBUF)
4858 	  *optp++ = ')';
4859 
4860 	sstrncpy(&optp, "? ", SIZEOF_20KBUF-(optp-tmp_20k_buf));
4861 	tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
4862 
4863 	if(p)
4864 	  *p = ' ';
4865 
4866 	if(flowing_label)
4867 	  opts[flowing_label].label = flowing_requested ? N_("NoFlow") : N_("Flow");
4868 
4869 	if(verbose_label)
4870 	  opts[verbose_label].label = (call_mailer_flags & CM_VERBOSE) ? N_("Normal") : N_("Verbose");
4871 
4872 	if(bg_label)
4873 	  opts[bg_label].label = background_requested
4874 				   ? N_("Foreground") : N_("Background");
4875 
4876 	if(fcc_label)
4877 	  opts[fcc_label].label = lmc.text_only ? N_("Fcc Attchmnts")
4878 						: N_("No Fcc Atmts ");
4879 
4880 	if(F_ON(F_DSN, ps_global)){
4881 	    if(call_mailer_flags & CM_DSN_SHOW){
4882 		opts[dsn_label].label   = (call_mailer_flags & CM_DSN_DELAY)
4883 					   ? N_("NoDelay") : N_("Delay");
4884 		opts[dsn_label+1].ch    = 's';
4885 		opts[dsn_label+1].label = (call_mailer_flags & CM_DSN_SUCCESS)
4886 					   ? N_("NoSuccess") : N_("Success");
4887 		opts[dsn_label+2].ch    = 'x';
4888 		opts[dsn_label+2].label = (call_mailer_flags & CM_DSN_NEVER)
4889 					   ? N_("ErrRets") : N_("NoErrRets");
4890 		opts[dsn_label+3].ch    = 'h';
4891 		opts[dsn_label+3].label = (call_mailer_flags & CM_DSN_FULL)
4892 					   ? N_("RetHdrs") : N_("RetFull");
4893 	    }
4894 	}
4895 
4896 	if(double_rad +
4897 	   ((call_mailer_flags & CM_DSN_SHOW)
4898 	       ? 4 : F_ON(F_DSN, ps_global) ? 1 : 0) > 11)
4899 	  rv = double_radio_buttons(tmp_20k_buf, -FOOTER_ROWS(ps_global), opts,
4900 			   'y', 'z',
4901 			   (F_ON(F_DSN, ps_global) && allow_flowed)
4902 					          ? h_send_prompt_dsn_flowed :
4903 			    F_ON(F_DSN, ps_global) ? h_send_prompt_dsn       :
4904 			     allow_flowed           ? h_send_prompt_flowed   :
4905 						       h_send_prompt,
4906 			   RB_NORM);
4907 	else
4908 	  rv = radio_buttons(tmp_20k_buf, -FOOTER_ROWS(ps_global), opts,
4909 			   'y', 'z',
4910 			   (double_rad +
4911 			    ((call_mailer_flags & CM_DSN_SHOW)
4912 				? 4 : F_ON(F_DSN, ps_global) ? 1 : 0) == 11)
4913 				   ? NO_HELP :
4914 			   (F_ON(F_DSN, ps_global) && allow_flowed)
4915 					          ? h_send_prompt_dsn_flowed :
4916 			    F_ON(F_DSN, ps_global) ? h_send_prompt_dsn       :
4917 			     allow_flowed           ? h_send_prompt_flowed   :
4918 						       h_send_prompt,
4919 			   RB_NORM);
4920 
4921 	if(rv == 'y'){				/* user ACCEPTS! */
4922 	    break;
4923 	}
4924 	else if(rv == 'n'){			/* Declined! */
4925 	    rstr = _("No Message Sent");
4926 	    break;
4927 	}
4928 	else if(rv == 'z'){			/* Cancelled! */
4929 	    rstr = _("Send Cancelled");
4930 	    break;
4931 	}
4932 	else if(rv == 10){			/* PREVIOUS filter */
4933 	    filters = filters->prev;
4934 	}
4935 	else if(rv == 11){			/* NEXT filter */
4936 	    filters = filters->next;
4937 	}
4938 	else if(rv == 21){
4939 	    lmc.text_only = !lmc.text_only;
4940 	}
4941 	else if(rv == 12){			/* flip verbose bit */
4942 	    if(call_mailer_flags & CM_VERBOSE)
4943 	      call_mailer_flags &= ~CM_VERBOSE;
4944 	    else
4945 	      call_mailer_flags |= CM_VERBOSE;
4946 
4947 	    if((call_mailer_flags & CM_VERBOSE) && background_requested)
4948 	      background_requested = 0;
4949 	}
4950 	else if(rv == 22){			/* flip flowing bit */
4951 	    flowing_requested = !flowing_requested;
4952 	}
4953 	else if(rv == 15){
4954 	    if((background_requested = !background_requested)
4955 	       && (call_mailer_flags & CM_VERBOSE))
4956 	      call_mailer_flags &= ~CM_VERBOSE;	/* clear verbose */
4957 	}
4958 	else if(call_mailer_flags & CM_DSN_SHOW){
4959 	    if(rv == 's'){			/* flip success bit */
4960 		call_mailer_flags ^= CM_DSN_SUCCESS;
4961 		/* turn off related bits */
4962 		if(call_mailer_flags & CM_DSN_SUCCESS)
4963 		  call_mailer_flags &= ~(CM_DSN_NEVER);
4964 	    }
4965 	    else if(rv == 'd'){			/* flip delay bit */
4966 		call_mailer_flags ^= CM_DSN_DELAY;
4967 		/* turn off related bits */
4968 		if(call_mailer_flags & CM_DSN_DELAY)
4969 		  call_mailer_flags &= ~(CM_DSN_NEVER);
4970 	    }
4971 	    else if(rv == 'x'){			/* flip never bit */
4972 		call_mailer_flags ^= CM_DSN_NEVER;
4973 		/* turn off related bits */
4974 		if(call_mailer_flags & CM_DSN_NEVER)
4975 		  call_mailer_flags &= ~(CM_DSN_SUCCESS | CM_DSN_DELAY);
4976 	    }
4977 	    else if(rv == 'h'){			/* flip full bit */
4978 		call_mailer_flags ^= CM_DSN_FULL;
4979 	    }
4980 	}
4981 	else if(rv == 'd'){			/* show dsn options */
4982 	    /*
4983 	     * When you turn on DSN, the default is to notify on
4984 	     * failure, success, or delay; and to return the whole
4985 	     * body on failure.
4986 	     */
4987 	    call_mailer_flags |= (CM_DSN_SHOW | CM_DSN_SUCCESS | CM_DSN_DELAY | CM_DSN_FULL);
4988 	}
4989 	else if(rv == 'p'){			/* choose X-Priority */
4990 	    char *prio;
4991 
4992 	    prio = choose_a_priority(priority_requested);
4993 	    if((ps_global->redrawer = redraw_pico) != NULL){
4994 		(*ps_global->redrawer)();
4995 		fix_windsize(ps_global);
4996 	    }
4997 
4998 	    if(prio){
4999 		if(priority_requested)
5000 		  fs_give((void **) &priority_requested);
5001 
5002 		if(prio[0])
5003 		  priority_requested = prio;
5004 		else
5005 		  fs_give((void **) &prio);
5006 	    }
5007 	}
5008 #ifdef SMIME
5009 	else if(rv=='e'){
5010 	    if(ps_global->smime)
5011 	      ps_global->smime->do_encrypt = !ps_global->smime->do_encrypt;
5012 	}
5013 	else if(rv=='g'){
5014 	    if(ps_global->smime)
5015 	      ps_global->smime->do_sign = !ps_global->smime->do_sign;
5016 	}
5017 #endif
5018 
5019 	snprintf(dsn_string, sizeof(dsn_string), "DSN requested[%s%s%s%s]",
5020 		(call_mailer_flags & CM_DSN_NEVER)
5021 		  ? "Never" : "F",
5022 		(call_mailer_flags & CM_DSN_DELAY)
5023 		  ? "D" : "",
5024 		(call_mailer_flags & CM_DSN_SUCCESS)
5025 		  ? "S" : "",
5026 		(call_mailer_flags & CM_DSN_NEVER)
5027 		  ? ""
5028 		  : (call_mailer_flags & CM_DSN_FULL) ? "-Full"
5029 					       : "-Hdrs");
5030 	dsn_string[sizeof(dsn_string)-1] = '\0';
5031     }
5032 
5033     /* remember selection */
5034     if(filters && filters->index > -1)
5035       sending_filter_requested = ps_global->VAR_SEND_FILTER[filters->index];
5036 
5037     if(filters){
5038 	filters->prev->next = NULL;			/* tie off list */
5039 	while(filters){				/* then free it */
5040 	    fp = filters->next;
5041 	    if(filters->filter)
5042 	      fs_give((void **)&filters->filter);
5043 
5044 	    fs_give((void **)&filters);
5045 	    filters = fp;
5046 	}
5047     }
5048 
5049     if(old_suspend)
5050       (void) F_SET(F_CAN_SUSPEND, ps_global, 1);
5051 
5052     if(result)
5053       *result = rstr;
5054 
5055     ps_global->redrawer = redraw;
5056 
5057     return((rstr == NULL) ? 0 : 1);
5058 }
5059 
5060 
5061 /*
5062  * Allow user to choose a priority for sending.
5063  *
5064  * Returns an allocated priority on success, NULL otherwise.
5065  */
5066 char *
choose_a_priority(char * default_val)5067 choose_a_priority(char *default_val)
5068 {
5069     char      *choice = NULL;
5070     char     **priority_list, **lp;
5071     char      *starting_val = NULL;
5072     char      *none;
5073     int        i, cnt;
5074     PRIORITY_S *p;
5075 
5076     for(cnt = 0, p = priorities; p && p->desc; p++)
5077       cnt++;
5078 
5079     cnt++;	/* for NONE entry */
5080     lp = priority_list = (char **) fs_get((cnt + 1) * sizeof(*priority_list));
5081     memset(priority_list, 0, (cnt+1) * sizeof(*priority_list));
5082 
5083     for(i = 0, p = priorities; p && p->desc; p++){
5084 	*lp = cpystr(p->desc);
5085 	if(default_val && !strcmp(default_val, p->desc))
5086 	  starting_val = (*lp);
5087 
5088 	lp++;
5089     }
5090 
5091     none = _("NONE - No X-Priority header included");
5092     *lp = cpystr(none);
5093     if(!starting_val)
5094       starting_val = (*lp);
5095 
5096     /* TRANSLATORS: SELECT A PRIORITY is a screen title
5097        TRANSLATORS: Print something1 using something2.
5098        "priorities" is something1 */
5099     choice = choose_item_from_list(priority_list, NULL, _("SELECT A PRIORITY"),
5100 				   _("priorities"), h_select_priority_screen,
5101 				   _("HELP FOR SELECTING A PRIORITY"),
5102 				   starting_val);
5103 
5104     if(!choice)
5105       q_status_message(SM_ORDER, 1, 4, _("No change"));
5106     else if(!strcmp(choice, none))
5107       choice[0] = '\0';
5108 
5109     free_list_array(&priority_list);
5110 
5111     return(choice);
5112 }
5113 
5114 
5115 int
dont_flow_this_time(void)5116 dont_flow_this_time(void)
5117 {
5118     return(flowing_requested ? 0 : 1);
5119 }
5120 
5121 
5122 /*----------------------------------------------------------------------
5123     Call back for pico to display mime type of attachment
5124 
5125 Args: file -- filename being attached
5126 
5127 Returns: returns 1 on success (message queued), zero otherwise (don't know
5128 	  type so nothing queued).
5129 ----*/
5130 int
mime_type_for_pico(char * file)5131 mime_type_for_pico(char *file)
5132 {
5133     BODY *body;
5134     int   rv;
5135     void *file_contents;
5136 
5137     body           = mail_newbody();
5138     body->type     = TYPEOTHER;
5139     body->encoding = ENCOTHER;
5140 
5141     /* don't know where the cursor's been, reset it */
5142     clear_cursor_pos();
5143     if(!set_mime_type_by_extension(body, file)){
5144 	if((file_contents=(void *)so_get(FileStar,file,READ_ACCESS|READ_FROM_LOCALE)) != NULL){
5145 	    body->contents.text.data = file_contents;
5146 	    set_mime_type_by_grope(body);
5147 	}
5148     }
5149 
5150     if(body->type != TYPEOTHER){
5151 	rv = 1;
5152 	q_status_message3(SM_ORDER, 0, 3,
5153 	    _("File %s attached as type %s/%s"), file,
5154 	    body_types[body->type],
5155 	    body->subtype ? body->subtype : rfc822_default_subtype(body->type));
5156     }
5157     else
5158       rv = 0;
5159 
5160     pine_free_body(&body);
5161     return(rv);
5162 }
5163 
5164 
5165 /*----------------------------------------------------------------------
5166   Call back for pico to receive an uploaded message
5167 
5168   Args: fname -- name for uploaded file (empty if they want us to assign it)
5169 	size -- pointer to long to hold the attachment's size
5170 
5171   Notes: the attachment is uploaded to a temp file, and
5172 
5173   Returns: TRUE on success, FALSE otherwise
5174 ----*/
5175 int
upload_msg_to_pico(char * fname,size_t fnlen,long int * size)5176 upload_msg_to_pico(char *fname, size_t fnlen, long int *size)
5177 {
5178     char     cmd[MAXPATH+1], *fnp = NULL;
5179     char    *locale_name = NULL;
5180     long     l;
5181     PIPE_S  *syspipe;
5182 
5183     dprint((1, "Upload cmd called to xfer \"%s\"\n",
5184 	       fname ? fname : "<NO FILE>"));
5185 
5186     if(!fname)				/* no place for file name */
5187       return(0);
5188 
5189     if(!*fname){			/* caller wants temp file */
5190 	if((fnp = temp_nam(NULL, "pu")) != NULL){
5191 	    strncpy(fname, fnp, fnlen);
5192 	    fname[fnlen-1] = '\0';
5193 	    our_unlink(fnp);
5194 	    fs_give((void **)&fnp);
5195 	}
5196     }
5197     else
5198       locale_name = convert_to_locale(fname);
5199 
5200     build_updown_cmd(cmd, sizeof(cmd), ps_global->VAR_UPLOAD_CMD_PREFIX,
5201 		     ps_global->VAR_UPLOAD_CMD, locale_name ? locale_name : fname);
5202     if((syspipe = open_system_pipe(cmd, NULL, NULL, PIPE_USER | PIPE_RESET,
5203 				  0, pipe_callback, pipe_report_error)) != NULL){
5204 	(void) close_system_pipe(&syspipe, NULL, pipe_callback);
5205 	if((l = name_file_size(locale_name ? locale_name : fname)) < 0L){
5206 	    q_status_message2(SM_ORDER | SM_DING, 3, 4,
5207 			      "Error determining size of %s: %s", fname,
5208 			      fnp = error_description(errno));
5209 	    dprint((1,
5210 		   "!!! Upload cmd \"%s\" failed for \"%s\": %s\n",
5211 		   cmd ? cmd : "?",
5212 		   fname ? fname : "?",
5213 		   fnp ? fnp : "?"));
5214 	}
5215 	else if(size)
5216 	  *size = l;
5217 
5218 	if(locale_name)
5219 	  fs_give((void **) &locale_name);
5220 
5221 	return(l >= 0);
5222     }
5223     else
5224       q_status_message(SM_ORDER | SM_DING, 3, 4, _("Error opening pipe"));
5225 
5226     if(locale_name)
5227       fs_give((void **) &locale_name);
5228 
5229     return(0);
5230 }
5231 
5232 
5233 char *
cancel_for_pico(void (* redraw_pico)(void))5234 cancel_for_pico(void (*redraw_pico)(void))
5235 {
5236     int	  rv;
5237     char *rstr = NULL;
5238     char *prompt =
5239      _("Cancel message (answering \"Confirm\" will abandon your mail message) ? ");
5240     void (*redraw)(void) = ps_global->redrawer;
5241     static ESCKEY_S opts[] = {
5242 	{'c', 'c', "C", N_("Confirm")},
5243 	{'n', 'n', "N", N_("No")},
5244 	{'y', 'y', "", ""},
5245 	{-1, 0, NULL, NULL}
5246     };
5247 
5248     ps_global->redrawer = redraw_pico;
5249     fix_windsize(ps_global);
5250 
5251     while(1){
5252 	rv = radio_buttons(prompt, -FOOTER_ROWS(ps_global), opts,
5253 			   'n', 'x', h_confirm_cancel, RB_NORM);
5254 	if(rv == 'c'){				/* user ACCEPTS! */
5255 	    rstr = "";
5256 	    break;
5257 	}
5258 	else if(rv == 'y'){
5259 	    q_status_message(SM_INFO, 1, 3, _(" Type \"C\" to cancel message "));
5260 	    display_message('x');
5261 	}
5262 	else
5263 	  break;
5264     }
5265 
5266     ps_global->redrawer = redraw;
5267     return(rstr);
5268 }
5269 
5270 
5271 /*----------------------------------------------------------------------
5272     Pass the first text segment of the message thru the "send filter"
5273 
5274 Args: body pointer and address for storage object of old data
5275 
5276 Returns: returns 1 on success, zero on error.
5277 ----*/
5278 int
filter_message_text(char * fcmd,ENVELOPE * outgoing,struct mail_bodystruct * body,STORE_S ** old,METAENV * header)5279 filter_message_text(char *fcmd, ENVELOPE *outgoing, struct mail_bodystruct *body,
5280 		    STORE_S **old, METAENV *header)
5281 {
5282     char     *cmd, *tmpf = NULL, *resultf = NULL, *errstr = NULL, *mtf = NULL;
5283     int	      key = 0, include_hdrs = 0;
5284     gf_io_t   gc, pc;
5285     STORE_S **so = (STORE_S **)((body->type == TYPEMULTIPART)
5286 				? &body->nested.part->body.contents.text.data
5287 				: &body->contents.text.data),
5288 	     *tmp_so = NULL, *tmpf_so,
5289 	     *save_local_so, *readthis_so = NULL, *our_tmpf_so = NULL;
5290 #define DO_HEADERS 1
5291 
5292     if(fcmd
5293        && (cmd=expand_filter_tokens(fcmd, outgoing, &tmpf, &resultf, &mtf,
5294 				    &key, &include_hdrs, NULL))){
5295 	if(tmpf){
5296 	    /*
5297 	     * We need WRITE_TO_LOCALE here because the user is going to
5298 	     * be operating on tmpf. We need to change it back after they
5299 	     * are done.
5300 	     */
5301 	    if((tmpf_so = so_get(FileStar, tmpf, EDIT_ACCESS|OWNER_ONLY|WRITE_TO_LOCALE)) != NULL){
5302 		if(key){
5303 		    so_puts(tmpf_so, filter_session_key());
5304 		    so_puts(tmpf_so, NEWLINE);
5305 		}
5306 
5307 		/*
5308 		 * If the headers are wanted for filtering, we can just
5309 		 * stick them in the tmpf file that is already there before
5310 		 * putting the body in.
5311 		 */
5312 		if(include_hdrs){
5313 		    save_local_so = lmc.so;
5314 		    lmc.so = tmpf_so;		/* write it to tmpf_so */
5315 		    lmc.all_written = lmc.text_written = lmc.text_only = 0;
5316 		    pine_rfc822_header(header, body, NULL, NULL);
5317 		    lmc.so = save_local_so;
5318 		}
5319 
5320 		so_seek(*so, 0L, 0);
5321 		gf_set_so_readc(&gc, *so);
5322 		gf_set_so_writec(&pc, tmpf_so);
5323 		gf_filter_init();
5324 		errstr = gf_pipe(gc, pc);
5325 		gf_clear_so_readc(*so);
5326 		gf_clear_so_writec(tmpf_so);
5327 		so_give(&tmpf_so);
5328 	    }
5329 	    else
5330 	      errstr = "Can't create space for filter temporary file.";
5331 	}
5332 	else if(include_hdrs){
5333 	    /*
5334 	     * Gf_filter wants a single storage object to read from.
5335 	     * If headers are wanted for filtering we'll have to put them
5336 	     * and the body into a temp file first and then use that
5337 	     * as the storage object for gf_filter.
5338 	     * We don't use WRITE_TO_LOCALE in this case because gf_filter
5339 	     * takes care of that.
5340 	     */
5341 	    if((our_tmpf_so = so_get(TmpFileStar, NULL, EDIT_ACCESS|OWNER_ONLY)) != NULL){
5342 		/* put headers in our_tmpf_so */
5343 		save_local_so = lmc.so;
5344 		lmc.so = our_tmpf_so;		/* write it to our_tmpf_so */
5345 		lmc.all_written = lmc.text_written = lmc.text_only = 0;
5346 		pine_rfc822_header(header, body, NULL, NULL);
5347 		lmc.so = save_local_so;
5348 
5349 		/* put body in our_tmpf_so */
5350 		so_seek(*so, 0L, 0);
5351 		gf_set_so_readc(&gc, *so);
5352 		gf_set_so_writec(&pc, our_tmpf_so);
5353 		gf_filter_init();
5354 		errstr = gf_pipe(gc, pc);
5355 		gf_clear_so_readc(*so);
5356 		gf_clear_so_writec(our_tmpf_so);
5357 
5358 		/* tell gf_filter to read from our_tmpf_so instead of *so */
5359 		readthis_so = our_tmpf_so;
5360 	    }
5361 	    else
5362 	      errstr = "Can't create space for temporary file.";
5363 	}
5364 	else
5365 	  readthis_so = *so;
5366 
5367 	if(!errstr){
5368 	    if((tmp_so = so_get(PicoText, NULL, EDIT_ACCESS)) != NULL){
5369 		gf_set_so_writec(&pc, tmp_so);
5370 		ps_global->mangled_screen = 1;
5371 		suspend_busy_cue();
5372 		ClearScreen();
5373 		fflush(stdout);
5374 		if(tmpf){
5375 		    PIPE_S *fpipe;
5376 
5377 		    if((fpipe = open_system_pipe(cmd, NULL, NULL,
5378 						PIPE_NOSHELL | PIPE_RESET,
5379 						0, pipe_callback, pipe_report_error)) != NULL){
5380 			if(close_system_pipe(&fpipe, NULL, pipe_callback) == 0){
5381 
5382 			    /* now we undo the WRITE_FROM_LOCALE change in tmpf */
5383 			    if((tmpf_so = so_get(FileStar, tmpf, READ_ACCESS|READ_FROM_LOCALE)) != NULL){
5384 				gf_set_so_readc(&gc, tmpf_so);
5385 				gf_filter_init();
5386 				errstr = gf_pipe(gc, pc);
5387 				gf_clear_so_readc(tmpf_so);
5388 				so_give(&tmpf_so);
5389 			    }
5390 			    else
5391 			      errstr = "Can't open temp file filter wrote.";
5392 			}
5393 			else
5394 			  errstr = "Filter command returned error.";
5395 		    }
5396 		    else
5397 		      errstr = "Can't exec filter text.";
5398 		}
5399 		else
5400 		  errstr = gf_filter(cmd, key ? filter_session_key() : NULL,
5401 				     readthis_so, pc, NULL, 0, 0,
5402 				     pipe_callback);
5403 
5404 		if(our_tmpf_so)
5405 		  so_give(&our_tmpf_so);
5406 
5407 		gf_clear_so_writec(tmp_so);
5408 
5409 #ifdef _WINDOWS
5410 		if(!errstr){
5411 		    /*
5412 		     * Can't really be using stdout, so don't print message that
5413 		     * gets printed in the else.  Ideally the program being called
5414 		     * will wait after showing the message, we might want to look
5415 		     * into doing the waiting in console based apps... or not.
5416 		     */
5417 #else
5418 		if(errstr){
5419 		    unsigned long ch;
5420 
5421 		    fprintf(stdout, "\r\n%s  Hit return to continue.", errstr);
5422 		    fflush(stdout);
5423 		    while((ch = read_char(300)) != ctrl('M')
5424 			  && ch != NO_OP_IDLE)
5425 		      putchar(BELL);
5426 		}
5427 		else{
5428 #endif /* _WINDOWS */
5429 		    BODY *b = (body->type == TYPEMULTIPART)
5430 					   ? &body->nested.part->body : body;
5431 
5432 		    *old = *so;			/* save old so */
5433 		    *so = tmp_so;		/* return new one */
5434 		    (*so)->attr = copy_parameters((*old)->attr);
5435 
5436 		    /*
5437 		     * If the command said it would return new MIME
5438 		     * mime type data, check it out...
5439 		     */
5440 		    if(mtf){
5441 			char  buf[MAILTMPLEN], *s;
5442 			FILE *fp;
5443 
5444 			if((fp = our_fopen(mtf, "rb")) != NULL){
5445 			    if(fgets(buf, sizeof(buf), fp)
5446 			       && !struncmp(buf, "content-", 8)
5447 			       && (s = strchr(buf+8, ':'))){
5448 				BODY *nb = mail_newbody();
5449 
5450 				for(*s++ = '\0'; *s == ' '; s++)
5451 				  ;
5452 
5453 				rfc822_parse_content_header(nb,
5454 				    (char *) ucase((unsigned char *) buf+8),s);
5455 				if(nb->type == TYPETEXT
5456 				   && nb->subtype
5457 				   && (!b->subtype
5458 				       || strucmp(b->subtype, nb->subtype))){
5459 				    if(b->subtype)
5460 				      fs_give((void **) &b->subtype);
5461 
5462 				    b->subtype  = nb->subtype;
5463 				    nb->subtype = NULL;
5464 
5465 				    mail_free_body_parameter(&b->parameter);
5466 				    b->parameter = nb->parameter;
5467 				    nb->parameter = NULL;
5468 				    mail_free_body_parameter(&nb->parameter);
5469 				}
5470 
5471 				mail_free_body(&nb);
5472 			    }
5473 
5474 			    fclose(fp);
5475 			}
5476 		    }
5477 
5478 		    /*
5479 		     * Reevaluate the encoding in case form's changed...
5480 		     */
5481 		    b->encoding = ENCOTHER;
5482 		    set_mime_type_by_grope(b);
5483 		}
5484 
5485 		ClearScreen();
5486 		resume_busy_cue(0);
5487 	    }
5488 	    else
5489 	      errstr = "Can't create space for filtered text.";
5490 	}
5491 
5492 	fs_give((void **)&cmd);
5493     }
5494     else
5495       return(0);
5496 
5497     if(tmpf){
5498 	our_unlink(tmpf);
5499 	fs_give((void **)&tmpf);
5500     }
5501 
5502     if(mtf){
5503 	our_unlink(mtf);
5504 	fs_give((void **) &mtf);
5505     }
5506 
5507     if(resultf){
5508 	if(name_file_size(resultf) > 0L)
5509 	  display_output_file(resultf, "Filter", NULL, DOF_BRIEF);
5510 	our_unlink(resultf);
5511 	fs_give((void **)&resultf);
5512     }
5513     else if(errstr){
5514 	if(tmp_so)
5515 	  so_give(&tmp_so);
5516 
5517 	q_status_message1(SM_ORDER | SM_DING, 3, 6, _("Problem filtering: %s"),
5518 			  errstr);
5519 	dprint((1, "Filter FAILED: %s\n",
5520 	       errstr ? errstr : "?"));
5521     }
5522 
5523     return(errstr == NULL);
5524 }
5525 
5526 
5527 /*----------------------------------------------------------------------
5528     Copy the newsgroup name of the given mailbox into the given buffer
5529 
5530 Args:
5531 
5532 Returns:
5533 ----*/
5534 void
5535 pine_send_newsgroup_name(char *mailbox, char *group_name, size_t len)
5536 {
5537     NETMBX  mb;
5538 
5539     if(*mailbox == '#'){		/* Strip the leading "#news." */
5540 	strncpy(group_name, mailbox + 6, len-1);
5541 	group_name[len-1] = '\0';
5542     }
5543     else if(mail_valid_net_parse(mailbox, &mb)){
5544 	pine_send_newsgroup_name(mb.mailbox, group_name, len);
5545     }
5546     else
5547       *group_name = '\0';
5548 }
5549 
5550 
5551 /*----------------------------------------------------------------------
5552     Set up fields for passing to pico.  Assumes first text part is
5553     intended to be passed along for editing, and is in the form of
5554     of a storage object brought into existence sometime before pico_send().
5555  -----*/
5556 void
5557 outgoing2strings(METAENV *header, struct mail_bodystruct *bod, void **text,
5558 		 PATMT **pico_a, int from_bounce)
5559 {
5560     PINEFIELD  *pf;
5561 
5562     /*
5563      * SIMPLIFYING ASSUMPTION #37: the first TEXT part's storage object
5564      * is guaranteed to be of type PicoText!
5565      */
5566     if(bod->type == TYPETEXT){
5567 	*text = so_text((STORE_S *) bod->contents.text.data);
5568 
5569 	/* mark storage object as user edited */
5570 	if(!from_bounce)
5571 	  (void) so_attr((STORE_S *) bod->contents.text.data, "edited", "1");
5572     }
5573     else if(bod->type == TYPEMULTIPART){
5574 	PART       *part;
5575 	PATMT     **ppa;
5576 	char       *type, *name, *p;
5577 	int		name_l;
5578 
5579 	/*
5580 	 * We used to jump out the window if the first part wasn't text,
5581 	 * but that may not be the case when bouncing a message with
5582 	 * a leading non-text segment.  So, IT'S UNDERSTOOD that the
5583 	 * contents of the first part to send is still ALWAYS in a
5584 	 * PicoText storage object, *AND* if that object doesn't contain
5585 	 * data of type text, then it must contain THE ENCODED NON-TEXT
5586 	 * DATA of the piece being sent.
5587 	 *
5588 	 * It's up to the programmer to make sure that such a message is
5589 	 * sent via pine_simple_send and never get to the composer via
5590 	 * pine_send.
5591 	 *
5592 	 * Make sense?
5593 	 */
5594 	*text = so_text((STORE_S *) bod->nested.part->body.contents.text.data);
5595 
5596 	/* mark storage object as user edited */
5597 	if(!from_bounce)
5598 	  (void) so_attr((STORE_S *) bod->nested.part->body.contents.text.data, "edited", "1");
5599 
5600 	/*
5601 	 * If we already had a list, blast it now, so we can build a new
5602 	 * attachment list that reflects what's really there...
5603 	 */
5604 	if(pico_a){
5605 	    free_attachment_list(pico_a);
5606 
5607 
5608 	    /* Simplifyihg assumption #28e. (see cross reference)
5609 	       All parts in the body passed in here that are not already
5610 	       in the attachments list are added to the end of the attachments
5611 	       list. Attachment items not in the body list will be taken care
5612 	       of in strings2outgoing, but they are unlikely to occur
5613 	    */
5614 
5615 	    for(part = bod->nested.part->next; part != NULL; part = part->next) {
5616 		/* Already in list? */
5617 		for(ppa = pico_a;
5618 		    *ppa && strcmp((*ppa)->id, part->body.id);
5619 		    ppa = &(*ppa)->next)
5620 		  ;
5621 
5622 		if(!*ppa){		/* Not in the list! append it... */
5623 		    *ppa = (PATMT *)fs_get(sizeof(PATMT));
5624 
5625 		    if(part->body.description){
5626 			char *p;
5627 			size_t len;
5628 
5629 			len = 4*strlen(part->body.description)+1;
5630 			p = (char *)fs_get(len*sizeof(char));
5631 			if(rfc1522_decode_to_utf8((unsigned char *)p,
5632 						  len, part->body.description) == (unsigned char *) p){
5633 			    (*ppa)->description = p;
5634 			}
5635 			else{
5636 			    fs_give((void **)&p);
5637 			    (*ppa)->description = cpystr(part->body.description);
5638 			}
5639 		    }
5640 		    else
5641 		      (*ppa)->description = cpystr("");
5642 
5643 		    type = type_desc(part->body.type, part->body.subtype,
5644 				     part->body.parameter, NULL, 0);
5645 
5646 		    /*
5647 		     * If we can find a "name" parm, display that too...
5648 		     */
5649 		    if((name = parameter_val(part->body.parameter, "name")) != NULL){
5650 			/* Convert any [ or ]'s the name contained */
5651 			for(p = name; *p ; p++)
5652 			  if(*p == '[')
5653 			    *p = '(';
5654 			  else if(*p == ']')
5655 			    *p = ')';
5656 
5657 			name_l = p - name;
5658 		    }
5659 		    else
5660 		      name_l = 0;
5661 
5662 		    (*ppa)->filename = fs_get(strlen(type) + name_l + 5);
5663 
5664 		    snprintf((*ppa)->filename, strlen(type) + name_l + 5, "[%s%s%s]", type,
5665 			    name ? ": " : "", name ? name : "");
5666 		    (*ppa)->filename[strlen(type) + name_l + 5 - 1] = '\0';
5667 
5668 		    if(name)
5669 		      fs_give((void **) &name);
5670 
5671 		    (*ppa)->flags = A_FLIT;
5672 		    (*ppa)->size  = cpystr(byte_string(
5673 						   send_body_size(&part->body)));
5674 		    if(!part->body.id)
5675 		      part->body.id = generate_message_id(NULL);
5676 
5677 		    (*ppa)->id   = cpystr(part->body.id);
5678 		    (*ppa)->next = NULL;
5679 		}
5680 	    }
5681 	}
5682     }
5683 
5684 
5685     /*------------------------------------------------------------------
5686        Malloc strings to pass to composer editor because it expects
5687        such strings so it can realloc them
5688       -----------------------------------------------------------------*/
5689     /*
5690      * turn any address fields into text strings
5691      */
5692     /*
5693      * SIMPLIFYING ASSUMPTION #116: all header strings are understood
5694      * NOT to be RFC1522 decoded.  Said differently, they're understood
5695      * to be RFC1522 ENCODED as necessary.  The intent is to preserve
5696      * original charset tagging as far into the compose/send pipe as
5697      * we can.
5698      */
5699     for(pf = header->local; pf && pf->name; pf = pf->next)
5700       if(pf->canedit)
5701 	switch(pf->type){
5702 	  case Address :
5703 	    if(pf->addr){
5704 		char *p, *t, *u;
5705 		long  l;
5706 
5707 		pf->scratch = addr_list_string(*pf->addr, NULL, 1);
5708 
5709 		/*
5710 		 * Scan for and fix-up patently bogus fields.
5711 		 *
5712 		 * NOTE: collaboration with this code and what's done in
5713 		 * reply.c:reply_cp_addr to package up the bogus stuff
5714 		 * is required.
5715 		 */
5716 		for(p = pf->scratch; (p = strstr(p, "@" RAWFIELD)); )
5717 		  for(t = p; ; t--)
5718 		    if(*t == '&'){		/* find "leading" token */
5719 			int replacelen;
5720 
5721 			/*
5722 			 * Rfc822_cat has been changed so that it now quotes
5723 			 * this sometimes. So we have to look out for quotes
5724 			 * which confuse the decoder. It was only quoting
5725 			 * because we were putting \r \n in the input, I think.
5726 			 */
5727 			if(t > pf->scratch && t[-1] == '\"' && p[-1] == '\"')
5728 			  t[-1] = p[-1] = ' ';
5729 
5730 			*t++ = ' ';		/* replace token */
5731 			*p = '\0';		/* tie off string */
5732 			u = rfc822_base64((unsigned char *) t,
5733 					  (unsigned long) strlen(t),
5734 					  (unsigned long *) &l);
5735 			if(!u)
5736 			  u = "";
5737 
5738 			replacelen = strlen(t);
5739 			*p = '@';		/* restore 'p' */
5740 			rplstr(p, strlen(p), 12, "");	/* clear special token */
5741 			rplstr(t, strlen(u)-replacelen+1, replacelen, u);
5742 			if(u)
5743 			  fs_give((void **) &u);
5744 
5745 			if(HE(pf))
5746 			  HE(pf)->start_here = 1;
5747 
5748 			break;
5749 		    }
5750 		    else if(t == pf->scratch)
5751 		      break;
5752 
5753 		removing_leading_white_space(pf->scratch);
5754 		if(pf->scratch){
5755 		    size_t l;
5756 
5757 		    /*
5758 		     * Replace control characters with ^C notation, unless
5759 		     * some conditions are met (see istrncpy).
5760 		     * If user doesn't edit, then we switch back to the
5761 		     * original version. If user does edit, then all bets
5762 		     * are off.
5763 		     */
5764 		    iutf8ncpy((char *)tmp_20k_buf, pf->scratch, SIZEOF_20KBUF-1);
5765 		    tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
5766 		    if((l=strlen((char *)tmp_20k_buf)) > strlen(pf->scratch)){
5767 			fs_give((void **)&pf->scratch);
5768 			pf->scratch = (char *)fs_get((l+1) * sizeof(char));
5769 		    }
5770 
5771 		    strncpy(pf->scratch, (char *)tmp_20k_buf, l+1);
5772 		}
5773 	    }
5774 
5775 	    break;
5776 
5777 	  case Subject :
5778 	    if(pf->text){
5779 		char *p, *src;
5780 		size_t len;
5781 
5782 		src = pf->scratch ? pf->scratch
5783 				  : (*pf->text) ? *pf->text : "";
5784 
5785 		len = 4*strlen(src)+1;
5786 		p = (char *)fs_get(len * sizeof(char));
5787 		if(rfc1522_decode_to_utf8((unsigned char *)p, len, src) == (unsigned char *) p){
5788 		    if(pf->scratch)
5789 		      fs_give((void **)&pf->scratch);
5790 
5791 		    pf->scratch = p;
5792 		}
5793 		else{
5794 		    fs_give((void **)&p);
5795 		    if(!pf->scratch)
5796 		      pf->scratch = cpystr(src);
5797 		}
5798 
5799 		if(pf->scratch){
5800 		    size_t l;
5801 
5802 		    /*
5803 		     * Replace control characters with ^C notation, unless
5804 		     * some conditions are met (see istrncpy).
5805 		     * If user doesn't edit, then we switch back to the
5806 		     * original version. If user does edit, then all bets
5807 		     * are off.
5808 		     */
5809 		    iutf8ncpy((char *)tmp_20k_buf, pf->scratch, SIZEOF_20KBUF-1);
5810 		    tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
5811 		    if((l=strlen((char *)tmp_20k_buf)) > strlen(pf->scratch)){
5812 			fs_give((void **)&pf->scratch);
5813 			pf->scratch = (char *)fs_get((l+1) * sizeof(char));
5814 		    }
5815 
5816 		    strncpy(pf->scratch, (char *)tmp_20k_buf, l+1);
5817 		}
5818 	    }
5819 
5820 	    break;
5821 
5822 	  default :
5823 	    break;
5824 	}
5825 }
5826 
5827 
5828 /*----------------------------------------------------------------------
5829     Restore fields returned from pico to form useful to sending
5830     routines.
5831  -----*/
5832 void
5833 strings2outgoing(METAENV *header, struct mail_bodystruct **bod, PATMT *attach, int flow_it)
5834 {
5835     PINEFIELD *pf;
5836     int we_cancel = 0;
5837 
5838     we_cancel = busy_cue(NULL, NULL, 1);
5839 
5840     /*
5841      * turn any local address strings into address lists
5842      */
5843     for(pf = header->local; pf && pf->name; pf = pf->next)
5844 	if(pf->scratch){
5845 	    char *the_address = NULL;
5846 
5847 	      switch(pf->type){
5848 		case Address :
5849 		  removing_trailing_white_space(pf->scratch);
5850 
5851 		  if((the_address || *pf->scratch) && pf->addr){
5852 		      ADDRESS     *new_addr = NULL;
5853 		      static char *fakedomain = "@";
5854 
5855 		      if(!the_address)
5856 			the_address = pf->scratch;
5857 
5858 		      rfc822_parse_adrlist(&new_addr, the_address,
5859 				   (F_ON(F_COMPOSE_REJECTS_UNQUAL, ps_global))
5860 				     ? fakedomain : ps_global->maildomain);
5861 		      mail_free_address(pf->addr);	/* free old addrs */
5862 		      *pf->addr = new_addr;		/* assign new addr */
5863 		  }
5864 		  else if(pf->addr)
5865 		    mail_free_address(pf->addr);	/* free old addrs */
5866 
5867 		  break;
5868 
5869 		case Subject :
5870 		  if(*pf->text)
5871 		    fs_give((void **)pf->text);
5872 
5873 		  if(*pf->scratch){
5874 		        *pf->text = cpystr(pf->scratch);
5875 		  }
5876 
5877 		  break;
5878 
5879 		default :
5880 		  break;
5881 	      }
5882 
5883 	    fs_give((void **)&pf->scratch);	/* free now useless text */
5884 	}
5885 
5886     create_message_body(bod, attach, flow_it);
5887 
5888     if(we_cancel)
5889       cancel_busy_cue(-1);
5890 }
5891 
5892 
5893 /*----------------------------------------------------------------------
5894 
5895  The head of the body list here is always either TEXT or MULTIPART. It may be
5896 changed from TEXT to MULTIPART if there are attachments to be added
5897 and it is not already multipart.
5898   ----*/
5899 void
5900 create_message_body(struct mail_bodystruct **b, PATMT *attach, int flow_it)
5901 {
5902     PART       *p, **pp;
5903     PATMT      *pa;
5904     BODY       *tmp_body, *text_body = NULL;
5905     void       *file_contents;
5906     PARAMETER **parmp;
5907     char       *lc;
5908 
5909     TIME_STAMP("create_body start.", 1);
5910     /*
5911      * if conditions are met short circuit MIME wrapping
5912      */
5913     if((*b)->type != TYPEMULTIPART && !attach){
5914 
5915 	/* only override assigned encoding if it might need upgrading */
5916 	if((*b)->type == TYPETEXT && (*b)->encoding == ENC7BIT)
5917 	  (*b)->encoding = ENCOTHER;
5918 
5919 	create_message_body_text(*b, flow_it);
5920 
5921 	if(F_ON(F_COMPOSE_ALWAYS_DOWNGRADE, ps_global)
5922 	   || !((*b)->encoding == ENC8BIT
5923 		|| (*b)->encoding == ENCBINARY)){
5924 	    TIME_STAMP("create_body end.", 1);
5925 	    return;
5926 	}
5927 	else			/* protect 8bit in multipart */
5928 	  text_body = *b;
5929     }
5930 
5931     if((*b)->type == TYPETEXT) {
5932         /*-- Current type is text, but there are attachments to add --*/
5933         /*-- Upgrade to a TYPEMULTIPART --*/
5934         tmp_body			= (BODY *)mail_newbody();
5935         tmp_body->type			= TYPEMULTIPART;
5936         tmp_body->nested.part		= mail_newbody_part();
5937 	if(text_body){
5938 	    /*
5939 	     * Why do we do this?
5940 	     * The problem is that base64 or quoted-printable encoding is
5941 	     * sensitive to having random data appended to it's end. If
5942 	     * we use a single part TEXT message and something in between
5943 	     * us and the end appends advertising without adjusting for
5944 	     * the encoding, the message is screwed up. So we wrap the
5945 	     * text part inside a multipart and then the appended data
5946 	     * will come after the boundary.
5947 	     *
5948 	     * We wish we could do this on the way out the door in a
5949 	     * child of post_rfc822_output because at that point we know
5950 	     * the character set and the encoding being used. For example,
5951 	     * iso-2022-jp is an encoding that is not sensitive to data
5952 	     * appended to the end, so it wouldn't need to be wrapped.
5953 	     * We could conceivably have post_rfc822_body inspect the
5954 	     * body and change it before doing the output. It would work
5955 	     * but would be very fragile. We'd be passed a body from
5956 	     * c-client to output and instead of just doing the output
5957 	     * we'd change the body and then output it. Not worth it
5958 	     * since the multipart wrapping is completely correct for
5959 	     * MIME-aware mailers.
5960 	     */
5961 	    (void) copy_body(&(tmp_body->nested.part->body), *b);
5962 	    /* move contents which were NOT copied */
5963 	    tmp_body->nested.part->body.contents.text.data = (*b)->contents.text.data;
5964 	    (*b)->contents.text.data = NULL;
5965 	}
5966 	else{
5967 	    tmp_body->nested.part->body	= **b;
5968 
5969 	    (*b)->subtype = (*b)->id = (*b)->description = NULL;
5970 	    (*b)->parameter				 = NULL;
5971 	    (*b)->contents.text.data			 = NULL;
5972 	}
5973 
5974 	pine_free_body(b);
5975         *b = tmp_body;
5976     }
5977 
5978     if(!text_body){
5979 	/*-- Now type must be MULTIPART with first part text --*/
5980 	(*b)->nested.part->body.encoding = ENCOTHER;
5981 	create_message_body_text(&((*b)->nested.part->body), flow_it);
5982     }
5983 
5984     /*------ Go through the parts list remove those to be deleted -----*/
5985     for(pp = &(*b)->nested.part->next; *pp;){
5986 	for(pa = attach; pa && (*pp)->body.id; pa = pa->next)
5987 	  /* already existed? */
5988 	  if(pa->id && strcmp(pa->id, (*pp)->body.id) == 0){
5989 	      char *orig_descp = NULL, *cs = NULL;
5990 
5991 	      /*
5992 	       * decode original to see if it matches what was decoded
5993 	       * when we sent it in.
5994 	       */
5995 
5996 	      if((*pp)->body.description)
5997 		orig_descp = (char *) rfc1522_decode_to_utf8((unsigned char *) tmp_20k_buf,
5998 							     SIZEOF_20KBUF, (*pp)->body.description);
5999 
6000 	      if(!(*pp)->body.description	/* update description? */
6001 		 || (pa->description && strcmp(pa->description, orig_descp))){
6002 		  if((*pp)->body.description)
6003 		    fs_give((void **) &(*pp)->body.description);
6004 
6005 		  /* encoding happens as msg text is written */
6006 		  (*pp)->body.description = cpystr(pa->description);
6007 	      }
6008 
6009 	      if(cs)
6010 		fs_give((void **) &cs);
6011 
6012 	      break;
6013 	  }
6014 
6015         if(pa == NULL){
6016 	    p = *pp;				/* prepare to zap *pp */
6017 	    *pp = p->next;			/* pull next one in list up */
6018 	    p->next = NULL;			/* tie off removed node */
6019 
6020 	    pine_free_body_data(&p->body);	/* clean up contained data */
6021 	    mail_free_body_part(&p);		/* free up the part */
6022 	}
6023 	else
6024 	  pp = &(*pp)->next;
6025     }
6026 
6027     /*---------- Now add any new attachments ---------*/
6028     for(p = (*b)->nested.part ; p->next != NULL; p = p->next);
6029     for(pa = attach; pa != NULL; pa = pa->next) {
6030         if(pa->id != NULL)
6031 	  continue;			/* Has an ID, it's old */
6032 
6033 	/*
6034 	 * the idea is handle ALL attachments as open FILE *'s.  Actual
6035          * encoding and such is handled at the time the message
6036          * is shoved into the mail slot or written to disk...
6037 	 *
6038          * Also, we never unlink a file, so it's up to whoever opens
6039          * it to deal with tmpfile issues.
6040 	 */
6041 	if((file_contents = (void *)so_get(FileStar, pa->filename,
6042 					   READ_ACCESS)) == NULL){
6043             q_status_message2(SM_ORDER | SM_DING, 3, 4,
6044 			  _("Error \"%s\", couldn't attach file \"%s\""),
6045                               error_description(errno), pa->filename);
6046             display_message('x');
6047             continue;
6048         }
6049 
6050         p->next			   = mail_newbody_part();
6051         p			   = p->next;
6052         p->body.id		   = generate_message_id(NULL);
6053         p->body.contents.text.data = file_contents;
6054 
6055 	/*
6056 	 * Set type to unknown and let set_mime_type_by_* figure it out.
6057 	 * Always encode attachments we add as BINARY.
6058 	 */
6059 	p->body.type		     = TYPEOTHER;
6060 	p->body.encoding	     = ENCBINARY;
6061 	p->body.size.bytes           = name_file_size(pa->filename);
6062 	if(!set_mime_type_by_extension(&p->body, pa->filename)){
6063 	    set_mime_type_by_grope(&p->body);
6064 	    set_charset_possibly_to_ascii(&p->body,  ps_global->keyboard_charmap);
6065 	}
6066 
6067 	so_release((STORE_S *)p->body.contents.text.data);
6068 
6069 	if(pa->description)	/* encoding happens when msg written */
6070           p->body.description = cpystr(pa->description);
6071 
6072 	/* Add name attribute for backward compatibility */
6073 	for(parmp = &p->body.parameter; *parmp; )
6074 	  if(!struncmp((*parmp)->attribute, "name", 4)
6075 	     && (!*((*parmp)->attribute + 4)
6076 		 || *((*parmp)->attribute + 4) == '*')){
6077 	      PARAMETER *free_me = *parmp;
6078 	      *parmp = (*parmp)->next;
6079 	      free_me->next = NULL;
6080 	      mail_free_body_parameter(&free_me);
6081 	  }
6082 	  else
6083 	    parmp = &(*parmp)->next;
6084 
6085 	set_parameter(parmp, "name",
6086 		      pa->filename
6087 		        ? ((lc = last_cmpnt(pa->filename)) ? lc : pa->filename)
6088 			: NULL);
6089 
6090 	/* Then set the Content-Disposition ala RFC1806 */
6091 	if(!p->body.disposition.type){
6092 	    p->body.disposition.type = cpystr("attachment");
6093             for(parmp = &p->body.disposition.parameter; *parmp; )
6094 	      if(!struncmp((*parmp)->attribute, "filename", 4)
6095 		 && (!*((*parmp)->attribute + 4)
6096 		     || *((*parmp)->attribute + 4) == '*')){
6097 		  PARAMETER *free_me = *parmp;
6098 		  *parmp = (*parmp)->next;
6099 		  free_me->next = NULL;
6100 		  mail_free_body_parameter(&free_me);
6101 	      }
6102 	      else
6103 		parmp = &(*parmp)->next;
6104 
6105 	    set_parameter(parmp, "filename",
6106 			  pa->filename
6107 			    ? ((lc = last_cmpnt(pa->filename)) ? lc : pa->filename)
6108 			    : NULL);
6109 	}
6110 
6111         p->next = NULL;
6112         pa->id = cpystr(p->body.id);
6113     }
6114 
6115     /*
6116      * Now, if this multipart has but one text piece (that is, no
6117      * attachments), then downgrade from a composite type to a discrete
6118      * text/plain message if CTE is not 8bit.
6119      */
6120     if(!(*b)->nested.part->next
6121        && (*b)->nested.part->body.type == TYPETEXT
6122        && (F_ON(F_COMPOSE_ALWAYS_DOWNGRADE, ps_global)
6123 	   || !((*b)->nested.part->body.encoding == ENC8BIT
6124 		|| (*b)->nested.part->body.encoding == ENCBINARY))){
6125 	/* Clone the interesting body part */
6126 	tmp_body  = mail_newbody();
6127 	*tmp_body = (*b)->nested.part->body;
6128 	/* and rub out what we don't want cleaned up when it's free'd */
6129 	mail_initbody(&(*b)->nested.part->body);
6130 	mail_free_body(b);
6131 	*b = tmp_body;
6132     }
6133 
6134 
6135     TIME_STAMP("create_body end.", 1);
6136 }
6137 
6138 
6139 /*
6140  * Fill in text BODY part's structure
6141  *
6142  */
6143 void
6144 create_message_body_text(struct mail_bodystruct *b, int flow_it)
6145 {
6146     set_mime_type_by_grope(b);
6147     if(b != NULL){
6148        remove_parameter(&b->parameter, "format"); /* we will set it up below */
6149        remove_parameter(&b->parameter, "delsp");  /* we never set this up    */
6150     }
6151     if(F_OFF(F_QUELL_FLOWED_TEXT, ps_global)
6152        && F_OFF(F_STRIP_WS_BEFORE_SEND, ps_global)
6153        && flow_it)
6154       set_parameter(b ? &b->parameter : NULL, "format", "flowed");
6155 
6156     set_body_size(b);
6157 }
6158 
6159 
6160 /*
6161  * free_attachment_list - free attachments in given list
6162  */
6163 void
6164 free_attachment_list(PATMT **alist)
6165 {
6166     PATMT  *leading;
6167 
6168     while(alist && *alist){		/* pointer pointing to something */
6169 	leading = (*alist)->next;
6170 	if((*alist)->description)
6171           fs_give((void **)&(*alist)->description);
6172 
6173 	if((*alist)->filename){
6174 	    if((*alist)->flags & A_TMP)
6175 	      if(our_unlink((*alist)->filename) < 0)
6176 		dprint((1, "-- Can't unlink(%s): %s\n",
6177 		       (*alist)->filename ? (*alist)->filename : "?",
6178 		       error_description(errno)));
6179 
6180 	    fs_give((void **)&(*alist)->filename);
6181 	}
6182 
6183 	if((*alist)->size)
6184           fs_give((void **)&(*alist)->size);
6185 
6186 	if((*alist)->id)
6187           fs_give((void **)&(*alist)->id);
6188 
6189 	fs_give((void **)alist);
6190 
6191 	*alist = leading;
6192     }
6193 }
6194 
6195 
6196 void
6197 set_body_size(struct mail_bodystruct *b)
6198 {
6199     unsigned char c;
6200     int we_cancel = 0;
6201 
6202     we_cancel = busy_cue(NULL, NULL, 1);
6203     so_seek((STORE_S *)b->contents.text.data, 0L, 0);
6204     b->size.bytes = 0L;
6205     while(so_readc(&c, (STORE_S *)b->contents.text.data))
6206       b->size.bytes++;
6207 
6208     if(we_cancel)
6209       cancel_busy_cue(-1);
6210 }
6211 
6212 
6213 /*
6214  * view_as_rich - set the rich_header flag
6215  *
6216  *         name  - name of the header field
6217  *         deflt - default value to return if user didn't set it
6218  *
6219  *         Note: if the user tries to turn them all off with "", then
6220  *		 we take that to mean default, since otherwise there is no
6221  *		 way to get to the headers.
6222  */
6223 int
6224 view_as_rich(char *name, int deflt)
6225 {
6226     char **p;
6227     char *q;
6228 
6229     p = ps_global->VAR_COMP_HDRS;
6230 
6231     if(p && *p && **p){
6232         for(; (q = *p) != NULL; p++){
6233 	    if(!struncmp(q, name, strlen(name)))
6234 	      return 0; /* 0 means we *do* view it by default */
6235 	}
6236 
6237         return 1; /* 1 means it starts out hidden */
6238     }
6239     return(deflt);
6240 }
6241 
6242 
6243 /*
6244  * background_posting - return whether or not we're already in the process
6245  *			of posting
6246  */
6247 int
6248 background_posting(int gripe)
6249 {
6250     if(ps_global->post){
6251 	if(gripe)
6252 	  q_status_message(SM_ORDER|SM_DING, 3, 3,
6253 			   _("Can't post while posting!"));
6254 	return(1);
6255     }
6256 
6257     return(0);
6258 }
6259 
6260 
6261 /*----------------------------------------------------------------------
6262     Validate the given subject relative to any news groups.
6263 
6264 Args: none
6265 
6266 Returns: always returns 1, but also returns error if
6267 ----*/
6268 int
6269 valid_subject(char *given, char **expanded, char **error, BUILDER_ARG *fcc, int *mangled)
6270 {
6271     struct headerentry *hp;
6272 
6273     if(expanded)
6274       *expanded = cpystr(given);
6275 
6276     if(error){
6277 	/*
6278 	 * Now look for any header entry we passed to pico that has to do
6279 	 * with news.  If there's no subject, gripe.
6280 	 */
6281 	for(hp = pbf->headents; hp->prompt; hp++)
6282 	  if(hp->help == h_composer_news){
6283 	      if(hp->hd_text->text[0] && !*given)
6284 		*error = cpystr(
6285 			_("News postings MUST have a subject!  Please add one!"));
6286 
6287 	      break;
6288 	  }
6289     }
6290 
6291     return(0);
6292 }
6293 
6294 
6295 /*
6296  * This is the build_address used by the composer to check for an address
6297  * in the addrbook.
6298  *
6299  * Args: to      -- the passed in line to parse
6300  *       full_to -- Address of a pointer to return the full address in.
6301  *		    This will be allocated here and freed by the caller.
6302  *       error   -- Address of a pointer to return an error message in.
6303  *		    This will be allocated here and freed by the caller.
6304  *        barg   -- Address of a pointer to return the fcc in is in
6305  *		    fcc->tptr.  It will have already been allocated by the
6306  *		    caller but we may free it and reallocate if we wish.
6307  *		    Caller will free it.
6308  *
6309  * Result:  0 is returned if address was OK,
6310  *         -1 if address wasn't OK.
6311  *
6312  * Side effect: Can flush addrbook entry cache entries so they need to be
6313  * re-fetched afterwords.
6314  */
6315 int
6316 build_address(char *to, char **full_to, char **error, BUILDER_ARG *barg, int *mangled)
6317 {
6318     char   *p;
6319     int     ret_val, no_repo = 0, *save_nesting_level;
6320     BuildTo bldto;
6321     PrivateTop *pt = NULL;
6322     PrivateAffector *af = NULL;
6323     char   *fcc_local = NULL;
6324     jmp_buf save_jmp_buf;
6325 
6326     dprint((5, "- build_address - (%s)\n", to ? to : "nul"));
6327 
6328     /* check to see if to string is empty to avoid work */
6329     for(p = to; p && *p && isspace((unsigned char)*p); p++)
6330       ;/* do nothing */
6331 
6332     if(!p || !*p){
6333 	if(full_to)
6334 	  *full_to = cpystr(to ? to : "");  /* because pico does a strcmp() */
6335 
6336 	return 0;
6337     }
6338 
6339     if(full_to != NULL)
6340       *full_to = (char *)NULL;
6341 
6342     if(error != NULL)
6343       *error = (char *)NULL;
6344 
6345     /* No guarantee cursor or status line is how we saved it */
6346     clear_cursor_pos();
6347     mark_status_unknown();
6348 
6349     if(ps_global->remote_abook_validity > 0 &&
6350        adrbk_check_and_fix_all(ab_nesting_level == 0, 0, 0) && mangled)
6351       *mangled |= BUILDER_SCREEN_MANGLED;
6352 
6353     /*
6354      * If we end up jumping back here because somebody else changed one of
6355      * our addrbooks out from underneath us, we may well leak some memory.
6356      * That's probably ok since this will be very rare.
6357      *
6358      * The reason for the memcpy of the jmp_buf is that we may actually
6359      * be indirectly calling this function from within the address book.
6360      * For example, we may be in the address book screen and then run
6361      * the ComposeTo command which puts us in the composer, then we call
6362      * build_address from there which resets addrbook_changed_unexpectedly.
6363      * Once we leave build_address we need to reset addrbook_changed_un...
6364      * because this position on the stack will no longer be valid.
6365      * Same is true of the other setjmp's in this file which are wrapped
6366      * in memcpy calls.
6367      */
6368     save_nesting_level = cpyint(ab_nesting_level);
6369     memcpy(save_jmp_buf, addrbook_changed_unexpectedly, sizeof(jmp_buf));
6370     if(setjmp(addrbook_changed_unexpectedly)){
6371 	no_repo = 0;
6372 	pt = NULL;
6373 	af = NULL;
6374 	fcc_local = NULL;
6375 	if(error != NULL)
6376 	  *error = (char *)NULL;
6377 
6378 	if(full_to && *full_to)
6379 	  fs_give((void **)full_to);
6380 
6381 	q_status_message(SM_ORDER, 3, 5, "Resetting address book...");
6382 	dprint((1,
6383 	    "RESETTING address book... build_address(%s)!\n", to ? to : "?"));
6384 	addrbook_reset();
6385         ab_nesting_level = *save_nesting_level;
6386     }
6387 
6388     ab_nesting_level++;
6389     bldto.type    = Str;
6390     bldto.arg.str = to;
6391     ret_val = build_address_internal(bldto, full_to, error,
6392 				     barg ? &fcc_local : NULL,
6393 				     &no_repo, NULL, save_and_restore,
6394 				     0, mangled);
6395     ab_nesting_level--;
6396     if(save_nesting_level)
6397       fs_give((void **)&save_nesting_level);
6398 
6399     /*
6400      * Have to rfc1522_decode the full_to string before sending it back.
6401      */
6402     if(full_to && *full_to ){
6403 	char   *q;
6404 	size_t  len;
6405 
6406 	len = 4*strlen(*full_to)+1;
6407 	q = (char *)fs_get(len * sizeof(char));
6408 	p = (char *)rfc1522_decode_to_utf8((unsigned char *)q, len, *full_to);
6409 
6410 	/* p == q means that decoding happened, p is decoded *full_to */
6411 	if(p == q){
6412 	    fs_give((void **)full_to);
6413 	    *full_to = p;
6414 	}
6415 	else
6416 	  fs_give((void **)&q);
6417     }
6418 
6419     if(fcc_local){
6420 	unsigned long csum;
6421 
6422 	/* Pt will point to headents[Fcc].bldr_private */
6423 	pt = NULL;
6424 	if(barg && barg->aff)
6425 	  pt = (PrivateTop *)(*barg->aff);
6426 
6427 	/*
6428 	 * If *barg->aff is set, that means fcc was set from a list
6429 	 * during some previous builder call.
6430 	 * If the current To line contains the old expansion as a prefix, then
6431 	 * we should leave things as they are. In order to decide that,
6432 	 * we look at a hash value computed from the strings.
6433 	 */
6434 	if(pt && (af=pt->affector) && af->who == BP_To){
6435 	    int len;
6436 
6437 	    len = strlen(to);
6438 	    if(len >= af->cksumlen){
6439 		int save;
6440 
6441 		save = to[af->cksumlen];
6442 		to[af->cksumlen] = '\0';
6443 		csum = line_hash(to);
6444 		to[af->cksumlen] = save;
6445 	    }
6446 	    else
6447 	      csum = af->cksumval + 1;  /* something not equal to cksumval */
6448 	}
6449 
6450 	if(!pt ||
6451 	   !pt->affector ||
6452 	   (pt->affector->who == BP_To && csum != pt->affector->cksumval)){
6453 
6454 	    /* replace fcc value */
6455 	    if(barg->tptr)
6456 	      fs_give((void **)&barg->tptr);
6457 
6458 	    barg->tptr = fcc_local;
6459 
6460 	    if(barg->aff){
6461 		if(!pt){
6462 		    *barg->aff = (void *)fs_get(sizeof(PrivateTop));
6463 		    pt = (PrivateTop *)(*barg->aff);
6464 		    memset((void *)pt, 0, sizeof(PrivateTop));
6465 		}
6466 
6467 		if(no_repo){
6468 		    if(!pt->affector)
6469 		      pt->affector =
6470 			    (PrivateAffector *)fs_get(sizeof(PrivateAffector));
6471 
6472 		    af = pt->affector;
6473 		    af->who = BP_To;
6474 		    af->cksumlen = strlen(((full_to && *full_to)
6475 							    ? *full_to : ""));
6476 		    af->cksumval = line_hash(((full_to && *full_to)
6477 							    ? *full_to : ""));
6478 		}
6479 		else{
6480 		    /*
6481 		     * If result is reproducible, we don't keep track here.
6482 		     */
6483 		    if(pt->affector)
6484 		      fs_give((void **)&pt->affector);
6485 		}
6486 	    }
6487 	}
6488 	else
6489 	  fs_give((void **)&fcc_local);  /* unused in this case */
6490     }
6491 
6492     /* This is so pico will erase the old message */
6493     if(error != NULL && *error == NULL)
6494       *error = cpystr("");
6495 
6496     memcpy(addrbook_changed_unexpectedly, save_jmp_buf, sizeof(jmp_buf));
6497     flush_status_messages(1);
6498     return(ret_val);
6499 }
6500 
6501 
6502 /*
6503  * This is the builder used by the composer for the Lcc line.
6504  *
6505  * Args:     lcc -- the passed in Lcc line to parse
6506  *      full_lcc -- Address of a pointer to return the full address in.
6507  *		    This will be allocated here and freed by the caller.
6508  *         error -- Address of a pointer to return an error message in.
6509  *                  This is not allocated so should not be freed by the caller.
6510  *          barg -- This is a pointer to text for affected entries which
6511  *		    we may be changing.  The first one in the list is the
6512  *		    To entry.  We may put the name of the list in empty
6513  *		    group syntax form there (like  List Name: ;).
6514  *		    The second one in the list is the fcc field.
6515  *		    The tptr members already point to text allocated in the
6516  *		    caller. We may free and reallocate here, caller will
6517  *		    free the result in any case.
6518  *
6519  * Result:  0 is returned if address was OK,
6520  *         -1 if address wasn't OK.
6521  *
6522  * Side effect: Can flush addrbook entry cache entries so they need to be
6523  * re-fetched afterwords.
6524  */
6525 int
6526 build_addr_lcc(char *lcc, char **full_lcc, char **error, BUILDER_ARG *barg, int *mangled)
6527 {
6528     int		     ret_val,
6529 		     no_repo = 0;	/* fcc or lcc not reproducible */
6530     int		    *save_nesting_level;
6531     BuildTo	     bldlcc;
6532     PrivateTop      *pt = NULL;
6533     PrivateAffector *af = NULL;
6534     char	    *p,
6535 		    *fcc_local = NULL,
6536 		    *to = NULL,
6537 		    *dummy;
6538     jmp_buf          save_jmp_buf;
6539 
6540     dprint((5, "- build_addr_lcc - (%s)\n", lcc ? lcc : "nul"));
6541 
6542     /* check to see if to string is empty to avoid work */
6543     for(p = lcc; p && *p && isspace((unsigned char)*p); p++)
6544       ;/* do nothing */
6545 
6546     if(!p || !*p){
6547 	if(full_lcc)
6548 	  *full_lcc = cpystr(lcc ? lcc : ""); /* because pico does a strcmp() */
6549 
6550 	return 0;
6551     }
6552 
6553     if(error != NULL)
6554       *error = (char *)NULL;
6555 
6556     if(ps_global->remote_abook_validity > 0 &&
6557        adrbk_check_and_fix_all(ab_nesting_level == 0, 0, 0) && mangled)
6558       *mangled |= BUILDER_SCREEN_MANGLED;
6559 
6560     /*
6561      * If we end up jumping back here because somebody else changed one of
6562      * our addrbooks out from underneath us, we may well leak some memory.
6563      * That's probably ok since this will be very rare.
6564      */
6565     save_nesting_level = cpyint(ab_nesting_level);
6566     memcpy(save_jmp_buf, addrbook_changed_unexpectedly, sizeof(jmp_buf));
6567     if(setjmp(addrbook_changed_unexpectedly)){
6568 	no_repo = 0;
6569 	pt = NULL;
6570 	af = NULL;
6571 	fcc_local = NULL;
6572 	to = NULL;
6573 	if(error != NULL)
6574 	  *error = (char *)NULL;
6575 
6576 	if(full_lcc && *full_lcc)
6577 	  fs_give((void **)full_lcc);
6578 
6579 	q_status_message(SM_ORDER, 3, 5, "Resetting address book...");
6580 	dprint((1,
6581 	    "RESETTING address book... build_address(%s)!\n", lcc ? lcc : "?"));
6582 	addrbook_reset();
6583 	ab_nesting_level = *save_nesting_level;
6584     }
6585 
6586     ab_nesting_level++;
6587     bldlcc.type    = Str;
6588     bldlcc.arg.str = lcc;
6589 
6590     /*
6591      * To is first affected_entry and Fcc is second.
6592      * The conditional stuff for the fcc argument says to only change the
6593      * fcc if the fcc pointer is passed in non-null, and the To pointer
6594      * is also non-null.  If they are null, that means they've already been
6595      * entered (are sticky).  We don't affect fcc if either fcc or To has
6596      * been typed in.
6597      */
6598     ret_val = build_address_internal(bldlcc,
6599 		full_lcc,
6600 		error,
6601 		(barg && barg->next && barg->next->tptr && barg->tptr)
6602 		  ? &fcc_local : NULL,
6603 		&no_repo,
6604 		(barg && barg->tptr) ? &to : NULL,
6605 		save_and_restore, 0, mangled);
6606 
6607     ab_nesting_level--;
6608     if(save_nesting_level)
6609       fs_give((void **)&save_nesting_level);
6610 
6611     /* full_lcc is what ends up in the Lcc: line */
6612     if(full_lcc && *full_lcc){
6613 	size_t len;
6614 
6615 	/*
6616 	 * Have to rfc1522_decode the full_lcc string before sending it back.
6617 	 */
6618 	len = 4*strlen(*full_lcc)+1;
6619 	p = (char *)fs_get(len * sizeof(char));
6620 	if(rfc1522_decode_to_utf8((unsigned char *)p, len, *full_lcc) == (unsigned char *)p){
6621 	    fs_give((void **)full_lcc);
6622 	    *full_lcc = p;
6623 	}
6624 	else
6625 	  fs_give((void **)&p);
6626     }
6627 
6628     /* to is what ends up in the To: line */
6629     if(to && *to){
6630 	unsigned long csum;
6631 	size_t len;
6632 
6633 	/*
6634 	 * Have to rfc1522_decode the full_to string before sending it back.
6635 	 */
6636 	len = 4*strlen(to)+1;
6637 	p = (char *)fs_get(len * sizeof(char));
6638 	dummy = NULL;
6639 	if(rfc1522_decode_to_utf8((unsigned char *)p, len, to) == (unsigned char *)p){
6640 	    /*
6641 	     * If the caller wants us to try to preserve the charset
6642 	     * information (they set aff) we copy it into encoded->etext.
6643 	     * We don't have to worry about pasting together pieces of
6644 	     * etext like we do in build_address because whenever the
6645 	     * Lcc line is setting the To line it will be setting the
6646 	     * whole line, not modifying it.
6647 	     * Pt will point to headents[To].bldr_private.
6648 	     */
6649 	    if(barg && barg->aff){
6650 		pt = (PrivateTop *)(*barg->aff);
6651 
6652 		if(!pt){
6653 		    *barg->aff = (void *)fs_get(sizeof(PrivateTop));
6654 		    pt = (PrivateTop *)(*barg->aff);
6655 		    memset((void *)pt, 0, sizeof(PrivateTop));
6656 		}
6657 	    }
6658 
6659 	    fs_give((void **)&to);
6660 	    to = p;
6661 	}
6662 	else
6663 	  fs_give((void **)&p);
6664 
6665 	if(dummy)
6666 	  fs_give((void **)&dummy);
6667 
6668 
6669 	/*
6670 	 * This part is recording the fact that the To line was set to
6671 	 * what it is by entering something on the Lcc line. In particular,
6672 	 * if a list alias was entered here then the fullname of the list
6673 	 * goes in the To line. We save this affector information so that
6674 	 * we can tell it shouldn't be modified if we call build_addr_lcc
6675 	 * again unless we actually modified what's in the Lcc line so that
6676 	 * it doesn't start with the same thing. The problem we're solving
6677 	 * is that the contents of the Lcc line no longer look like the
6678 	 * list they were derived from.
6679 	 * Pt will point to headents[To].bldr_private.
6680 	 */
6681 	if(barg && barg->aff)
6682 	  pt = (PrivateTop *)(*barg->aff);
6683 
6684 	if(pt && (af=pt->affector) && af->who == BP_Lcc){
6685 	    int len;
6686 
6687 	    len = strlen(lcc);
6688 	    if(len >= af->cksumlen){
6689 		int save;
6690 
6691 		save = lcc[af->cksumlen];
6692 		lcc[af->cksumlen] = '\0';
6693 		csum = line_hash(lcc);
6694 		lcc[af->cksumlen] = save;
6695 	    }
6696 	    else
6697 	      csum = af->cksumval + 1;		/* so they aren't equal */
6698 	}
6699 
6700 	if(!pt ||
6701 	   !pt->affector ||
6702 	   pt->affector->who != BP_Lcc ||
6703 	   (pt->affector->who == BP_Lcc && csum != pt->affector->cksumval)){
6704 
6705 	    /* replace to value */
6706 	    if(barg->tptr && barg->tptr[0]){
6707 		size_t l;
6708 		char *t;
6709 
6710 		l = strlen(barg->tptr) + strlen(to ? to : "") + 2;
6711 		t = (char *)fs_get((l+1) * sizeof(char));
6712 		snprintf(t, l+1, "%s%s%s",
6713 			 barg->tptr,
6714 			 (to && *to) ? ", " : "",
6715 			 (to && *to) ? to : "");
6716 		fs_give((void **)&barg->tptr);
6717 		if(to)
6718 		  fs_give((void **)&to);
6719 
6720 		barg->tptr = t;
6721 	    }
6722 	    else{
6723 		if(barg->tptr)
6724 		  fs_give((void **)&barg->tptr);
6725 
6726 		barg->tptr = to;
6727 	    }
6728 
6729 	    if(barg->aff){
6730 		if(!pt){
6731 		    *barg->aff = (void *)fs_get(sizeof(PrivateTop));
6732 		    pt = (PrivateTop *)(*barg->aff);
6733 		    memset((void *)pt, 0, sizeof(PrivateTop));
6734 		}
6735 
6736 		if(no_repo){
6737 		    if(!pt->affector)
6738 		      pt->affector =
6739 			    (PrivateAffector *)fs_get(sizeof(PrivateAffector));
6740 
6741 		    af = pt->affector;
6742 		    af->who = BP_Lcc;
6743 		    af->cksumlen = strlen(((full_lcc && *full_lcc)
6744 							    ? *full_lcc : ""));
6745 		    af->cksumval = line_hash(((full_lcc && *full_lcc)
6746 							    ? *full_lcc : ""));
6747 		}
6748 		else{
6749 		    /*
6750 		     * If result is reproducible, we don't keep track here.
6751 		     */
6752 		    if(pt->affector)
6753 		      fs_give((void **)&pt->affector);
6754 		}
6755 	    }
6756 	}
6757 	else
6758 	  fs_give((void **)&to);  /* unused in this case */
6759     }
6760 
6761     if(fcc_local){
6762 	unsigned long csum;
6763 
6764 	/*
6765 	 * If *barg->next->aff is set, that means fcc was set from a list
6766 	 * during some previous builder call. If the current Lcc line
6767 	 * contains the old expansion as a prefix, then we should leave
6768 	 * things as they are. In order to decide that we look at a hash
6769 	 * value computed from the strings.
6770 	 * Pt will point to headents[Fcc].bldr_private
6771 	 */
6772 	pt = NULL;
6773 	if(barg && barg->next && barg->next->aff)
6774 	  pt = (PrivateTop *)(*barg->next->aff);
6775 
6776 	if(pt && (af=pt->affector) && af->who == BP_Lcc){
6777 	    int len;
6778 
6779 	    len = strlen(lcc);
6780 	    if(len >= af->cksumlen){
6781 		int save;
6782 
6783 		save = lcc[af->cksumlen];
6784 		lcc[af->cksumlen] = '\0';
6785 		csum = line_hash(lcc);
6786 		lcc[af->cksumlen] = save;
6787 	    }
6788 	    else
6789 	      csum = af->cksumval + 1;  /* something not equal to cksumval */
6790 	}
6791 
6792 	if(!pt ||
6793 	   !pt->affector ||
6794 	   pt->affector->who != BP_Lcc ||
6795 	   (pt->affector->who == BP_Lcc && csum != pt->affector->cksumval)){
6796 
6797 	    /* replace fcc value */
6798 	    if(barg->next->tptr)
6799 	      fs_give((void **)&barg->next->tptr);
6800 
6801 	    barg->next->tptr = fcc_local;
6802 
6803 	    if(barg->next->aff){
6804 		if(!pt){
6805 		    *barg->next->aff = (void *)fs_get(sizeof(PrivateTop));
6806 		    pt = (PrivateTop *)(*barg->next->aff);
6807 		    memset((void *)pt, 0, sizeof(PrivateTop));
6808 		}
6809 
6810 		if(no_repo){
6811 		    if(!pt->affector)
6812 		      pt->affector =
6813 			    (PrivateAffector *)fs_get(sizeof(PrivateAffector));
6814 
6815 		    af = pt->affector;
6816 		    af->who = BP_Lcc;
6817 		    af->cksumlen = strlen(((full_lcc && *full_lcc)
6818 							    ? *full_lcc : ""));
6819 		    af->cksumval = line_hash(((full_lcc && *full_lcc)
6820 							    ? *full_lcc : ""));
6821 		}
6822 		else{
6823 		    /*
6824 		     * If result is reproducible, we don't keep track here.
6825 		     */
6826 		    if(pt->affector)
6827 		      fs_give((void **)&pt->affector);
6828 		}
6829 	    }
6830 	}
6831 	else
6832 	  fs_give((void **)&fcc_local);  /* unused in this case */
6833     }
6834 
6835 
6836     if(error != NULL && *error == NULL)
6837       *error = cpystr("");
6838 
6839     memcpy(addrbook_changed_unexpectedly, save_jmp_buf, sizeof(jmp_buf));
6840     flush_status_messages(0);
6841     return(ret_val);
6842 }
6843 
6844 
6845 /*----------------------------------------------------------------------
6846     Verify and canonicalize news groups names.
6847     Called from the message composer
6848 
6849 Args:  given_group    -- List of groups typed by user
6850        expanded_group -- pointer to point to expanded list, which will be
6851 			 allocated here and freed in caller.  If this is
6852 			 NULL, don't attempt to validate.
6853        error          -- pointer to store error message
6854        fcc            -- pointer to point to fcc, which will be
6855 			 allocated here and freed in caller
6856 
6857 Returns:  0 if all is OK
6858          -1 if addresses weren't valid
6859 
6860 Test the given list of newstroups against those recognized by our nntp
6861 servers.  Testing by actually trying to open the list is much cheaper, both
6862 in bandwidth and memory, than yanking the whole list across the wire.
6863   ----*/
6864 int
6865 news_build(char *given_group, char **expanded_group, char **error, BUILDER_ARG *fcc, int *mangled)
6866 {
6867     int	  rv;
6868     char *fccptr = NULL;
6869 
6870     if(fcc && fcc->tptr)
6871       fccptr = cpystr(fcc->tptr);
6872 
6873     clear_cursor_pos();
6874 
6875     rv = news_grouper(given_group, expanded_group, error, &fccptr, news_build_busy);
6876 
6877     /* assign any new fcc to the BUILDER_ARG */
6878     if(fccptr){
6879 	if(fcc){
6880 	    /* it changed */
6881 	    if(fcc->tptr && strcmp(fcc->tptr, fccptr)){
6882 		fs_give((void **) &fcc->tptr);
6883 		fcc->tptr = fccptr;
6884 		fccptr = NULL;
6885 	    }
6886 	}
6887 
6888 	if(fccptr)
6889 	  fs_give((void **) &fccptr);
6890     }
6891 
6892     /* deal with any busy indicator */
6893     if(news_busy_cue){
6894 	news_busy_cue = 0;
6895 	cancel_busy_cue(0);
6896 	mark_status_dirty();
6897 	display_message('x');
6898 	if(mangled)
6899 	  *mangled |= BUILDER_MESSAGE_DISPLAYED;
6900     }
6901 
6902 
6903     return(rv);
6904 }
6905 
6906 
6907 void
6908 news_build_busy(void)
6909 {
6910     news_busy_cue = busy_cue("Validating newsgroup(s)", NULL, 0);
6911 }
6912 
6913 
6914 #if defined(DOS) || defined(OS2)
6915 
6916 /*----------------------------------------------------------------------
6917     Verify that the necessary pieces are around to allow for
6918     message sending under DOS
6919 
6920 Args:  strict -- tells us if a remote stream is required before
6921 		 sending is permitted.
6922 
6923 The idea is to make sure pine knows enough to put together a valid
6924 from line.  The things we MUST know are a user-id, user-domain and
6925 smtp server to dump the message off on.  Typically these are
6926 provided in pine's configuration file, but if not, the user is
6927 queried here.
6928  ----*/
6929 int
6930 dos_valid_from()
6931 {
6932     char        prompt[100], answer[80];
6933     int         rc, i, flags;
6934     HelpType    help;
6935 
6936     /*
6937      * query for user name portion of address, use IMAP login
6938      * name as default
6939      */
6940     if(!ps_global->VAR_USER_ID || ps_global->VAR_USER_ID[0] == '\0'){
6941 	NETMBX mb;
6942 	int no_prompt_user_id = 0;
6943 
6944 	if(ps_global->mail_stream && ps_global->mail_stream->mailbox
6945 	   && mail_valid_net_parse(ps_global->mail_stream->mailbox, &mb)
6946 	   && *mb.user){
6947 	    strncpy(answer, mb.user, sizeof(answer)-1);
6948 	    answer[sizeof(answer)-1] = '\0';
6949 	}
6950 	else if(F_ON(F_QUELL_USER_ID_PROMPT, ps_global)){
6951 	    /* no user-id prompting if set */
6952 	    no_prompt_user_id = 1;
6953 	    rc = 0;
6954 	    if(!ps_global->mail_stream)
6955 	      do_broach_folder(ps_global->inbox_name,
6956 			       ps_global->context_list, NULL, DB_INBOXWOCNTXT);
6957 	    if(ps_global->mail_stream && ps_global->mail_stream->mailbox
6958 	       && mail_valid_net_parse(ps_global->mail_stream->mailbox, &mb)
6959 	       && *mb.user){
6960 		strncpy(answer, mb.user, sizeof(answer)-1);
6961 		answer[sizeof(answer)-1] = '\0';
6962 	    }
6963 	    else
6964 	      answer[0] = '\0';
6965 	}
6966 	else
6967 	  answer[0] = '\0';
6968 
6969 	if(F_ON(F_QUELL_USER_ID_PROMPT, ps_global) && answer[0]){
6970 	    /* No prompt, just assume mailbox login is user-id */
6971 	    no_prompt_user_id = 1;
6972 	    rc = 0;
6973 	}
6974 
6975 	snprintf(prompt,sizeof(prompt),_("User-id for From address : "));
6976 	prompt[sizeof(prompt)-1] = '\0';
6977 
6978 	help = NO_HELP;
6979 	while(!no_prompt_user_id) {
6980 	    flags = OE_APPEND_CURRENT;
6981 	    rc = optionally_enter(answer,-FOOTER_ROWS(ps_global),0,
6982 				  sizeof(answer),prompt,NULL,help,&flags);
6983 	    if(rc == 2)
6984 	      continue;
6985 
6986 	    if(rc == 3){
6987 		help = (help == NO_HELP) ? h_sticky_user_id : NO_HELP;
6988 		continue;
6989 	    }
6990 
6991 	    if(rc != 4)
6992 	      break;
6993 	}
6994 
6995 	if(rc == 1 || (rc == 0 && !answer[0])) {
6996 	    q_status_message(SM_ORDER, 3, 4,
6997 		   _("Send cancelled (User-id must be provided before sending)"));
6998 	    return(0);
6999 	}
7000 
7001 	/* save the name */
7002 	snprintf(prompt, sizeof(prompt), _("Preserve %.*s as \"user-id\" in PINERC"),
7003 		sizeof(prompt)-50, answer);
7004 	prompt[sizeof(prompt)-1] = '\0';
7005 	if(ps_global->blank_user_id
7006 	   && !no_prompt_user_id
7007 	   && want_to(prompt, 'y', 'n', NO_HELP, WT_NORM) == 'y'){
7008 	    set_variable(V_USER_ID, answer, 1, 1, Main);
7009 	}
7010 	else{
7011             fs_give((void **)&(ps_global->VAR_USER_ID));
7012 	    ps_global->VAR_USER_ID = cpystr(answer);
7013 	}
7014     }
7015 
7016     /* query for personal name */
7017     if(!ps_global->VAR_PERSONAL_NAME || ps_global->VAR_PERSONAL_NAME[0]=='\0'
7018 	&& F_OFF(F_QUELL_PERSONAL_NAME_PROMPT, ps_global)){
7019 	answer[0] = '\0';
7020 	snprintf(prompt, sizeof(prompt), _("Personal name for From address : "));
7021 	prompt[sizeof(prompt)-1] = '\0';
7022 
7023 	help = NO_HELP;
7024 	while(1) {
7025 	    flags = OE_APPEND_CURRENT;
7026 	    rc = optionally_enter(answer,-FOOTER_ROWS(ps_global),0,
7027 				  sizeof(answer),prompt,NULL,help,&flags);
7028 	    if(rc == 2)
7029 	      continue;
7030 
7031 	    if(rc == 3){
7032 		help = (help == NO_HELP) ? h_sticky_personal_name : NO_HELP;
7033 		continue;
7034 	    }
7035 
7036 	    if(rc != 4)
7037 	      break;
7038     	}
7039 
7040 	if(rc == 0 && answer){		/* save the name */
7041 	    snprintf(prompt, sizeof(prompt), _("Preserve %.*s as \"personal-name\" in PINERC"),
7042 		    sizeof(prompt)-50, answer);
7043 	    prompt[sizeof(prompt)-1] = '\0';
7044 	    if(ps_global->blank_personal_name
7045 	       && want_to(prompt, 'y', 'n', NO_HELP, WT_NORM) == 'y'){
7046 		set_variable(V_PERSONAL_NAME, answer, 1, 1, Main);
7047 	    }
7048 	    else{
7049         	fs_give((void **)&(ps_global->VAR_PERSONAL_NAME));
7050 		ps_global->VAR_PERSONAL_NAME = cpystr(answer);
7051 	    }
7052 	}
7053     }
7054 
7055     /*
7056      * query for host/domain portion of address, using IMAP
7057      * host as default
7058      */
7059     if(ps_global->blank_user_domain
7060        || ps_global->maildomain == ps_global->localdomain
7061        || ps_global->maildomain == ps_global->hostname){
7062 	if(ps_global->inbox_name[0] == '{'){
7063 	    for(i=0;
7064 		i < sizeof(answer)-1 && ps_global->inbox_name[i+1] != '}'; i++)
7065 		answer[i] = ps_global->inbox_name[i+1];
7066 
7067 	    answer[i] = '\0';
7068 	}
7069 	else
7070 	  answer[0] = '\0';
7071 
7072 	snprintf(prompt,sizeof(prompt),_("Host/domain for From address : "));
7073 	prompt[sizeof(prompt)-1] = '\0';
7074 
7075 	help = NO_HELP;
7076 	while(1) {
7077 	    flags = OE_APPEND_CURRENT;
7078 	    rc = optionally_enter(answer,-FOOTER_ROWS(ps_global),0,
7079 				  sizeof(answer),prompt,NULL,help,&flags);
7080 	    if(rc == 2)
7081 	      continue;
7082 
7083 	    if(rc == 3){
7084 		help = (help == NO_HELP) ? h_sticky_domain : NO_HELP;
7085 		continue;
7086 	    }
7087 
7088 	    if(rc != 4)
7089 	      break;
7090 	}
7091 
7092 	if(rc == 1 || (rc == 0 && !answer[0])) {
7093 	    q_status_message(SM_ORDER, 3, 4,
7094 	  _("Send cancelled (Host/domain name must be provided before sending)"));
7095 	    return(0);
7096 	}
7097 
7098 	/* save the name */
7099 	snprintf(prompt, sizeof(prompt), _("Preserve %.*s as \"user-domain\" in PINERC"),
7100 		sizeof(prompt)-50, answer);
7101 	prompt[sizeof(prompt)-1] = '\0';
7102 	if(!ps_global->userdomain && !ps_global->blank_user_domain
7103 	   && want_to(prompt, 'y', 'n', NO_HELP, WT_NORM) == 'y'){
7104 	    set_variable(V_USER_DOMAIN, answer, 1, 1, Main);
7105 	    fs_give((void **)&(ps_global->maildomain));	/* blast old val */
7106 	    ps_global->userdomain      = cpystr(answer);
7107 	    ps_global->maildomain      = ps_global->userdomain;
7108 	}
7109 	else{
7110             fs_give((void **)&(ps_global->maildomain));
7111             ps_global->userdomain = cpystr(answer);
7112 	    ps_global->maildomain = ps_global->userdomain;
7113 	}
7114     }
7115 
7116     /* check for smtp server */
7117     if(!ps_global->VAR_SMTP_SERVER ||
7118        !ps_global->VAR_SMTP_SERVER[0] ||
7119        !ps_global->VAR_SMTP_SERVER[0][0]){
7120 	char **list;
7121 
7122 	if(ps_global->inbox_name[0] == '{'){
7123 	    for(i=0;
7124 		i < sizeof(answer)-1 && ps_global->inbox_name[i+1] != '}'; i++)
7125 	      answer[i] = ps_global->inbox_name[i+1];
7126 
7127 	    answer[i] = '\0';
7128 	}
7129 	else
7130           answer[0] = '\0';
7131 
7132         snprintf(prompt,sizeof(prompt),_("SMTP server to forward message : "));
7133 	prompt[sizeof(prompt)-1] = '\0';
7134 
7135 	help = NO_HELP;
7136         while(1) {
7137 	    flags = OE_APPEND_CURRENT;
7138             rc = optionally_enter(answer,-FOOTER_ROWS(ps_global),0,
7139 				  sizeof(answer),prompt,NULL,help,&flags);
7140             if(rc == 2)
7141                   continue;
7142 
7143 	    if(rc == 3){
7144 		help = (help == NO_HELP) ? h_sticky_smtp : NO_HELP;
7145 		continue;
7146 	    }
7147 
7148             if(rc != 4)
7149                   break;
7150         }
7151 
7152         if(rc == 1 || (rc == 0 && answer[0] == '\0')) {
7153             q_status_message(SM_ORDER, 3, 4,
7154 	       _("Send cancelled (SMTP server must be provided before sending)"));
7155             return(0);
7156         }
7157 
7158 	/* save the name */
7159         list    = (char **) fs_get(2 * sizeof(char *));
7160 	list[0] = cpystr(answer);
7161 	list[1] = NULL;
7162 	set_variable_list(V_SMTP_SERVER, list, TRUE, Main);
7163 	fs_give((void *)&list[0]);
7164 	fs_give((void *)list);
7165     }
7166 
7167     return(1);
7168 }
7169 
7170 #endif /* defined(DOS) || defined(OS2) */
7171