1 #if !defined(lint) && !defined(DOS)
2 static char rcsid
[] = "$Id: send.c 1142 2008-08-13 17:22:21Z hubert@u.washington.edu $";
6 * ========================================================================
7 * Copyright 2013-2020 Eduardo Chappa
8 * Copyright 2006-2008 University of Washington
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
14 * http://www.apache.org/licenses/LICENSE-2.0
16 * ========================================================================
19 /*======================================================================
20 Functions for composing and sending mail
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"
68 typedef struct body_particulars
{
69 unsigned short type
, encoding
, had_csp
;
70 char *subtype
, *charset
;
75 * macro to bind pico's headerentry pointer to PINEFIELD "extdata" hook
77 #define HE(PF) ((struct headerentry *)((PF)->extdata))
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
*);
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) */
122 * Pointer to buffer to hold pointers into pine data that's needed by pico.
127 static char *g_rolenick
= NULL
;
130 static char *sending_filter_requested
;
131 static char background_requested
, flowing_requested
;
132 static unsigned call_mailer_flags
;
133 static char *priority_requested
;
135 /* local global to save busy_cue state */
136 static int news_busy_cue
= 0;
140 * Various useful strings
143 _("Continue INTERRUPTED composition (answering \"n\" won't erase it)")
145 _("Continue postponed composition (answering \"No\" won't erase it)")
147 _("Start composition from Form Letter Folder")
148 #define PSTPN_FORM_PMT \
149 _("Save to Postponed or Form letter folder? ")
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")
157 * Macros to help sort out posting results
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
170 #define COMPOSE_MAIL_TITLE "COMPOSE MESSAGE"
174 * For check_for_subject and check_for_fcc
177 #define CF_MISSING 0x2
180 /*----------------------------------------------------------------------
181 Compose screen (not forward or reply). Set up envelope, call composer
183 Args: pine_state -- The usual pine structure
185 Little front end for the compose screen
188 compose_screen(struct pine
*pine_state
)
190 void (*prev_screen
)(struct pine
*) = pine_state
->prev_screen
,
191 (*redraw
)(void) = pine_state
->redrawer
;
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
;
202 /*----------------------------------------------------------------------
203 Alternate compose screen. Set up role and call regular compose.
205 Args: pine_state -- The usual pine structure
208 alt_compose_screen(struct pine
*pine_state
)
210 ACTION_S
*role
= NULL
;
211 void (*prev_screen
)(struct pine
*) = pine_state
->prev_screen
,
212 (*redraw
)(void) = pine_state
->redrawer
;
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 */
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
;
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.
232 role
= combine_inherited_role(role
);
234 role
= (ACTION_S
*)fs_get(sizeof(*role
));
235 memset((void *)role
, 0, sizeof(*role
));
236 role
->nick
= cpystr("Default Role");
239 pine_state
->redrawer
= NULL
;
240 compose_mail(NULL
, NULL
, role
, NULL
, NULL
);
242 pine_state
->next_screen
= prev_screen
;
243 pine_state
->redrawer
= redraw
;
247 /*----------------------------------------------------------------------
248 Format envelope for outgoing message and call editor
250 Args: given_to -- An address to send mail to (usually from command line
252 fcc_arg -- The fcc that goes with this address.
254 If a "To" line is given format that into the envelope and get ready to call
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.
259 NOTE: we ignore postponed and interrupted messages in nr mode
262 compose_mail(char *given_to
, char *fcc_arg
, ACTION_S
*role_arg
,
263 PATMT
*attach
, gf_io_t inc_text_getc
)
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
;
276 int fcc_is_sticky
= 0,
283 "\n\n ---- COMPOSE SCREEN (not in pico yet) ----\n"));
285 /*-- Check for INTERRUPTED mail --*/
286 if(!role_arg
&& !(given_to
|| attach
)){
287 char file_path
[MAXPATH
+1];
289 /* build filename and see if it exists. build_path creates
290 * an explicit local path name, so all c-client access is thru
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
));
299 /* check to see if the folder exists, the user wants to continue
300 * and that we can actually read something in...
302 if(folder_exists(NULL
, file_path
) & FEX_ISFILE
)
306 /*-- Check for postponed mail --*/
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])
314 /*-- Check for form letter folder --*/
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])
322 if(!outgoing
&& !(given_to
|| attach
)
323 && !role_arg
&& F_ON(F_ALT_COMPOSE_MENU
, ps_global
)){
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];
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;
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
;
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
;
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
;
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
;
369 compose_style
[ekey_num
].ch
= -1;
371 if(F_ON(F_BLANK_KEYMENU
,ps_global
)){
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
;
380 if(compose_style
[ekey_num
+ 1].ch
!= -1 && p
- letters
< sizeof(letters
))
384 if(p
- letters
< sizeof(letters
))
388 which_help
= intrptd
+ 2 * postponed
+ 4 * form
;
391 help
= h_compose_intrptd
;
394 help
= h_compose_postponed
;
397 help
= h_compose_intrptd_postponed
;
400 help
= h_compose_form
;
403 help
= h_compose_intrptd_form
;
406 help
= h_compose_postponed_form
;
409 help
= h_compose_intrptd_postponed_form
;
412 help
= h_compose_default
;
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';
421 chosen_task
= radio_buttons(prompt
, -FOOTER_ROWS(ps_global
),
422 compose_style
, 'n', 'x', help
, RB_NORM
);
423 intrptd
= postponed
= form
= 0;
434 void (*prev_screen
)(struct pine
*) = ps_global
->prev_screen
,
435 (*redraw
)(void) = ps_global
->redrawer
;
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
;
446 ps_global
->next_screen
= prev_screen
;
447 ps_global
->redrawer
= redraw
;
449 role
= combine_inherited_role(role
);
458 q_status_message(SM_ORDER
, 0, 3,
459 "Composition cancelled");
468 if(intrptd
&& !outgoing
){
469 char file_path
[MAXPATH
+1];
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
){
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
)){
487 pine_mail_close(stream
);
494 /* redraft() may or may not have closed stream */
496 pine_mail_close(stream
);
498 postponed
= form
= 0;
501 pine_mail_close(stream
);
503 q_status_message(SM_ORDER
, 0, 3,
504 _("Composition cancelled"));
510 q_status_message1(SM_ORDER
| SM_DING
, 3, 3,
511 _("Can't open Interrupted mailbox: %s"),
514 pine_mail_close(stream
);
519 if(postponed
&& !outgoing
){
520 int ret
= 'n', done
= 0;
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
))
533 /* stream may or may not be closed in redraft() */
534 if(stream
&& (stream
!= ps_global
->mail_stream
))
535 pine_mail_close(stream
);
541 if(stream
!= ps_global
->mail_stream
)
542 pine_mail_close(stream
);
545 q_status_message(SM_ORDER
, 0, 3,
546 _("Composition cancelled"));
551 else if(F_ON(F_ALT_COMPOSE_MENU
, ps_global
))
558 if(form
&& !outgoing
){
559 int ret
= 'n', done
= 0;
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
))
571 /* stream may or may not be closed in redraft() */
572 if(stream
&& (stream
!= ps_global
->mail_stream
))
573 pine_mail_close(stream
);
576 intrptd
= postponed
= 0;
579 if(stream
!= ps_global
->mail_stream
)
580 pine_mail_close(stream
);
583 q_status_message(SM_ORDER
, 0, 3,
584 _("Composition cancelled"));
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!"));
601 /*-- normal composition --*/
603 int impl
, template_len
= 0;
604 long rflags
= ROLE_COMPOSE
;
607 /*================= Compose new message ===============*/
608 body
= mail_newbody();
609 outgoing
= mail_newenvelope();
612 rfc822_parse_adrlist(&outgoing
->to
, given_to
, ps_global
->maildomain
);
615 * Setup possible role
618 role
= copy_action(role_arg
);
621 /* Setup possible compose role */
622 if(nonempty_patterns(rflags
, &dummy
)){
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
630 role
= set_role_from_msg(ps_global
, rflags
, -1L, NULL
);
632 if(confirm_role(rflags
, &role
))
633 role
= combine_inherited_role(role
);
634 else{ /* cancel reply */
636 cmd_cancelled("Composition");
643 q_status_message1(SM_ORDER
, 3, 4, _("Composing using role \"%s\""),
646 outgoing
->message_id
= generate_message_id(role
);
648 * The type of storage object allocated below is vitally
649 * important. See SIMPLIFYING ASSUMPTION #37
651 if((body
->contents
.text
.data
= (void *) so_get(PicoText
,
652 NULL
, EDIT_ACCESS
)) != NULL
){
656 while((*inc_text_getc
)(&ch
))
657 if(!so_writec(ch
, (STORE_S
*)body
->contents
.text
.data
)){
663 q_status_message(SM_ORDER
| SM_DING
, 3, 4,
664 _("Problem creating space for message text."));
668 if(role
&& role
->template){
671 impl
= 1; /* leave cursor in header if not explicit */
672 filtered
= detoken(role
, NULL
, 0, 0, 0, &redraft_pos
, &impl
);
675 so_puts((STORE_S
*)body
->contents
.text
.data
, filtered
);
677 template_len
= strlen(filtered
);
680 fs_give((void **)&filtered
);
686 if((sig
= detoken(role
, NULL
, 2, 0, 1, &redraft_pos
, &impl
)) != NULL
){
688 redraft_pos
->offset
+= template_len
;
691 so_puts((STORE_S
*)body
->contents
.text
.data
, sig
);
693 fs_give((void **)&sig
);
696 body
->type
= TYPETEXT
;
699 create_message_body(&body
, attach
, 0);
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 */
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.
711 char *tmp_fcc
= NULL
;
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 */
719 else if((tmp_fcc
= get_fcc(NULL
)) != NULL
&&
720 !strcmp(fcc
, tmp_fcc
)){
727 fs_give((void **)&tmp_fcc
);
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));
736 fs_give((void **) &reply
->mailbox
);
738 fs_give((void **) &reply
->origmbox
);
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
);
747 fs_give((void **)&fcc_to_free
);
750 fs_give((void **)&lcc
);
752 mail_free_envelope(&outgoing
);
753 pine_free_body(&body
);
754 free_redraft_pos(&redraft_pos
);
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.
763 These are all return values:
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
)
787 if(!(streamp
&& *streamp
))
793 * If we're manipulating the current folder, don't bother
797 if(REDRAFT_PPND
&flags
)
798 q_status_message(SM_ORDER
| SM_DING
, 3, 5, _("Empty folder! No messages really postponed!"));
800 q_status_message(SM_ORDER
| SM_DING
, 3, 5, _("Empty folder! No messages really interrupted!"));
802 return(redraft_cleanup(streamp
, FALSE
, flags
));
804 else if(stream
== ps_global
->mail_stream
805 && ps_global
->prev_screen
== mail_index_screen
){
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...
811 cont_msg
= mn_m2raw(ps_global
->msgmap
, mn_get_cur(ps_global
->msgmap
));
813 else if(stream
->nmsgs
> 1L){ /* offer browser ? */
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
)));
821 else{ /* set to top form letter */
822 mn_set_cur(sp_msgmap(stream
), 1L);
825 clear_index_cache(stream
, 0);
829 ti
= stop_threading_temporarily();
830 rv
= index_lister(ps_global
, NULL
, stream
->mailbox
,
831 stream
, sp_msgmap(stream
));
832 restore_threading(&ti
);
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"));
840 q_status_message(SM_ORDER
, 3, 3, _("Undelete form letters you want to keep, and then continue message"));
848 clear_index_cache(stream
, 0);
851 q_status_message(SM_ORDER
, 0, 3, _("Composition cancelled"));
852 (void) redraft_cleanup(streamp
, FALSE
, flags
);
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"
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;
865 do_broach_folder(ps_global
->inbox_name
,
866 ps_global
->context_list
, NULL
, DB_INBOXWOCNTXT
);
868 ps_global
->next_screen
= mail_index_screen
;
871 return(0); /* special case */
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
,
885 redraft_prompt(char *type
, char *prompt
, int failure
)
887 if(background_posting(FALSE
)){
888 q_status_message1(SM_ORDER
, 0, 3,
889 _("%s folder unavailable while background posting"),
894 return(want_to(prompt
, 'y', 'x', NO_HELP
, WT_NORM
));
898 /* this is for initializing the fixed header elements in pine_send() */
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
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
}
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
};
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
};
1003 /*----------------------------------------------------------------------
1004 Get addressee for message, then post message
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
1016 Result: message "To: " field is provided and message is sent or cancelled.
1025 subject passed in, NOT edited but maybe canonized here
1026 to possibly passed in, edited and canonized here
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
1036 Returns 0 on success, -1 on failure.
1039 pine_simple_send(ENVELOPE
*outgoing
, /* envelope for outgoing message */
1040 struct mail_bodystruct
**body
,
1044 char **used_tobufval
,
1047 char **tobufp
, *p
, tmp
[MAILTMPLEN
];
1049 int done
= 0, retval
= 0, x
;
1050 int lastrc
, rc
= 0, ku
, i
, resize_len
, result
, fcc_result
;
1053 static HISTORY_S
*history
= NULL
;
1057 ACTION_S
*role
= rolep
? *rolep
: NULL
;
1060 dprint((1,"\n === simple send called === \n"));
1062 memset(&ba_fcc
, 0, sizeof(BUILDER_ARG
));
1064 init_hist(&history
, HISTSIZE
);
1066 header
= pine_simple_send_header(outgoing
, &ba_fcc
.tptr
, &tobufp
);
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
);
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
);
1077 outgoing
->date
= (unsigned char *) cpystr(tmp_20k_buf
);
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"));
1085 outgoing
->from
= copyaddrlist(role
->from
);
1088 outgoing
->from
= generate_from();
1091 if(!(flagsarg
& SS_NULLRP
))
1092 outgoing
->return_path
= rfc822_cpy_adr(outgoing
->from
);
1094 ekey
[i
= 0].ch
= ctrl('T');
1096 ekey
[i
].name
= "^T";
1097 ekey
[i
++].label
= N_("To AddrBk");
1099 if(F_ON(F_ENABLE_TAB_COMPLETE
,ps_global
)){
1100 ekey
[i
].ch
= ctrl('I');
1102 ekey
[i
].name
= "TAB";
1103 ekey
[i
++].label
= N_("Complete");
1106 if(nonempty_patterns(ROLE_DO_ROLES
, &pstate
) && first_pattern(&pstate
)){
1107 ekey
[i
].ch
= ctrl('R');
1109 ekey
[i
].name
= "^R";
1110 ekey
[i
++].label
= "Set Role";
1113 ekey
[i
].ch
= KEY_UP
;
1117 ekey
[i
++].label
= "";
1119 ekey
[i
].ch
= KEY_DOWN
;
1122 ekey
[i
++].label
= "";
1126 if(outgoing
->remail
== NULL
)
1127 strcpy(tmp
, _("FORWARD (as e-mail) to : "));
1129 /*----------------------------------------------------------------------
1130 Loop editing the "To: " field until everything goes well
1137 if(outgoing
->message_id
)
1138 fs_give((void **) &outgoing
->message_id
);
1140 outgoing
->message_id
= generate_message_id(role
);
1142 if(outgoing
->remail
){
1144 snprintf(tmp
, sizeof(tmp
), _("BOUNCE (redirect) message using role \"%s\" to : "), role
->nick
);
1146 strncpy(tmp
, _("BOUNCE (redirect) message to : "), sizeof(tmp
));
1147 tmp
[sizeof(tmp
)-1] = '\0';
1152 outgoing2strings(header
, *body
, &messagebuf
, NULL
, 1);
1156 if(flagsarg
& SS_PROMPTFORTO
){
1158 *tobufp
= cpystr("");
1160 resize_len
= MAX(MAXPATH
, strlen(*tobufp
));
1161 fs_resize((void **) tobufp
, resize_len
+1);
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
;
1171 ekey
[ku
].label
= "";
1172 ekey
[ku
+1].name
= "";
1173 ekey
[ku
+1].label
= "";
1176 flags
= OE_APPEND_CURRENT
;
1178 rc
= optionally_enter(*tobufp
, -FOOTER_ROWS(ps_global
),
1183 ekey
, help
, &flags
);
1190 q_status_message(SM_ORDER
| SM_DING
, 3, 4,
1191 "Internal problem encountered");
1196 case 15 : /* set a role */
1197 {void (*prev_screen
)(struct pine
*) = NULL
, (*redraw
)(void) = NULL
;
1199 redraw
= ps_global
->redrawer
;
1200 ps_global
->redrawer
= NULL
;
1201 prev_screen
= ps_global
->prev_screen
;
1203 ps_global
->next_screen
= SCREEN_FUN_NULL
;
1205 if(role_select_screen(ps_global
, &role
,
1206 outgoing
->remail
? MC_BOUNCE
: MC_FORWARD
) < 0)
1207 cmd_cancelled(_("Set Role"));
1210 role
= combine_inherited_role(role
);
1212 role
= (ACTION_S
*) fs_get(sizeof(*role
));
1213 memset((void *) role
, 0, sizeof(*role
));
1214 role
->nick
= cpystr("Default Role");
1221 ps_global
->next_screen
= prev_screen
;
1222 ps_global
->redrawer
= redraw
;
1223 ps_global
->mangled_screen
= 1;
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
);
1233 if(rolep
) *rolep
= role
;
1238 if((p
= get_prev_hist(history
, *tobufp
, 0, NULL
)) != NULL
){
1239 strncpy(*tobufp
, p
, resize_len
);
1240 (*tobufp
)[resize_len
-1] = '\0';
1248 if((p
= get_next_hist(history
, *tobufp
, 0, NULL
)) != NULL
){
1249 strncpy(*tobufp
, p
, resize_len
);
1250 (*tobufp
)[resize_len
-1] = '\0';
1259 {void (*redraw
) (void) = ps_global
->redrawer
;
1260 char *returned_addr
= NULL
;
1264 int got_something
= 0;
1266 push_titlebar_state();
1267 returned_addr
= addr_book_bounce();
1270 * Just make it look like user typed this list in.
1274 if((l
=resize_len
) < (len
= strlen(returned_addr
)) + 1){
1276 fs_resize((void **) tobufp
, (size_t) (l
+1));
1279 strncpy(*tobufp
, returned_addr
, l
);
1280 (*tobufp
)[l
] = '\0';
1281 fs_give((void **)&returned_addr
);
1285 pop_titlebar_state();
1287 if((ps_global
->redrawer
= redraw
) != NULL
) /* reset old value, and test */
1288 (*ps_global
->redrawer
)();
1294 if(*tobufp
&& **tobufp
!= '\0'){
1295 char *errbuf
, *addr
;
1298 save_hist(history
, *tobufp
, 0, NULL
);
1303 * If role has an fcc, use it instead of what build_address
1306 if(role
&& role
->fcc
){
1308 fs_give((void **) &ba_fcc
.tptr
);
1310 ba_fcc
.tptr
= cpystr(role
->fcc
);
1313 if(build_address(*tobufp
, &addr
, &errbuf
,
1314 (role
&& role
->fcc
) ? NULL
: &ba_fcc
, NULL
) >= 0){
1318 fs_give((void **)&errbuf
);
1320 if((l
=strlen(*tobufp
)) < (tolen
= strlen(addr
)) + 1){
1322 fs_resize((void **) tobufp
, (size_t) (l
+1));
1325 strncpy(*tobufp
, addr
, l
);
1326 (*tobufp
)[l
] = '\0';
1328 *used_tobufval
= cpystr(addr
);
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;
1337 strings2outgoing(header
, body
, NULL
, 0);
1339 if((flagsarg
& SS_PROMPTFORTO
)
1340 && ((x
= check_addresses(header
)) == CA_BAD
1341 || (x
== CA_EMPTY
&& F_OFF(F_FCC_ON_BOUNCE
,
1343 /*--- Addresses didn't check out---*/
1350 opts
[i
++].label
= N_("Yes");
1355 opts
[i
++].label
= N_("No");
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');
1362 opts
[i
].name
= "^W";
1363 verbose_label
= i
++;
1364 if(F_ON(F_DSN
, ps_global
)){
1368 opts
[i
++].label
= "";
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 */
1379 opts
[i
].label
= "DSNOpts";
1384 opts
[i
++].label
= "";
1388 opts
[i
++].label
= "";
1392 opts
[i
++].label
= "";
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
)
1407 (call_mailer_flags
& CM_VERBOSE
)
1408 ? "in verbose mode" : "",
1409 (dsn_show
&& (call_mailer_flags
& CM_VERBOSE
))
1411 (dsn_show
) ? dsn_string
: "",
1412 ((call_mailer_flags
& CM_VERBOSE
) || dsn_show
)
1416 : (F_ON(F_FCC_ON_BOUNCE
, ps_global
)
1417 && ba_fcc
.tptr
&& ba_fcc
.tptr
[0])
1420 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
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);
1428 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
1431 opts
[verbose_label
].label
=
1432 /* TRANSLATORS: several possible key labels follow */
1433 (call_mailer_flags
& CM_VERBOSE
) ? N_("Normal") : N_("Verbose");
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");
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! */
1462 else if(rv
== 'n'){ /* Declined! */
1465 else if(rv
== 'z'){ /* Cancelled! */
1468 else if(rv
== 12){ /* flip verbose bit */
1469 if(call_mailer_flags
& CM_VERBOSE
)
1470 call_mailer_flags
&= ~CM_VERBOSE
;
1472 call_mailer_flags
|= CM_VERBOSE
;
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
);
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
);
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
);
1493 else if(rv
== 'h'){ /* flip full bit */
1494 call_mailer_flags
^= CM_DSN_FULL
;
1497 else if(rv
== 'd'){ /* show dsn options */
1498 call_mailer_flags
|= (CM_DSN_SHOW
| CM_DSN_SUCCESS
| CM_DSN_DELAY
| CM_DSN_FULL
);
1501 snprintf(dsn_string
, sizeof(dsn_string
), _("DSN requested[%s%s%s%s]"),
1502 (call_mailer_flags
& CM_DSN_NEVER
)
1504 (call_mailer_flags
& CM_DSN_DELAY
)
1506 (call_mailer_flags
& CM_DSN_SUCCESS
)
1508 (call_mailer_flags
& CM_DSN_NEVER
)
1510 : (call_mailer_flags
& CM_DSN_FULL
) ? "-Full"
1512 dsn_string
[sizeof(dsn_string
)-1] = '\0';
1517 fs_give((void **)&addr
);
1519 if(!(flagsarg
& SS_PROMPTFORTO
) || sendit
){
1521 CONTEXT_S
*fcc_cntxt
= NULL
;
1523 if(F_ON(F_FCC_ON_BOUNCE
, ps_global
)){
1525 fcc
= cpystr(ba_fcc
.tptr
);
1530 * If special name "inbox" then replace it with the
1533 if(ps_global
->VAR_INBOX_PATH
1534 && strucmp(fcc
, ps_global
->inbox_name
) == 0){
1537 replace_fcc
= cpystr(ps_global
->VAR_INBOX_PATH
);
1538 fs_give((void **) &fcc
);
1543 /*---- Check out fcc -----*/
1545 (void) commence_fcc(fcc
, &fcc_cntxt
, FALSE
);
1547 dprint((4,"can't open fcc, cont\n"));
1548 if(!(flagsarg
& SS_PROMPTFORTO
)){
1550 fs_give((void **)&fcc
);
1558 so_truncate(lmc
.so
, fcc_size_guess(*body
) + 2048);
1563 if(!(outgoing
->to
|| outgoing
->cc
|| outgoing
->bcc
1565 q_status_message(SM_ORDER
, 3, 5, _("No recipients specified!"));
1569 if(outgoing
->to
|| outgoing
->cc
|| outgoing
->bcc
){
1570 char **alt_smtp
= NULL
;
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"));
1577 alt_smtp
= role
->smtp
;
1580 result
= call_mailer(header
, *body
, alt_smtp
,
1582 call_mailer_file_result
,
1584 mark_address_failure_for_pico(header
);
1589 if(result
== 1 && !lmc
.so
)
1590 q_status_message(SM_ORDER
, 0, 3, _("Message sent"));
1592 /*----- Was there an fcc involved? -----*/
1596 && pine_rfc822_output(header
, *body
, NULL
, NULL
))){
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';
1606 /* Now actually copy to fcc folder and close */
1608 write_fcc(fcc
, fcc_cntxt
, lmc
.so
, NULL
,
1610 F_ON(F_MARK_FCC_SEEN
, ps_global
)
1613 else if(result
== 0){
1614 q_status_message(SM_ORDER
,3,5,
1615 _("Fcc Failed!. No message saved."));
1617 dprint((1, "explicit fcc write failed!\n"));
1624 dprint((1, "Bounce failed\n"));
1625 if(!(flagsarg
& SS_PROMPTFORTO
))
1630 else if(result
== 1){
1632 q_status_message(SM_ORDER
, 0, 3,
1635 int avail
= ps_global
->ttyo
->screen_cols
-2;
1637 char *part1
= "Message sent and ";
1638 char *part2
= fcc_result
? "" : "NOT ";
1639 char *part3
= "copied to ";
1640 fcclen
= strlen(fcc
);
1642 need
= 2 + strlen(part1
) + strlen(part2
) +
1643 strlen(part3
) + fcclen
;
1645 if(need
> avail
&& fcclen
> 6)
1646 fcclen
-= MIN(fcclen
-6, need
-avail
);
1648 q_status_message4(SM_ORDER
, 0, 3,
1650 part1
, part2
, part3
,
1652 (char *)tmp_20k_buf
,
1654 fcclen
, FrontDots
));
1659 fs_give((void **)&fcc
);
1662 q_status_message(SM_ORDER
, 0, 3, _("Send cancelled"));
1667 q_status_message1(SM_ORDER
| SM_DING
, 3, 5,
1668 _("Error in address: %s"), errbuf
);
1670 fs_give((void **)&errbuf
);
1672 if(!(flagsarg
& SS_PROMPTFORTO
))
1680 q_status_message(SM_ORDER
| SM_DING
, 3, 5,
1681 _("No addressee! No e-mail sent."));
1690 q_status_message(SM_ORDER
, 0, 3, _("Send cancelled"));
1696 help
= (help
== NO_HELP
)
1697 ? (outgoing
->remail
== NULL
1705 char *new_nickname
= NULL
;
1709 ambiguity
= abook_nickname_complete(*tobufp
, &new_nickname
,
1710 (lastrc
==rc
&& !(flags
& OE_USER_MODIFIED
)), ANC_AFTERCOMMA
);
1713 if((l
=strlen(new_nickname
)) > resize_len
){
1715 fs_resize((void **) tobufp
, resize_len
+1);
1718 strncpy(*tobufp
, new_nickname
, l
);
1719 (*tobufp
)[l
] = '\0';
1722 fs_give((void **) &new_nickname
);
1731 case 4: /* can't suspend */
1739 fs_give((void **)&ba_fcc
.tptr
);
1741 pine_free_env(&header
);
1748 * pine_simple_send_header - generate header suitable for simple_sending
1751 pine_simple_send_header(ENVELOPE
*outgoing
, char **fccp
, char ***tobufpp
)
1755 static struct headerentry he_dummy
;
1757 header
= pine_new_env(outgoing
, fccp
, tobufpp
, NULL
);
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
;
1773 /*----------------------------------------------------------------------
1774 Prepare data structures for pico, call pico, then post message
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
1782 custom -- custom header list.
1785 Result: message is edited, then postponed, cancelled or sent.
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
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
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
1809 There's a further assumption that the text in the TYPETEXT part is
1810 stored in a storage object (see filter.c).
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
)
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
;
1824 struct headerentry
*he
, *headents
, *he_to
, *he_fcc
, *he_news
= NULL
, *he_lcc
= NULL
,
1826 PINEFIELD
*pfields
, *pf
, *pf_nobody
= NULL
, *pf_to
= NULL
,
1827 *pf_smtp_server
, *pf_nntp_server
,
1828 *pf_fcc
= NULL
, *pf_err
, *pf_uid
, *pf_mbox
, *pf_curpos
,
1829 *pf_ourrep
, *pf_ourhdrs
, **sending_order
;
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
;
1837 REDRAFT_POS_S
*local_redraft_pos
= NULL
;
1839 dprint((1,"\n=== send called ===\n"));
1841 save_previous_pbuf
= pbf
;
1843 standard_picobuf_setup(pbf
);
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.
1850 if(ps_global
->in_init_seq
){
1851 ps_global
->in_init_seq
= 0;
1852 ps_global
->save_in_init_seq
= 0;
1854 if(ps_global
->initial_cmds
){
1855 if(ps_global
->free_initial_cmds
)
1856 fs_give((void **)&(ps_global
->free_initial_cmds
));
1858 ps_global
->initial_cmds
= 0;
1861 F_SET(F_USE_FK
,ps_global
,ps_global
->orig_use_fkeys
);
1864 #if defined(DOS) || defined(OS2)
1865 if(!dos_valid_from()){
1866 pbf
= save_previous_pbuf
;
1872 pbf
->upload
= (ps_global
->VAR_UPLOAD_CMD
1873 && ps_global
->VAR_UPLOAD_CMD
[0])
1874 ? upload_msg_to_pico
: NULL
;
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
;
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
;
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
;
1919 if(redraft_pos
&& editor_title
&& !strcmp(editor_title
, COMPOSE_MAIL_TITLE
))
1920 pbf
->pine_flags
|= P_CHKPTNOW
;
1922 /* NOTE: initial cursor position set below */
1924 dprint((9, "flags: %x\n", pbf
->pine_flags
));
1927 * When user runs compose and the current folder is a newsgroup,
1928 * offer to post to the current newsgroup.
1930 if(!(outgoing
->to
|| (outgoing
->newsgroups
&& *outgoing
->newsgroups
))
1931 && IS_NEWS(ps_global
->mail_stream
)){
1932 char prompt
[200], news_group
[MAILTMPLEN
];
1934 pine_send_newsgroup_name(ps_global
->mail_stream
->mailbox
, news_group
,
1935 sizeof(news_group
));
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.
1942 if(news_group
[0] && !outgoing
->subject
){
1945 char *errmsg
= NULL
;
1946 BUILDER_ARG
*fcc_build
= NULL
;
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
);
1957 if(outgoing
->newsgroups
)
1958 fs_give((void **)&outgoing
->newsgroups
);
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
;
1966 ret_val
= news_build(news_group
, &outgoing
->newsgroups
,
1967 &errmsg
, fcc_build
, NULL
);
1970 if(outgoing
->newsgroups
)
1971 fs_give((void **)&outgoing
->newsgroups
);
1973 outgoing
->newsgroups
= cpystr(news_group
);
1976 if(!fcc_arg
&& !(role
&& role
->fcc
)){
1977 fcc_arg
= fcc_to_free
= fcc_build
->tptr
;
1978 fs_give((void **)&fcc_build
);
1983 q_status_message(SM_ORDER
, 3, 3, errmsg
);
1984 display_message(NO_OP_COMMAND
);
1987 fs_give((void **)&errmsg
);
1993 q_status_message(SM_ORDER
, 0, 3, _("Message cancelled"));
1994 dprint((4, "=== send: cancelled\n"));
1995 pbf
= save_previous_pbuf
;
2006 if(F_ON(F_PREDICT_NNTP_SERVER
, ps_global
)
2007 && outgoing
->newsgroups
&& *outgoing
->newsgroups
2008 && IS_NEWS(ps_global
->mail_stream
)){
2011 if(mail_valid_net_parse(ps_global
->mail_stream
->original_mailbox
,
2013 if(!strucmp(news_mb
.service
, "nntp")){
2014 if(*ps_global
->mail_stream
->original_mailbox
== '{'){
2015 char *svcp
= NULL
, *psvcp
;
2017 suggested_nntp_server
=
2018 cpystr(ps_global
->mail_stream
->original_mailbox
+ 1);
2019 if((p
= strindex(suggested_nntp_server
, '}')) != NULL
)
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))
2026 else if(!struncmp(p
, "/service=nntp", 13))
2028 else if(!struncmp(p
, "/service=\"nntp\"", 15))
2035 else if(*svcp
== '/' || *svcp
== ':'){
2036 for(psvcp
= p
; *svcp
; svcp
++, psvcp
++)
2045 suggested_nntp_server
= cpystr(news_mb
.orighost
);
2050 * If we don't already have custom headers set and the role has custom
2051 * headers, then incorporate those custom headers into "custom".
2054 PINEFIELD
*dflthdrs
= NULL
, *rolehdrs
= NULL
;
2056 dflthdrs
= parse_custom_hdrs(ps_global
->VAR_CUSTOM_HDRS
, UseAsDef
);
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
2069 #ifdef WANT_TO_COMBINE_ADDRESSES
2070 if(role
&& role
->cstm
)
2071 rolehdrs
= parse_custom_hdrs(role
->cstm
, Combine
);
2073 if(role
&& role
->cstm
)
2074 rolehdrs
= parse_custom_hdrs(role
->cstm
, Replace
);
2078 custom
= combine_custom_headers(dflthdrs
, rolehdrs
);
2080 free_prompts(dflthdrs
);
2081 free_customs(dflthdrs
);
2085 free_prompts(rolehdrs
);
2086 free_customs(rolehdrs
);
2093 g_rolenick
= role
? role
->nick
: NULL
;
2095 /* how many fixed fields are there? */
2096 for(fixed_cnt
= 0; pf_template
&& pf_template
[fixed_cnt
].name
; fixed_cnt
++)
2099 total_cnt
= fixed_cnt
+ count_custom_hdrs_pf(custom
,1);
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
);
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
);
2111 i
= total_cnt
* sizeof(PINEFIELD
*);
2112 sending_order
= (PINEFIELD
**)fs_get((size_t) i
);
2113 memset(sending_order
, 0, (size_t) i
);
2115 pbf
->headents
= headents
;
2116 header
.env
= outgoing
;
2117 header
.local
= pfields
;
2118 header
.sending_order
= sending_order
;
2120 /* custom part of PINEFIELDs */
2121 header
.custom
= custom
;
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().
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
2141 * He->realaddr is the pointer to the text that pico actually edits.
2144 #if !(defined(DOS) || defined(OS2)) || defined(NOAUTH)
2150 if(outgoing
->newsgroups
&& *outgoing
->newsgroups
)
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)
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
];
2171 /* copy the templates */
2172 *he
= he_template
[index
];
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
++)
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
;
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
;
2194 case FreeText
: /* realaddr points to c-client env */
2195 if(index
== N_NEWS
){
2196 sending_order
[1] = pf
;
2197 he
->realaddr
= &outgoing
->newsgroups
;
2200 switch(set_default_hdrval(pf
, custom
)){
2203 fs_give((void **)he
->realaddr
);
2205 *he
->realaddr
= pf
->textbuf
;
2211 if(*he
->realaddr
){ /* combine values */
2212 if(pf
->textbuf
&& *pf
->textbuf
){
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';
2225 fs_give((void **)he
->realaddr
);
2226 *he
->realaddr
= combined_hdr
;
2227 q_status_message(SM_ORDER
, 3, 3,
2228 "Adding newsgroup from role");
2233 *he
->realaddr
= pf
->textbuf
;
2240 /* if no value, use default */
2242 *he
->realaddr
= pf
->textbuf
;
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 */
2257 fs_give((void **)&pf
->textbuf
);
2259 pf
->text
= he
->realaddr
;
2261 else if(index
== N_DATE
){
2262 sending_order
[2] = pf
;
2263 pf
->text
= (char **) &outgoing
->date
;
2266 else if(index
== N_INREPLY
){
2267 sending_order
[NN
+9] = pf
;
2268 pf
->text
= &outgoing
->in_reply_to
;
2271 else if(index
== N_MSGID
){
2272 sending_order
[NN
+10] = pf
;
2273 pf
->text
= &outgoing
->message_id
;
2276 else if(index
== N_REF
){
2277 sending_order
[NN
+11] = pf
;
2278 pf
->text
= &outgoing
->references
;
2281 else if(index
== N_PRIORITY
){
2282 sending_order
[NN
+12] = pf
;
2283 pf
->text
= &pf
->textbuf
;
2286 else if(index
== N_USERAGENT
){
2287 sending_order
[NN
+13] = pf
;
2288 pf
->text
= &pf
->textbuf
;
2289 pf
->textbuf
= generate_user_agent();
2292 else if(index
== N_POSTERR
){
2293 sending_order
[NN
+14] = pf
;
2295 pf
->text
= &pf
->textbuf
;
2298 else if(index
== N_RPLUID
){
2299 sending_order
[NN
+15] = pf
;
2301 pf
->text
= &pf
->textbuf
;
2304 else if(index
== N_RPLMBOX
){
2305 sending_order
[NN
+16] = pf
;
2307 pf
->text
= &pf
->textbuf
;
2310 else if(index
== N_SMTP
){
2311 sending_order
[NN
+17] = pf
;
2312 pf_smtp_server
= pf
;
2313 pf
->text
= &pf
->textbuf
;
2316 else if(index
== N_NNTP
){
2317 sending_order
[NN
+18] = pf
;
2318 pf_nntp_server
= pf
;
2319 pf
->text
= &pf
->textbuf
;
2322 else if(index
== N_CURPOS
){
2323 sending_order
[NN
+19] = pf
;
2325 pf
->text
= &pf
->textbuf
;
2328 else if(index
== N_OURREPLYTO
){
2329 sending_order
[NN
+20] = pf
;
2331 pf
->text
= &pf
->textbuf
;
2334 else if(index
== N_OURHDRS
){
2335 sending_order
[NN
+21] = pf
;
2337 pf
->text
= &pf
->textbuf
;
2340 else if(index
== N_AUTHRCVD
){
2341 sending_order
[0] = pf
;
2343 pf
->text
= &pf
->textbuf
;
2347 q_status_message(SM_ORDER
| SM_DING
, 3, 7,
2348 "Botched: Unmatched FreeText header in pine_send");
2353 /* can't do a default for this one */
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 */
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"));
2370 outgoing
->from
= copyaddrlist(role
->from
);
2371 he
->display_it
= 1; /* show it */
2372 he
->rich_header
= 0;
2380 sending_order
[NN
+2] = pf
;
2381 pf
->addr
= &outgoing
->to
;
2382 /* If already set, make it act like we typed it in */
2384 && outgoing
->to
->mailbox
2385 && outgoing
->to
->mailbox
[0]
2386 && flags
& PS_STICKY_TO
)
2394 sending_order
[NN
+5] = pf
;
2396 if(ps_global
->VAR_EMPTY_HDR_MSG
2397 && !ps_global
->VAR_EMPTY_HDR_MSG
[0]){
2401 nobody_addr
= mail_newaddr();
2402 nobody_addr
->next
= mail_newaddr();
2403 nobody_addr
->mailbox
= cpystr(rfc1522_encode(tmp_20k_buf
,
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
;
2415 sending_order
[NN
+3] = pf
;
2416 pf
->addr
= &outgoing
->cc
;
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...
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
);
2437 outgoing
->reply_to
= copyaddrlist(role
->replyto
);
2438 he
->display_it
= 1; /* show it */
2439 he
->rich_header
= 0;
2445 sending_order
[NN
+7] = pf
;
2446 pf
->addr
= &lcc_addr
;
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
);
2458 #if !(defined(DOS) || defined(OS2)) || defined(NOAUTH)
2460 sending_order
[4] = pf
;
2461 pf
->addr
= &outgoing
->sender
;
2466 q_status_message1(SM_ORDER
,3,7,
2467 "Internal error: Address header %s", comatose(index
));
2472 * If this is a reply to news, don't show the regular email
2473 * recipient headers (unless they are non-empty).
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
);
2491 he
->rich_header
= 1; /* hide */
2495 * If this address doesn't already have a value, then we check
2496 * for a default value assigned by the user.
2498 else if(pf
->addr
&& !*pf
->addr
){
2499 if((ct
=set_default_hdrval(pf
, custom
)) >= UseAsDef
&&
2501 (!ps_global
->never_allow_changing_from
&&
2502 F_ON(F_ALLOW_CHANGING_FROM
, ps_global
))) &&
2503 pf
->textbuf
&& *pf
->textbuf
){
2505 removing_trailing_white_space(pf
->textbuf
);
2506 (void)removing_double_quotes(pf
->textbuf
);
2509 * Try to set To based on Lcc. Don't attempt Fcc.
2511 if(index
== N_LCC
&& !he_to
->sticky
&& pf_to
&& pf_to
->addr
){
2512 BUILDER_ARG
*barg
= NULL
;
2516 ppp
= addr_list_string(*pf_to
->addr
, NULL
, 1);
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
);
2527 build_addr_lcc(pf
->textbuf
, &addr
, NULL
, barg
, NULL
);
2530 rfc822_parse_adrlist(pf
->addr
, addr
,
2531 ps_global
->maildomain
);
2533 fs_give((void **) &addr
);
2538 if(barg
&& barg
->tptr
&& strcmp(ppp
, barg
->tptr
)){
2541 rfc822_parse_adrlist(&a
, barg
->tptr
,
2542 ps_global
->maildomain
);
2545 mail_free_address(pf_to
->addr
);
2553 fs_give((void **) &barg
->tptr
);
2555 fs_give((void **) &barg
);
2559 fs_give((void **) &ppp
);
2562 build_address(pf
->textbuf
, &addr
, NULL
, NULL
, NULL
);
2563 rfc822_parse_adrlist(pf
->addr
, addr
,
2564 ps_global
->maildomain
);
2566 fs_give((void **) &addr
);
2573 /* if we still don't have a from */
2574 if(index
== N_FROM
&& !*pf
->addr
)
2575 *pf
->addr
= generate_from();
2579 * Addr is already set in the rest of the cases.
2581 else if((index
== N_FROM
|| index
== N_REPLYTO
) && pf
->addr
){
2582 ADDRESS
*adr
= NULL
;
2585 * We get to this case of the ifelse if the from or reply-to
2586 * addr was set by a role above.
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
);
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 */
2605 if(!(*pf
->addr
)->mailbox
){
2606 fs_give((void **)pf
->addr
);
2611 mail_free_address(&adr
);
2613 else if((index
== N_TO
|| index
== N_CC
|| index
== N_BCC
)
2615 ADDRESS
*a
= NULL
, **tail
;
2618 * These three are different from the others because we
2619 * might add the addresses to what is already there instead
2623 switch(set_default_hdrval(pf
, custom
)){
2626 mail_free_address(pf
->addr
);
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
);
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
);
2644 for(tail
= pf
->addr
; *tail
; tail
= &(*tail
)->next
)
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
);
2660 he
->display_it
= 1; /* start this off showing */
2663 switch(set_default_hdrval(pf
, custom
)){
2667 mail_free_address(pf
->addr
);
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
);
2685 if(pf
->addr
&& *pf
->addr
&& !(*pf
->addr
)->mailbox
){
2686 mail_free_address(pf
->addr
);
2687 he
->display_it
= 1; /* start this off showing */
2690 if(pf
->textbuf
) /* free default value in any case */
2691 fs_give((void **)&pf
->textbuf
);
2693 /* outgoing2strings will alloc the string pf->scratch below */
2694 he
->realaddr
= &pf
->scratch
;
2698 sending_order
[NN
+8] = pf
;
2700 if(role
&& role
->fcc
)
2703 fcc
= get_fcc(fcc_arg
);
2706 fs_give((void **)&fcc_to_free
);
2710 if(((flags
& PS_STICKY_FCC
) && fcc
[0]) || (role
&& role
->fcc
))
2716 if(strcmp(fcc
, ps_global
->VAR_DEFAULT_FCC
) != 0)
2717 he
->display_it
= 1; /* start this off showing */
2719 he
->realaddr
= &fcc
;
2725 sending_order
[NN
+6] = pf
;
2727 switch(set_default_hdrval(pf
, custom
)){
2730 pf
->scratch
= pf
->textbuf
;
2733 if(outgoing
->subject
)
2734 fs_give((void **)&outgoing
->subject
);
2740 /* if no value, use default */
2741 if(outgoing
->subject
){
2742 pf
->scratch
= cpystr(outgoing
->subject
);
2745 pf
->scratch
= pf
->textbuf
;
2752 he
->realaddr
= &pf
->scratch
;
2753 pf
->text
= &outgoing
->subject
;
2757 q_status_message1(SM_ORDER
,3,7,
2758 "Unknown header type %d in pine_send",
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
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.
2774 * For other types, just not setting canedit will cause it to be
2775 * uneditable, regardless of what the user does.
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\""));
2787 memset(he
, 0, (size_t)sizeof(*he
));
2793 if(!pf
->canedit
&& he
->rich_header
){
2794 memset(he
, 0, (size_t)sizeof(*he
));
2806 memset(he
, 0, (size_t)sizeof(*he
));
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.
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.
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
;
2831 (--pf
)->next
= (total_cnt
!= fixed_cnt
) ? header
.custom
: NULL
;
2833 i
--; /* subtract one because N_ATTCH doesn't get a sending_order slot */
2835 * Set up headerentries for custom fields.
2836 * NOTE: "i" is assumed to now index first custom field in sending
2839 for(pf
= pf
->next
; pf
&& pf
->name
; pf
= pf
->next
){
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
);
2864 fs_give((void **)&pf
->textbuf
);
2866 he
->realaddr
= &pf
->scratch
;
2867 if(F_OFF(F_ENABLE_TAB_COMPLETE
,ps_global
))
2868 he
->nickcmpl
= NULL
;
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 */
2885 q_status_message1(SM_ORDER
,0,7,"Unknown custom header type %d",
2890 he
->name
= pf
->name
;
2892 /* use first 8 characters for prompt */
2893 he
->prompt
= cpystr(" : ");
2894 strncpy(he
->prompt
, he
->name
, MIN(strlen(he
->name
), he
->prwid
- 2));
2896 he
->rich_header
= view_as_rich(he
->name
, he
->rich_header
);
2901 * Make sure at least *one* field is displayable...
2903 for(index
= -1, i
=0, pf
=header
.local
; pf
&& pf
->name
; pf
=pf
->next
, i
++)
2904 if(HE(pf
) && !HE(pf
)->rich_header
){
2910 * None displayable!!! Warn and display defaults.
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
)
2918 HE(pf
)->rich_header
= 0;
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.
2926 if ((*body
)->type
== TYPEMULTIPART
)
2927 bp
= save_body_particulars(&(*body
)->nested
.part
->body
);
2929 bp
= save_body_particulars(*body
);
2932 local_redraft_pos
= redraft_pos
;
2934 /*----------------------------------------------------------------------
2935 Loop calling the editor until everything goes well
2938 int saved_user_timeout
;
2940 /* Reset body to what it was when we started. */
2941 if ((*body
)->type
== TYPEMULTIPART
)
2942 reset_body_particulars(bp
, &(*body
)->nested
.part
->body
);
2944 reset_body_particulars(bp
,*body
);
2946 * set initial cursor position based on how many times we've been
2949 if(reply
&& reply
->pseudo
){
2950 pbf
->pine_flags
|= reply
->data
.pico_flags
;
2952 else if(body_start
){
2953 pbf
->pine_flags
|= P_BODY
;
2954 body_start
= 0; /* maybe not next time */
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
2962 HE(pf
)->start_here
= 1;
2966 /* If didn't find it, we start in body. */
2967 if(!pf
|| !pf
->name
)
2968 pbf
->pine_flags
|= P_BODY
;
2970 else if(reply
&& (!reply
->forw
&& !reply
->forwarded
)){
2971 pbf
->pine_flags
|= P_BODY
;
2974 /* in case these were turned on in previous pass through loop */
2976 pf_nobody
->writehdr
= 0;
2977 pf_nobody
->localcopy
= 0;
2981 pf_fcc
->localcopy
= 0;
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...
2989 STORE_S
**so
= (STORE_S
**)(((*body
)->type
== TYPEMULTIPART
)
2990 ? &(*body
)->nested
.part
->body
.contents
.text
.data
2991 : &(*body
)->contents
.text
.data
);
2998 * Convert the envelope and body to the string format that
3001 outgoing2strings(&header
, *body
, &pbf
->msgtext
, &pbf
->attachments
, 0);
3003 for(pf
= header
.local
; pf
&& pf
->name
; pf
= pf
->next
){
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.
3010 if(pf
->type
== FreeText
&& HE(pf
) && !*HE(pf
)->realaddr
)
3011 *HE(pf
)->realaddr
= cpystr("");
3013 if(pf
->type
!= Attachment
&& HE(pf
) && *HE(pf
)->realaddr
)
3014 HE(pf
)->maxlen
= strlen(*HE(pf
)->realaddr
);
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.
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
)
3027 (HE(pf
)->display_it
|| !HE(pf
)->rich_header
) &&
3029 (!*HE(pf
)->realaddr
|| !**HE(pf
)->realaddr
)){
3030 HE(pf
)->start_here
= 1;
3036 mswin_setwindowmenu (MENU_COMPOSER
);
3039 cancel_busy_cue(-1);
3040 flush_status_messages(1);
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
;
3051 mswin_setwindowmenu (MENU_DEFAULT
);
3053 fix_windsize(ps_global
);
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.
3060 if(!(editor_result
& COMP_GOTHUP
))
3061 init_signals(); /* Pico has it's own signal stuff */
3064 * We're going to save in DEADLETTER. Dump attachments first.
3066 if(editor_result
& COMP_CANCEL
)
3067 free_attachment_list(&pbf
->attachments
);
3069 /* Turn strings back into structures */
3070 strings2outgoing(&header
, body
, pbf
->attachments
, flowing_requested
);
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
));
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
));
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
);
3093 removing_trailing_white_space(fcc
);
3095 /*-------- Stamp it with a current date -------*/
3096 if(outgoing
->date
) /* update old date */
3097 fs_give((void **)&(outgoing
->date
));
3099 if(F_ON(F_QUELL_TIMEZONE
, ps_global
))
3100 mail_parameters(NULL
, SET_DISABLE822TZTEXT
, (void *) TRUE
);
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
);
3106 outgoing
->date
= (unsigned char *) cpystr(tmp_20k_buf
);
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
);
3112 outgoing
->return_path
= rfc822_cpy_adr(outgoing
->from
);
3115 * Don't ever believe the sender that is there.
3116 * If From doesn't look quite right, generate our own sender.
3118 if(outgoing
->sender
)
3119 mail_free_address(&outgoing
->sender
);
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).
3126 * Don't add a personal_name since the user can change that.
3128 if(F_OFF(F_DISABLE_SENDER
, ps_global
)
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))){
3137 outgoing
->sender
= mail_newaddr();
3138 outgoing
->sender
->mailbox
= cpystr(ps_global
->VAR_USER_ID
);
3139 outgoing
->sender
->host
= cpystr(ps_global
->hostname
);
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
);
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];
3155 dprint((4, "pine_send:%s handling\n",
3156 (editor_result
& COMP_SUSPEND
)
3158 : (editor_result
& COMP_GOTHUP
)
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");
3170 * The idea here is to use the Fcc: writing facility
3171 * to append to the special postponed message folder...
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...
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"));
3194 * Build the local message copy so.
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.
3202 * In the Postpone case, just create it if the user wants to
3203 * and create a temporary storage object to write into. */
3205 lmc
.all_written
= lmc
.text_only
= lmc
.text_written
= 0;
3206 if(editor_result
& (COMP_GOTHUP
| COMP_CANCEL
)){
3208 time_t now
= time((time_t *)0);
3210 #if defined(DOS) || defined(OS2)
3212 * we can't assume anything about root or home dirs, so
3213 * just plunk it down in the same place as the pinerc
3215 if(!getenv("HOME")){
3216 char *lc
= last_cmpnt(ps_global
->pinerc
);
3219 strncpy(folder
,ps_global
->pinerc
,
3220 MIN(lc
-ps_global
->pinerc
,sizeof(folder
)-1));
3221 folder
[MIN(lc
-ps_global
->pinerc
,sizeof(folder
)-1)]='\0';
3224 strncat(folder
, (editor_result
& COMP_GOTHUP
)
3225 ? INTERRUPTED_MAIL
: DEADLETTER
,
3226 sizeof(folder
)-strlen(folder
)-1);
3231 ps_global
->VAR_OPER_DIR
3232 ? ps_global
->VAR_OPER_DIR
: ps_global
->home_dir
,
3233 (editor_result
& COMP_GOTHUP
)
3234 ? INTERRUPTED_MAIL
: DEADLETTER
,
3237 if(editor_result
& COMP_CANCEL
){
3238 char filename
[MAXPATH
+1], newfname
[MAXPATH
+1], nbuf
[5];
3240 if(strlen(folder
) + 1 < sizeof(filename
))
3241 for(i
= ps_global
->deadlets
- 1; i
> 0 && i
< 9; i
--){
3242 strncpy(filename
, folder
, sizeof(filename
));
3243 filename
[sizeof(filename
)-1] = '\0';
3244 strncpy(newfname
, filename
, sizeof(newfname
));
3245 newfname
[sizeof(newfname
)-1] = '\0';
3248 snprintf(nbuf
, sizeof(nbuf
), "%d", i
);
3249 nbuf
[sizeof(nbuf
)-1] = '\0';
3250 strncat(filename
, nbuf
,
3251 sizeof(filename
)-strlen(filename
)-1);
3252 filename
[sizeof(filename
)-1] = '\0';
3255 snprintf(nbuf
, sizeof(nbuf
), "%d", i
+1);
3256 nbuf
[sizeof(nbuf
)-1] = '\0';
3257 strncat(newfname
, nbuf
,
3258 sizeof(newfname
)-strlen(newfname
)-1);
3259 newfname
[sizeof(newfname
)-1] = '\0';
3260 (void) rename_file(filename
, newfname
);
3266 newfile
= can_access(folder
, ACCESS_EXISTS
);
3268 if((lmc
.so
= so_get(FCC_SOURCE
, NULL
, WRITE_ACCESS
)) != NULL
){
3269 if (outgoing
->from
){
3270 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, "%sFrom %s@%s %.24s\015\012",
3271 newfile
? "" : "\015\012",
3272 outgoing
->from
->mailbox
,
3273 outgoing
->from
->host
, ctime(&now
));
3274 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
3275 if(!so_puts(lmc
.so
, tmp_20k_buf
)){
3276 if(editor_result
& COMP_CANCEL
)
3277 q_status_message2(SM_ORDER
| SM_DING
, 3, 3,
3278 "Can't write \"%s\": %s",
3279 folder
, error_description(errno
));
3281 dprint((1, "* * * CAN'T WRITE %s: %s\n",
3282 folder
? folder
: "?",
3283 error_description(errno
)));
3288 else{ /* Must be COMP_SUSPEND */
3289 if(!ps_global
->VAR_POSTPONED_FOLDER
3290 || !ps_global
->VAR_POSTPONED_FOLDER
[0]){
3291 q_status_message(SM_ORDER
| SM_DING
, 3, 3,
3292 _("No postponed file defined"));
3297 * Store the cursor position
3299 * First find the header entry with the start_here
3300 * bit set, if any. This means the editor is telling
3301 * us to start on this header field next time.
3303 start_here_name
= NULL
;
3304 for(pf
= header
.local
; pf
&& pf
->name
; pf
= pf
->next
)
3305 if(HE(pf
) && HE(pf
)->start_here
){
3306 start_here_name
= pf
->name
;
3310 /* If there wasn't one, ":" means we start in the body. */
3311 if(!start_here_name
|| !*start_here_name
)
3312 start_here_name
= ":";
3314 if(ps_global
->VAR_FORM_FOLDER
3315 && ps_global
->VAR_FORM_FOLDER
[0]
3316 && postpone_prompt() == 'f'){
3317 strncpy(folder
, ps_global
->VAR_FORM_FOLDER
,
3319 folder
[sizeof(folder
)-1] = '\0';
3320 strncpy(label
, "form letter", sizeof(label
));
3321 label
[sizeof(label
)-1] = '\0';
3324 strncpy(folder
, ps_global
->VAR_POSTPONED_FOLDER
,
3326 folder
[sizeof(folder
)-1] = '\0';
3327 strncpy(label
, "postponed message", sizeof(label
));
3328 label
[sizeof(label
)-1] = '\0';
3331 lmc
.so
= open_fcc(folder
,&fcc_cntxt
, 1, NULL
, NULL
);
3338 /* copy fcc line to postponed or interrupted folder */
3340 pf_fcc
->localcopy
= 1;
3342 /* plug error into header for later display to user */
3343 if((editor_result
& ~0xff) && (lmq
= last_message_queued()) != NULL
){
3344 pf_err
->writehdr
= 1;
3345 pf_err
->localcopy
= 1;
3346 pf_err
->textbuf
= lmq
;
3350 * if reply, write (UID)folder header field so we can
3351 * later flag the replied-to message \\ANSWERED
3352 * DON'T save MSGNO's.
3354 if(reply
&& reply
->uid
){
3355 char uidbuf
[MAILTMPLEN
], *p
;
3358 for(i
= 0L, p
= tmp_20k_buf
; reply
->data
.uid
.msgs
[i
]; i
++){
3360 sstrncpy(&p
, ",", SIZEOF_20KBUF
-(p
-tmp_20k_buf
));
3362 sstrncpy(&p
,ulong2string(reply
->data
.uid
.msgs
[i
]),SIZEOF_20KBUF
-(p
-tmp_20k_buf
));
3365 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
3367 pf_uid
->writehdr
= 1;
3368 pf_uid
->localcopy
= 1;
3369 snprintf(uidbuf
, sizeof(uidbuf
), "(%s%s%s)(%ld %lu %s)%s",
3370 reply
->prefix
? int2string(strlen(reply
->prefix
))
3371 : (reply
->forwarded
) ? "": "0 ",
3372 reply
->prefix
? " " : "",
3373 reply
->prefix
? reply
->prefix
: "",
3374 i
, reply
->data
.uid
.validity
,
3375 tmp_20k_buf
, reply
->mailbox
);
3376 uidbuf
[sizeof(uidbuf
)-1] = '\0';
3377 pf_uid
->textbuf
= cpystr(uidbuf
);
3380 * Logically, this ought to be part of pf_uid, but this
3381 * was added later and so had to be in a separate header
3382 * for backwards compatibility.
3384 pf_mbox
->writehdr
= 1;
3385 pf_mbox
->localcopy
= 1;
3386 pf_mbox
->textbuf
= cpystr(reply
->origmbox
3391 /* Save cursor position */
3392 if(start_here_name
&& *start_here_name
){
3393 char curposbuf
[MAILTMPLEN
];
3395 pf_curpos
->writehdr
= 1;
3396 pf_curpos
->localcopy
= 1;
3397 snprintf(curposbuf
, sizeof(curposbuf
), "%s %ld", start_here_name
,
3399 curposbuf
[sizeof(curposbuf
)-1] = '\0';
3400 pf_curpos
->textbuf
= cpystr(curposbuf
);
3404 * Work around c-client reply-to bug. C-client will
3405 * return a reply_to in an envelope even if there is
3406 * no reply-to header field. We want to note here whether
3407 * the reply-to is real or not.
3409 if(outgoing
->reply_to
|| hdr_is_in_list("reply-to", custom
)){
3410 pf_ourrep
->writehdr
= 1;
3411 pf_ourrep
->localcopy
= 1;
3412 if(outgoing
->reply_to
)
3413 pf_ourrep
->textbuf
= cpystr("Full");
3415 pf_ourrep
->textbuf
= cpystr("Empty");
3418 /* Save the role-specific smtp server */
3419 if(role
&& role
->smtp
&& role
->smtp
[0]){
3420 char *q
, *smtp
= NULL
;
3425 * Turn the list of smtp servers into a space-
3426 * delimited list in a single string.
3428 for(lp
= role
->smtp
; (q
= *lp
) != NULL
; lp
++)
3429 len
+= (strlen(q
) + 1);
3432 smtp
= (char *) fs_get(len
* sizeof(char));
3434 for(lp
= role
->smtp
; (q
= *lp
) != NULL
; lp
++){
3435 if(lp
!= role
->smtp
)
3436 strncat(smtp
, " ", len
-strlen(smtp
)-1);
3438 strncat(smtp
, q
, len
-strlen(smtp
)-1);
3444 pf_smtp_server
->writehdr
= 1;
3445 pf_smtp_server
->localcopy
= 1;
3447 pf_smtp_server
->textbuf
= smtp
;
3449 pf_smtp_server
->textbuf
= cpystr("");
3452 /* Save the role-specific nntp server */
3453 if(suggested_nntp_server
||
3454 (role
&& role
->nntp
&& role
->nntp
[0])){
3455 char *q
, *nntp
= NULL
;
3459 if(role
&& role
->nntp
&& role
->nntp
[0]){
3461 * Turn the list of nntp servers into a space-
3462 * delimited list in a single string.
3464 for(lp
= role
->nntp
; (q
= *lp
) != NULL
; lp
++)
3465 len
+= (strlen(q
) + 1);
3468 nntp
= (char *) fs_get(len
* sizeof(char));
3470 for(lp
= role
->nntp
; (q
= *lp
) != NULL
; lp
++){
3471 if(lp
!= role
->nntp
)
3472 strncat(nntp
, " ", len
-strlen(nntp
)-1);
3474 strncat(nntp
, q
, len
-strlen(nntp
)-1);
3481 nntp
= cpystr(suggested_nntp_server
);
3483 pf_nntp_server
->writehdr
= 1;
3484 pf_nntp_server
->localcopy
= 1;
3486 pf_nntp_server
->textbuf
= nntp
;
3488 pf_nntp_server
->textbuf
= cpystr("");
3492 * Write the list of custom headers to the
3493 * X-Our-Headers header so that we can recover the
3497 for(pf
= header
.custom
; pf
&& pf
->name
; pf
= pf
->next
)
3498 sz
+= strlen(pf
->name
) + 1;
3503 pf_ourhdrs
->writehdr
= 1;
3504 pf_ourhdrs
->localcopy
= 1;
3505 pf_ourhdrs
->textbuf
= (char *)fs_get(sz
);
3506 memset(pf_ourhdrs
->textbuf
, 0, sz
);
3507 q
= pf_ourhdrs
->textbuf
;
3508 for(pf
= header
.custom
; pf
&& pf
->name
; pf
= pf
->next
){
3509 if(pf
!= header
.custom
)
3510 sstrncpy(&q
, ",", sz
-(q
-pf_ourhdrs
->textbuf
));
3512 sstrncpy(&q
, pf
->name
, sz
-(q
-pf_ourhdrs
->textbuf
));
3515 pf_ourhdrs
->textbuf
[sz
-1] = '\0';;
3519 * We need to make sure any header values that got cleared
3520 * get written to the postponed message (they won't if
3521 * pf->text is NULL). Otherwise, we can't tell previously
3522 * non-existent custom headers or default values from
3523 * custom (or other) headers that got blanked in the
3526 for(pf
= header
.local
; pf
&& pf
->name
; pf
= pf
->next
)
3527 if(pf
->type
== FreeText
&& HE(pf
) && !*(HE(pf
)->realaddr
))
3528 *(HE(pf
)->realaddr
) = cpystr("");
3531 * We're saving the message for use later. It may be that the
3532 * characters in the message are not all convertible to the
3533 * user's posting_charmap. We'll save it as UTF-8 instead
3534 * and worry about that the next time they try to send it.
3535 * Use a different save pointer just to be sure we don't
3536 * mess up the other stuff. We should probably make the
3537 * charset an argument.
3539 * We also need to fix the charset of the body part
3540 * the user is editing so that we can read it back
3541 * successfully when we resume the composition.
3543 ps_global
->post_utf8
= 1;
3548 if((*body
)->type
== TYPEMULTIPART
)
3549 bp
= &(*body
)->nested
.part
->body
;
3553 for(pm
= bp
->parameter
;
3554 pm
&& strucmp(pm
->attribute
, "charset") != 0;
3560 fs_give((void **) &pm
->value
);
3562 pm
->value
= cpystr("UTF-8");
3566 if(pine_rfc822_output(&header
,*body
,NULL
,NULL
) >= 0L){
3567 if(editor_result
& (COMP_GOTHUP
| COMP_CANCEL
)){
3573 if(editor_result
& COMP_CANCEL
){
3574 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
,
3575 "Saving to \"%s\"", folder
);
3576 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
3577 we_cancel
= busy_cue((char *)tmp_20k_buf
, NULL
, 1);
3581 so_get(FileStar
, folder
, WRITE_ACCESS
|OWNER_ONLY
)) != NULL
){
3582 gf_set_so_readc(&gc
, lmc
.so
);
3583 gf_set_so_writec(&pc
, hup_so
);
3584 so_seek(lmc
.so
, 0L, 0); /* read msg copy and */
3585 so_seek(hup_so
, 0L, 2); /* append to folder */
3587 gf_link_filter(gf_nvtnl_local
, NULL
);
3588 if(!(fcc_result
= !(err
= gf_pipe(gc
, pc
))))
3589 dprint((1, "*** PIPE FAILED: %s\n",
3592 gf_clear_so_readc(lmc
.so
);
3593 gf_clear_so_writec(hup_so
);
3597 dprint((1, "*** CAN'T CREATE %s: %s\n",
3598 folder
? folder
: "?",
3599 error_description(errno
)));
3602 cancel_busy_cue(-1);
3605 fcc_result
= write_fcc(folder
, fcc_cntxt
,
3606 lmc
.so
, NULL
, label
, NULL
);
3609 /* discontinue coerced UTF-8 posting */
3610 ps_global
->post_utf8
= 0;
3615 dprint((1, "***CAN'T ALLOCATE temp store: %s ",
3616 error_description(errno
)));
3618 if(editor_result
& COMP_GOTHUP
){
3620 * Special Hack #291: if any hi-byte bits are set in
3621 * editor's result, we put them there.
3623 if(editor_result
& 0xff00)
3624 exit(editor_result
>> 8);
3626 dprint((1, "Save composition on HUP %sED\n",
3627 fcc_result
? "SUCCEED" : "FAIL"));
3628 hup_signal(); /* Do what we normally do on SIGHUP */
3630 else if((editor_result
& COMP_SUSPEND
) && fcc_result
){
3631 if(ps_global
->VAR_FORM_FOLDER
3632 && ps_global
->VAR_FORM_FOLDER
[0]
3633 && !strcmp(folder
, ps_global
->VAR_FORM_FOLDER
))
3634 q_status_message(SM_ORDER
, 0, 3,
3635 _("Composition saved to Form Letter Folder. Select Compose to send."));
3637 q_status_message(SM_ORDER
, 0, 3,
3638 _("Composition postponed. Select Compose to resume."));
3640 break; /* postpone went OK, get out of here */
3642 else if(editor_result
& COMP_CANCEL
){
3645 if(fcc_result
&& folder
)
3646 lc
= last_cmpnt(folder
);
3648 q_status_message3(SM_ORDER
, 0, 3,
3649 _("Message cancelled%s%s%s"),
3650 (lc
&& *lc
) ? " and copied to \"" : "",
3651 (lc
&& *lc
) ? lc
: "",
3652 (lc
&& *lc
) ? "\" file" : "");
3656 q_status_message(SM_ORDER
, 0, 4,
3657 _("Continuing composition. Message not postponed or sent"));
3659 continue; /* postpone failed, jump back in to composer */
3663 /*------ Must be sending mail or posting ! -----*/
3664 int result
, valid_addr
, continue_with_only_fcc
= 0;
3665 CONTEXT_S
*fcc_cntxt
= NULL
;
3668 dprint((4, "=== sending: "));
3670 /* --- If posting, confirm with user ----*/
3671 if(outgoing
->newsgroups
&& *outgoing
->newsgroups
3672 && F_OFF(F_QUELL_EXTRA_POST_PROMPT
, ps_global
)
3673 && want_to(POST_PMT
, 'n', 'n', NO_HELP
, WT_NORM
) == 'n'){
3674 q_status_message(SM_ORDER
, 0, 3, _("Message not posted"));
3675 dprint((4, "no post, continuing\n"));
3679 if(!(outgoing
->to
|| outgoing
->cc
|| outgoing
->bcc
|| lcc_addr
3680 || outgoing
->newsgroups
)){
3682 if(F_OFF(F_AUTO_FCC_ONLY
, ps_global
) &&
3683 want_to(_("No recipients, really copy only to Fcc "),
3684 'n', 'n', h_send_fcc_only
, WT_NORM
) != 'y')
3687 continue_with_only_fcc
++;
3690 q_status_message(SM_ORDER
, 3, 4,
3691 _("No recipients specified!"));
3692 dprint((4, "no recip, continuing\n"));
3697 if((valid_addr
= check_addresses(&header
)) == CA_BAD
){
3698 /*--- Addresses didn't check out---*/
3699 dprint((4, "addrs failed, continuing\n"));
3703 if(F_ON(F_WARN_ABOUT_NO_TO_OR_CC
, ps_global
)
3704 && !continue_with_only_fcc
3705 && !(outgoing
->to
|| outgoing
->cc
|| lcc_addr
3706 || outgoing
->newsgroups
)
3707 && (want_to(_("No To, Cc, or Newsgroup specified, send anyway "),
3708 'n', 'n', h_send_check_to_cc
, WT_NORM
) != 'y')){
3709 dprint((4, "No To or CC or Newsgroup, continuing\n"));
3710 if(local_redraft_pos
&& local_redraft_pos
!= redraft_pos
)
3711 free_redraft_pos(&local_redraft_pos
);
3714 = (REDRAFT_POS_S
*) fs_get(sizeof(*local_redraft_pos
));
3715 memset((void *) local_redraft_pos
,0,sizeof(*local_redraft_pos
));
3716 local_redraft_pos
->hdrname
= cpystr(TONAME
);
3720 if(F_ON(F_WARN_ABOUT_NO_SUBJECT
, ps_global
)
3721 && check_for_subject(&header
) == CF_MISSING
){
3722 dprint((4, "No subject, continuing\n"));
3723 if(local_redraft_pos
&& local_redraft_pos
!= redraft_pos
)
3724 free_redraft_pos(&local_redraft_pos
);
3727 = (REDRAFT_POS_S
*) fs_get(sizeof(*local_redraft_pos
));
3728 memset((void *) local_redraft_pos
,0,sizeof(*local_redraft_pos
));
3729 local_redraft_pos
->hdrname
= cpystr(SUBJNAME
);
3733 if(F_ON(F_WARN_ABOUT_NO_FCC
, ps_global
)
3734 && check_for_fcc(fcc
) == CF_MISSING
){
3735 dprint((4, "No fcc, continuing\n"));
3736 if(local_redraft_pos
&& local_redraft_pos
!= redraft_pos
)
3737 free_redraft_pos(&local_redraft_pos
);
3740 = (REDRAFT_POS_S
*) fs_get(sizeof(*local_redraft_pos
));
3741 memset((void *) local_redraft_pos
,0,sizeof(*local_redraft_pos
));
3742 local_redraft_pos
->hdrname
= cpystr("Fcc");
3748 /*---- Check out fcc -----*/
3751 * If special name "inbox" then replace it with the
3754 if(ps_global
->VAR_INBOX_PATH
3755 && strucmp(fcc
, ps_global
->inbox_name
) == 0){
3758 replace_fcc
= cpystr(ps_global
->VAR_INBOX_PATH
);
3759 fs_give((void **)&fcc
);
3763 lmc
.all_written
= lmc
.text_written
= 0;
3764 /* lmc.text_only set on command line */
3765 if(!(lmc
.so
= open_fcc(fcc
, &fcc_cntxt
, 0, NULL
, NULL
))){
3766 /* ---- Open or allocation of fcc failed ----- */
3767 dprint((4,"can't open/allocate fcc, cont'g\n"));
3770 * Find field entry associated with fcc, and start
3773 for(pf
= header
.local
; pf
&& pf
->name
; pf
= pf
->next
)
3774 if(pf
->type
== Fcc
&& HE(pf
))
3775 HE(pf
)->start_here
= 1;
3780 so_truncate(lmc
.so
, fcc_size_guess(*body
) + 2048);
3785 /*---- Take care of any requested prefiltering ----*/
3786 if(sending_filter_requested
3787 && !filter_message_text(sending_filter_requested
, outgoing
,
3788 *body
, &orig_so
, &header
)){
3789 q_status_message1(SM_ORDER
, 3, 3,
3790 _("Problem filtering! Nothing sent%s."),
3791 fcc
? " or saved to fcc" : "");
3795 /*------ Actually post -------*/
3796 if(outgoing
->newsgroups
){
3797 char **alt_nntp
= NULL
, *alt_nntp_p
[2];
3798 if(((role
&& role
->nntp
)
3799 || suggested_nntp_server
)){
3800 if(ps_global
->FIX_NNTP_SERVER
3801 && ps_global
->FIX_NNTP_SERVER
[0])
3802 q_status_message(SM_ORDER
| SM_DING
, 5, 5,
3803 "Using nntp-server that is administratively fixed");
3804 else if(role
&& role
->nntp
)
3805 alt_nntp
= role
->nntp
;
3807 alt_nntp_p
[0] = suggested_nntp_server
;
3808 alt_nntp_p
[1] = NULL
;
3809 alt_nntp
= alt_nntp_p
;
3812 if(news_poster(&header
, *body
, alt_nntp
, pipe_callback
) < 0){
3813 dprint((1, "Post failed, continuing\n"));
3814 if(outgoing
->message_id
)
3815 fs_give((void **) &outgoing
->message_id
);
3817 outgoing
->message_id
= generate_message_id(role
);
3822 result
|= P_NEWS_WIN
;
3826 * BUG: IF we've posted the message *and* an fcc was specified
3827 * then we've already got a neatly formatted message in the
3828 * lmc.so. It'd be nice not to have to re-encode everything
3829 * to insert it into the smtp slot...
3833 * Turn on "undisclosed recipients" header if no To or cc.
3835 if(!(outgoing
->to
|| outgoing
->cc
)
3836 && (outgoing
->bcc
|| lcc_addr
) && pf_nobody
&& pf_nobody
->addr
){
3837 pf_nobody
->writehdr
= 1;
3838 pf_nobody
->localcopy
= 1;
3841 if(priority_requested
){
3842 (void) set_priority_header(&header
, priority_requested
);
3843 fs_give((void **) &priority_requested
);
3846 #if defined(BACKGROUND_POST) && defined(SIGCHLD)
3848 * If requested, launch background posting...
3850 if(background_requested
&& !(call_mailer_flags
& CM_VERBOSE
)){
3851 ps_global
->post
= (POST_S
*)fs_get(sizeof(POST_S
));
3852 memset(ps_global
->post
, 0, sizeof(POST_S
));
3854 ps_global
->post
->fcc
= cpystr(fcc
);
3856 if((ps_global
->post
->pid
= fork()) == 0){
3858 * Put us in new process group...
3860 setpgrp(0, ps_global
->post
->pid
);
3862 /* BUG: should fix argv[0] to indicate what we're up to */
3865 * If there are any live streams, pretend we never
3866 * knew them. Problem is two processes writing
3867 * same server process.
3868 * This is not clean but we're just going to exit
3869 * right away anyway. We just want to be sure to leave
3870 * the stuff that the parent is going to use alone.
3871 * The next three lines will disable the re-use of the
3872 * existing streams and cause us to open a new one if
3875 ps_global
->mail_stream
= NULL
;
3876 ps_global
->s_pool
.streams
= NULL
;
3877 ps_global
->s_pool
.nstream
= 0;
3879 /* quell any display output */
3880 ps_global
->in_init_seq
= 1;
3882 /*------- Actually mail the message ------*/
3883 if(valid_addr
== CA_OK
3884 && (outgoing
->to
|| outgoing
->cc
3885 || outgoing
->bcc
|| lcc_addr
)){
3886 char **alt_smtp
= NULL
;
3888 if(role
&& role
->smtp
){
3889 if(ps_global
->FIX_SMTP_SERVER
3890 && ps_global
->FIX_SMTP_SERVER
[0])
3891 q_status_message(SM_ORDER
| SM_DING
, 5, 5, "Use of a role-defined smtp-server is administratively prohibited");
3893 alt_smtp
= role
->smtp
;
3896 result
|= (call_mailer(&header
, *body
, alt_smtp
,
3898 call_mailer_file_result
,
3900 ? P_MAIL_WIN
: P_MAIL_LOSE
;
3902 if(result
& P_MAIL_LOSE
)
3903 mark_address_failure_for_pico(&header
);
3906 /*----- Was there an fcc involved? -----*/
3908 /*------ Write it if at least something worked ------*/
3909 if((result
& (P_MAIL_WIN
| P_NEWS_WIN
))
3910 || (!(result
& (P_MAIL_BITS
| P_NEWS_BITS
))
3911 && pine_rfc822_output(&header
, *body
,
3915 strncpy(label
, "Fcc", sizeof(label
));
3916 label
[sizeof(label
)-1] = '\0';
3917 if(strcmp(fcc
, ps_global
->VAR_DEFAULT_FCC
)){
3918 snprintf(label
+ 3, sizeof(label
)-3, " to %s", fcc
);
3919 label
[sizeof(label
)-1] = '\0';
3922 /*-- Now actually copy to fcc folder and close --*/
3923 result
|= (write_fcc(fcc
, fcc_cntxt
, lmc
.so
,
3925 F_ON(F_MARK_FCC_SEEN
, ps_global
)
3927 ? P_FCC_WIN
: P_FCC_LOSE
;
3929 else if(!(result
& (P_MAIL_BITS
| P_NEWS_BITS
))){
3930 q_status_message(SM_ORDER
, 3, 5,
3931 _("Fcc Failed!. No message saved."));
3933 "explicit fcc write failed!\n"));
3934 result
|= P_FCC_LOSE
;
3940 if(result
& (P_MAIL_LOSE
| P_NEWS_LOSE
| P_FCC_LOSE
)){
3942 * Encode child's result in hi-byte of
3945 editor_result
= ((result
<< 8) | COMP_GOTHUP
);
3952 if(ps_global
->post
->pid
> 0){
3953 q_status_message(SM_ORDER
, 3, 3,
3954 _("Message handed off for posting"));
3955 break; /* up to our child now */
3958 q_status_message1(SM_ORDER
| SM_DING
, 3, 3,
3959 "Can't fork for send: %s",
3960 error_description(errno
));
3961 if(ps_global
->post
->fcc
)
3962 fs_give((void **) &ps_global
->post
->fcc
);
3964 fs_give((void **) &ps_global
->post
);
3967 if(lmc
.so
) /* throw away unused store obj */
3970 if(outgoing
->message_id
)
3971 fs_give((void **) &outgoing
->message_id
);
3973 outgoing
->message_id
= generate_message_id(role
);
3975 continue; /* if we got here, there was a prob */
3977 #endif /* BACKGROUND_POST */
3979 /*------- Actually mail the message ------*/
3980 if(valid_addr
== CA_OK
3981 && (outgoing
->to
|| outgoing
->cc
|| outgoing
->bcc
|| lcc_addr
)){
3982 char **alt_smtp
= NULL
;
3984 if(role
&& role
->smtp
){
3985 if(ps_global
->FIX_SMTP_SERVER
3986 && ps_global
->FIX_SMTP_SERVER
[0])
3987 q_status_message(SM_ORDER
| SM_DING
, 5, 5, "Use of a role-defined smtp-server is administratively prohibited");
3989 alt_smtp
= role
->smtp
;
3992 result
|= (call_mailer(&header
, *body
, alt_smtp
,
3994 call_mailer_file_result
,
3996 ? P_MAIL_WIN
: P_MAIL_LOSE
;
3998 if(result
& P_MAIL_LOSE
)
3999 mark_address_failure_for_pico(&header
);
4002 /*----- Was there an fcc involved? -----*/
4004 /*------ Write it if at least something worked ------*/
4005 if((result
& (P_MAIL_WIN
| P_NEWS_WIN
))
4006 || (!(result
& (P_MAIL_BITS
| P_NEWS_BITS
))
4007 && pine_rfc822_output(&header
, *body
, NULL
, NULL
))){
4010 strncpy(label
, "Fcc", sizeof(label
));
4011 label
[sizeof(label
)-1] = '\0';
4012 if(strcmp(fcc
, ps_global
->VAR_DEFAULT_FCC
)){
4013 snprintf(label
+ 3, sizeof(label
)-3, " to %s", fcc
);
4014 label
[sizeof(label
)-1] = '\0';
4017 /*-- Now actually copy to fcc folder and close --*/
4018 result
|= (write_fcc(fcc
, fcc_cntxt
, lmc
.so
, NULL
, label
,
4019 F_ON(F_MARK_FCC_SEEN
, ps_global
)
4021 ? P_FCC_WIN
: P_FCC_LOSE
;
4023 else if(!(result
& (P_MAIL_BITS
| P_NEWS_BITS
))){
4024 q_status_message(SM_ORDER
,3,5,
4025 _("Fcc Failed!. No message saved."));
4026 dprint((1, "explicit fcc write failed!\n"));
4027 result
|= P_FCC_LOSE
;
4033 /*----- Mail Post FAILED, back to composer -----*/
4034 if(result
& (P_MAIL_LOSE
| P_FCC_LOSE
)){
4035 dprint((1, "Send failed, continuing\n"));
4037 if(result
& P_FCC_LOSE
){
4039 * Find field entry associated with fcc, and start
4042 for(pf
= header
.local
; pf
&& pf
->name
; pf
= pf
->next
)
4043 if(pf
->type
== Fcc
&& HE(pf
))
4044 HE(pf
)->start_here
= 1;
4046 q_status_message(SM_ORDER
| SM_DING
, 3, 3,
4047 pine_send_status(result
, fcc
,
4048 tmp_20k_buf
, SIZEOF_20KBUF
, NULL
));
4051 if(outgoing
->message_id
)
4052 fs_give((void **) &outgoing
->message_id
);
4054 outgoing
->message_id
= generate_message_id(role
);
4060 * If message sent *completely* successfully, there's a
4061 * reply struct AND we're allowed to write back state, do it.
4062 * But also protect against shifted message numbers due
4063 * to new mail arrival. Since the number passed is based
4064 * on the real imap msg no, AND we're sure no expunge has
4065 * been done, just fix up the sorted number...
4067 update_answered_flags(reply
);
4069 /*----- Signed, sealed, delivered! ------*/
4070 q_status_message(SM_ORDER
, 0, 3,
4071 pine_send_status(result
, fcc
, tmp_20k_buf
, SIZEOF_20KBUF
, NULL
));
4073 break; /* All's well, pop out of here */
4081 fs_give((void **)&fcc
);
4083 free_body_particulars(bp
);
4085 free_attachment_list(&pbf
->attachments
);
4087 standard_picobuf_teardown(pbf
);
4089 for(i
=0; i
< fixed_cnt
; i
++){
4090 if(pfields
[i
].textbuf
)
4091 fs_give((void **)&pfields
[i
].textbuf
);
4093 fs_give((void **)&pfields
[i
].name
);
4097 mail_free_address(&lcc_addr
);
4100 mail_free_address(&nobody_addr
);
4102 free_prompts(header
.custom
);
4103 free_customs(header
.custom
);
4104 fs_give((void **)&pfields
);
4105 free_headents(&headents
);
4106 fs_give((void **)&sending_order
);
4107 if(suggested_nntp_server
)
4108 fs_give((void **)&suggested_nntp_server
);
4110 fs_give((void **)&title
);
4112 if(local_redraft_pos
&& local_redraft_pos
!= redraft_pos
)
4113 free_redraft_pos(&local_redraft_pos
);
4115 pbf
= save_previous_pbuf
;
4118 dprint((4, "=== send returning ===\n"));
4123 * Check for subject in outgoing message.
4125 * Asks user whether to proceed with no subject.
4128 check_for_subject(METAENV
*header
)
4133 for(pf
= header
->local
; pf
&& pf
->name
; pf
= pf
->next
)
4134 if(pf
->type
== Subject
){
4135 if(pf
->text
&& *pf
->text
&& **pf
->text
)
4138 if(want_to("No Subject, send anyway ",
4139 'n', 'n', h_send_check_subj
, WT_NORM
) == 'y')
4154 * Check for fcc in outgoing message.
4156 * Asks user whether to proceed with no fcc.
4159 check_for_fcc(char *fcc
)
4166 if(want_to("No Fcc, send anyway ", 'n', 'n', h_send_check_fcc
, WT_NORM
) == 'y')
4177 * Confirm that the user wants to send to MAILER-DAEMON
4180 confirm_daemon_send(void)
4182 return(want_to("Really send this message to the MAILER-DAEMON",
4183 'n', 'n', NO_HELP
, WT_NORM
) == 'y');
4188 free_prompts(PINEFIELD
*head
)
4192 for(pf
= head
; pf
&& pf
->name
; pf
= pf
->next
){
4193 if(HE(pf
) && HE(pf
)->prompt
)
4194 fs_give((void **)& HE(pf
)->prompt
);
4200 postpone_prompt(void)
4202 static ESCKEY_S pstpn_form_opt
[] = { {'p', 'p', "P", N_("Postponed Folder")},
4203 {'f', 'f', "F", N_("Form Letter Folder")},
4204 {-1, 0, NULL
, NULL
} };
4206 return(radio_buttons(PSTPN_FORM_PMT
, -FOOTER_ROWS(ps_global
),
4207 pstpn_form_opt
, 'p', 0, NO_HELP
, RB_FLUSH_IN
));
4212 * call__mailer_file_result - some results from call_mailer might be in a file.
4213 * dislplay that file.
4216 call_mailer_file_result(char *filename
, int style
)
4219 if(style
& CM_BR_VERBOSE
){
4220 display_output_file(filename
, "Verbose SMTP Interaction", NULL
, DOF_BRIEF
);
4223 display_output_file(filename
, "POSTING ERRORS", "Posting Error", DOF_EMPTY
);
4229 mark_address_failure_for_pico(METAENV
*header
)
4233 int error_count
= 0;
4234 struct headerentry
*last_he
= NULL
;
4236 for(pf
= header
->local
; pf
&& pf
->name
; pf
= pf
->next
)
4237 if(pf
->type
== Address
&& pf
->rcptto
&& pf
->addr
&& *pf
->addr
)
4238 for(a
= *pf
->addr
; a
!= NULL
; a
= a
->next
)
4240 && error_count
++ < MAX_ADDR_ERROR
4242 if(last_he
) /* start last reported err */
4243 last_he
->start_here
= 0;
4245 (last_he
= HE(pf
))->start_here
= 1;
4252 * This is specialized routine. It assumes that the only things that we
4253 * care about restoring are the body type, subtype, encoding and the
4254 * state of the charset parameter. It also assumes that if the charset
4255 * parameter exists when we save it, it won't be removed later.
4257 BODY_PARTICULARS_S
*
4258 save_body_particulars(struct mail_bodystruct
*body
)
4260 BODY_PARTICULARS_S
*bp
;
4263 bp
= (BODY_PARTICULARS_S
*)fs_get(sizeof(BODY_PARTICULARS_S
));
4265 bp
->type
= body
->type
;
4266 bp
->encoding
= body
->encoding
;
4267 bp
->subtype
= body
->subtype
? cpystr(body
->subtype
) : NULL
;
4268 bp
->parameter
= body
->parameter
;
4269 for(pm
= bp
->parameter
;
4270 pm
&& strucmp(pm
->attribute
, "charset") != 0;
4272 ;/* searching for possible charset parameter */
4274 if(pm
){ /* found one */
4275 bp
->had_csp
= 1; /* saved body had charset parameter */
4276 bp
->charset
= pm
->value
? cpystr(pm
->value
) : NULL
;
4288 reset_body_particulars(BODY_PARTICULARS_S
*bp
, struct mail_bodystruct
*body
)
4290 body
->type
= bp
->type
;
4291 body
->encoding
= bp
->encoding
;
4293 fs_give((void **)&body
->subtype
);
4295 body
->subtype
= bp
->subtype
? cpystr(bp
->subtype
) : NULL
;
4298 PARAMETER
*pm
, *pm_prev
= NULL
;
4300 for(pm
= body
->parameter
;
4301 pm
&& strucmp(pm
->attribute
, "charset") != 0;
4305 if(pm
){ /* body has charset parameter */
4306 if(bp
->had_csp
){ /* reset to what it used to be */
4308 fs_give((void **)&pm
->value
);
4310 pm
->value
= bp
->charset
? cpystr(bp
->charset
) : NULL
;
4312 else{ /* remove charset parameter */
4314 pm_prev
->next
= pm
->next
;
4316 body
->parameter
= pm
->next
;
4318 mail_free_body_parameter(&pm
);
4324 * This can't happen because grope never removes
4325 * the charset parameter.
4327 q_status_message(SM_ORDER
| SM_DING
, 5, 5,
4328 "Programmer error: saved charset but no current charset param in pine_send");
4332 ok, still no parameter
4339 mail_free_body_parameter(&body
->parameter
);
4341 body
->parameter
= NULL
;
4347 free_body_particulars(BODY_PARTICULARS_S
*bp
)
4351 fs_give((void **)&bp
->subtype
);
4354 fs_give((void **)&bp
->charset
);
4356 fs_give((void **)&bp
);
4361 /*----------------------------------------------------------------------
4362 Build a status message suitable for framing
4364 Returns: pointer to resulting buffer
4367 pine_send_status(int result
, char *fcc_name
, char *buf
, size_t buflen
, int *goodorbad
)
4369 int avail
= ps_global
->ttyo
->screen_cols
- 2;
4370 int fixedneed
, need
, lenfcc
;
4371 char *part1
, *part2
, *part3
, *part4
, *part5
;
4372 char fbuf
[MAILTMPLEN
+1];
4374 part1
= (result
& P_NEWS_WIN
)
4376 : (result
& P_NEWS_LOSE
)
4379 part2
= ((result
& P_NEWS_BITS
) && (result
& P_MAIL_BITS
)
4380 && (result
& P_FCC_BITS
))
4382 : ((result
& P_NEWS_BITS
) && (result
& (P_MAIL_BITS
| P_FCC_BITS
)))
4385 part3
= (result
& P_MAIL_WIN
)
4387 : (result
& P_MAIL_LOSE
)
4390 part4
= ((result
& P_MAIL_BITS
) && (result
& P_FCC_BITS
))
4393 part5
= ((result
& P_FCC_WIN
) && !(result
& (P_MAIL_WIN
| P_NEWS_WIN
)))
4395 : (result
& P_FCC_WIN
)
4397 : (result
& P_FCC_LOSE
)
4400 lenfcc
= MIN(sizeof(fbuf
)-1, (result
& P_FCC_BITS
) ? strlen(fcc_name
) : 0);
4402 fixedneed
= 9 + strlen(part1
) + strlen(part2
) + strlen(part3
) +
4403 strlen(part4
) + strlen(part5
);
4404 need
= fixedneed
+ ((result
& P_FCC_BITS
) ? 2 : 0) + lenfcc
;
4406 if(need
> avail
&& fixedneed
+ 3 >= avail
){
4407 /* dots on end of fixed, no fcc */
4408 snprintf(fbuf
, sizeof(fbuf
), "Message %s%s%s%s%s ",
4409 part1
, part2
, part3
, part4
, part5
);
4410 short_str(fbuf
, buf
, buflen
, avail
, EndDots
);
4412 else if(need
> avail
){
4413 /* include whole fixed part, quotes and dots at end of fcc name */
4415 lenfcc
= MAX(1, lenfcc
-(need
-avail
));
4417 snprintf(buf
, buflen
, "Message %s%s%s%s%s%s%s%s.",
4418 part1
, part2
, part3
, part4
, part5
,
4419 (result
& P_FCC_BITS
) ? "\"" : "",
4420 short_str((result
& P_FCC_BITS
) ? fcc_name
: "",
4421 fbuf
, sizeof(fbuf
), lenfcc
, FrontDots
),
4422 (result
& P_FCC_BITS
) ? "\"" : "");
4426 snprintf(buf
, buflen
, "Message %s%s%s%s%s%s%s%s.",
4427 part1
, part2
, part3
, part4
, part5
,
4428 (result
& P_FCC_BITS
) ? "\"" : "",
4429 (result
& P_FCC_BITS
) ? fcc_name
: "",
4430 (result
& P_FCC_BITS
) ? "\"" : "");
4434 *goodorbad
= (result
& (P_MAIL_LOSE
| P_NEWS_LOSE
| P_FCC_LOSE
)) == 0;
4439 /* Callback from Pico to set the conditions for Alpine to start a new thread
4443 new_thread_on_blank_subject(void)
4445 ps_global
->newthread
= F_ON(F_NEW_THREAD_ON_BLANK_SUBJECT
, ps_global
);
4450 /*----------------------------------------------------------------------
4451 Call back for pico to insert the specified message's text
4453 Args: n -- message number to format
4454 f -- function to use to output the formatted message
4457 Returns: returns msg number formatted on success, zero on error.
4460 message_format_for_pico(long int n
, int (*f
) (int))
4464 char *old_quote
= NULL
;
4467 if(!(n
> 0L && n
<= mn_get_total(ps_global
->msgmap
)
4468 && (e
= pine_mail_fetchstructure(ps_global
->mail_stream
,
4469 mn_m2raw(ps_global
->msgmap
, n
), &b
)))){
4470 q_status_message(SM_ORDER
|SM_DING
,3,3,"Error inserting Message");
4471 flush_status_messages(0);
4475 /* temporarily assign a new quote string */
4476 old_quote
= pbf
->quote_str
;
4477 pbf
->quote_str
= reply_quote_str(e
);
4479 /* build separator line */
4480 reply_delimiter(e
, NULL
, f
);
4482 /* actually write message text */
4483 if(!format_message(mn_m2raw(ps_global
->msgmap
, n
), e
, b
, NULL
,
4484 FM_NEW_MESS
| FM_DISPLAY
| FM_NOCOLOR
| FM_NOINDENT
, f
)){
4485 q_status_message(SM_ORDER
|SM_DING
,3,3,"Error inserting Message");
4486 flush_status_messages(0);
4490 fs_give((void **)&pbf
->quote_str
);
4491 pbf
->quote_str
= old_quote
;
4496 /*----------------------------------------------------------------------
4497 Call back for pico to prompt the user for exit confirmation
4499 Args: dflt -- default answer for confirmation prompt
4501 Returns: either NULL if the user accepts exit, or string containing
4502 reason why the user declined.
4505 send_exit_for_pico(struct headerentry
*he
, void (*redraw_pico
)(void), int allow_flowed
,
4508 int i
, rv
, c
, verbose_label
= 0, bg_label
= 0, old_suspend
;
4509 int dsn_label
= 0, fcc_label
= 0, lparen
;
4510 int flowing_label
= 0, double_rad
;
4511 char *rstr
= NULL
, *p
, *lc
, *optp
;
4512 char dsn_string
[30];
4513 void (*redraw
)(void) = ps_global
->redrawer
;
4518 struct filters
*prev
, *next
;
4519 } *filters
= NULL
, *fp
;
4521 sending_filter_requested
= NULL
;
4522 call_mailer_flags
= 0;
4523 background_requested
= 0;
4524 flowing_requested
= allow_flowed
? 1 : 0;
4525 lmc
.text_only
= F_ON(F_NO_FCC_ATTACH
, ps_global
) != 0;
4526 if(priority_requested
)
4527 fs_give((void **) &priority_requested
);
4529 if(background_posting(FALSE
)){
4531 *result
= "Can't send while background posting. Use postpone.";
4536 if(F_ON(F_SEND_WO_CONFIRM
, ps_global
)){
4543 ps_global
->redrawer
= redraw_pico
;
4545 if((old_suspend
= F_ON(F_CAN_SUSPEND
, ps_global
)) != 0)
4546 (void) F_SET(F_CAN_SUSPEND
, ps_global
, 0);
4549 * Build list of available filters...
4551 for(i
=0; ps_global
->VAR_SEND_FILTER
&& ps_global
->VAR_SEND_FILTER
[i
]; i
++){
4552 for(p
= ps_global
->VAR_SEND_FILTER
[i
];
4553 *p
&& !isspace((unsigned char)*p
); p
++)
4558 if(!(is_absolute_path(ps_global
->VAR_SEND_FILTER
[i
])
4559 && can_access(ps_global
->VAR_SEND_FILTER
[i
],EXECUTE_ACCESS
) ==0)){
4564 fp
= (struct filters
*)fs_get(sizeof(struct filters
));
4566 if((lc
= last_cmpnt(ps_global
->VAR_SEND_FILTER
[i
])) != NULL
){
4567 fp
->filter
= cpystr(lc
);
4569 else if((p
- ps_global
->VAR_SEND_FILTER
[i
]) > 20){
4570 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, "...%s", p
- 17);
4571 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
4572 fp
->filter
= cpystr(tmp_20k_buf
);
4575 fp
->filter
= cpystr(ps_global
->VAR_SEND_FILTER
[i
]);
4581 fp
->prev
= filters
->prev
;
4582 fp
->prev
->next
= filters
->prev
= fp
;
4585 filters
= (struct filters
*)fs_get(sizeof(struct filters
));
4586 filters
->index
= -1;
4587 filters
->filter
= NULL
;
4588 filters
->next
= filters
->prev
= fp
;
4589 fp
->next
= fp
->prev
= filters
;
4597 opts
[i
++].label
= N_("Yes");
4602 opts
[i
++].label
= N_("No");
4605 /* set global_filter_pointer to desired filter or NULL if none */
4606 /* prepare two keymenu slots for selecting filter */
4607 opts
[i
].ch
= ctrl('P');
4609 opts
[i
].name
= "^P";
4610 opts
[i
++].label
= N_("Prev Filter");
4612 opts
[i
].ch
= ctrl('N');
4614 opts
[i
].name
= "^N";
4615 opts
[i
++].label
= N_("Next Filter");
4617 if(F_ON(F_FIRST_SEND_FILTER_DFLT
, ps_global
))
4618 filters
= filters
->next
;
4621 if(F_ON(F_VERBOSE_POST
, ps_global
)){
4622 /* setup keymenu slot to toggle verbose mode */
4623 opts
[i
].ch
= ctrl('W');
4625 opts
[i
].name
= "^W";
4626 verbose_label
= i
++;
4630 /* setup keymenu slot to toggle flowed mode */
4631 opts
[i
].ch
= ctrl('V');
4633 opts
[i
].name
= "^V";
4634 flowing_label
= i
++;
4635 flowing_requested
= 1;
4638 if(F_ON(F_NO_FCC_ATTACH
, ps_global
)){
4639 /* setup keymenu slot to toggle attacment on fcc */
4640 opts
[i
].ch
= ctrl('F');
4642 opts
[i
].name
= "^F";
4646 #if defined(BACKGROUND_POST) && defined(SIGCHLD)
4647 if(F_ON(F_BACKGROUND_POST
, ps_global
)){
4648 opts
[i
].ch
= ctrl('R');
4650 opts
[i
].name
= "^R";
4658 opts
[i
++].label
= N_("Priority");
4661 if(F_OFF(F_DONT_DO_SMIME
, ps_global
)){
4665 opts
[i
++].label
= "Encrypt";
4670 opts
[i
++].label
= "Sign";
4672 if(ps_global
->smime
){
4673 ps_global
->smime
->do_encrypt
= F_ON(F_ENCRYPT_DEFAULT_ON
, ps_global
);
4674 ps_global
->smime
->do_sign
= F_ON(F_SIGN_DEFAULT_ON
, ps_global
);
4681 if(F_ON(F_DSN
, ps_global
)){
4682 /* setup keymenu slots to toggle dsn bits */
4686 opts
[i
].label
= N_("DSNOpts");
4691 opts
[i
++].label
= "";
4695 opts
[i
++].label
= "";
4699 opts
[i
++].label
= "";
4703 opts
[i
].ch
= KEY_UP
;
4706 opts
[i
++].label
= "";
4708 opts
[i
].ch
= KEY_DOWN
;
4711 opts
[i
++].label
= "";
4716 fix_windsize(ps_global
);
4719 if(filters
&& filters
->filter
&& (p
= strindex(filters
->filter
, ' ')))
4725 strncpy(tmp_20k_buf
, "Send message", SIZEOF_20KBUF
);
4726 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
4727 optp
= tmp_20k_buf
+ strlen(tmp_20k_buf
);
4729 if(F_ON(F_NO_FCC_ATTACH
, ps_global
) && !lmc
.text_only
)
4730 sstrncpy(&optp
, " and Fcc Atmts", SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4732 if(allow_flowed
&& !flowing_requested
){
4733 if((optp
-tmp_20k_buf
)+2 < SIZEOF_20KBUF
){
4743 sstrncpy(&optp
, "not flowed", SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4747 if((optp
-tmp_20k_buf
)+2 < SIZEOF_20KBUF
){
4759 if(filters
->filter
){
4760 sstrncpy(&optp
, "filtered thru \"", SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4761 sstrncpy(&optp
, filters
->filter
, SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4762 if((optp
-tmp_20k_buf
) < SIZEOF_20KBUF
)
4766 sstrncpy(&optp
, "unfiltered", SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4769 if((call_mailer_flags
& CM_VERBOSE
) || background_requested
){
4770 if((optp
-tmp_20k_buf
)+2 < SIZEOF_20KBUF
){
4780 sstrncpy(&optp
, "in ", SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4781 if(call_mailer_flags
& CM_VERBOSE
)
4782 sstrncpy(&optp
, "verbose ", SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4784 if(background_requested
)
4785 sstrncpy(&optp
, "background ", SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4787 sstrncpy(&optp
, "mode", SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4790 if(g_rolenick
&& !(he
&& he
[N_FROM
].dirty
)){
4791 if((optp
-tmp_20k_buf
)+2 < SIZEOF_20KBUF
){
4801 sstrncpy(&optp
, "as \"", SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4802 sstrncpy(&optp
, g_rolenick
, SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4803 sstrncpy(&optp
, "\"", SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4806 if(call_mailer_flags
& CM_DSN_SHOW
){
4807 if((optp
-tmp_20k_buf
)+2 < SIZEOF_20KBUF
){
4819 sstrncpy(&optp
, dsn_string
, SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4823 if(ps_global
->smime
&& ps_global
->smime
->do_encrypt
){
4824 if((optp
-tmp_20k_buf
)+2 < SIZEOF_20KBUF
){
4836 sstrncpy(&optp
, "Encrypted", SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4839 if(ps_global
->smime
&& ps_global
->smime
->do_sign
){
4840 if((optp
-tmp_20k_buf
)+2 < SIZEOF_20KBUF
){
4852 sstrncpy(&optp
, "Signed", SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4856 if(lparen
&& (optp
-tmp_20k_buf
) < SIZEOF_20KBUF
)
4859 sstrncpy(&optp
, "? ", SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4860 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
4866 opts
[flowing_label
].label
= flowing_requested
? N_("NoFlow") : N_("Flow");
4869 opts
[verbose_label
].label
= (call_mailer_flags
& CM_VERBOSE
) ? N_("Normal") : N_("Verbose");
4872 opts
[bg_label
].label
= background_requested
4873 ? N_("Foreground") : N_("Background");
4876 opts
[fcc_label
].label
= lmc
.text_only
? N_("Fcc Attchmnts")
4877 : N_("No Fcc Atmts ");
4879 if(F_ON(F_DSN
, ps_global
)){
4880 if(call_mailer_flags
& CM_DSN_SHOW
){
4881 opts
[dsn_label
].label
= (call_mailer_flags
& CM_DSN_DELAY
)
4882 ? N_("NoDelay") : N_("Delay");
4883 opts
[dsn_label
+1].ch
= 's';
4884 opts
[dsn_label
+1].label
= (call_mailer_flags
& CM_DSN_SUCCESS
)
4885 ? N_("NoSuccess") : N_("Success");
4886 opts
[dsn_label
+2].ch
= 'x';
4887 opts
[dsn_label
+2].label
= (call_mailer_flags
& CM_DSN_NEVER
)
4888 ? N_("ErrRets") : N_("NoErrRets");
4889 opts
[dsn_label
+3].ch
= 'h';
4890 opts
[dsn_label
+3].label
= (call_mailer_flags
& CM_DSN_FULL
)
4891 ? N_("RetHdrs") : N_("RetFull");
4896 ((call_mailer_flags
& CM_DSN_SHOW
)
4897 ? 4 : F_ON(F_DSN
, ps_global
) ? 1 : 0) > 11)
4898 rv
= double_radio_buttons(tmp_20k_buf
, -FOOTER_ROWS(ps_global
), opts
,
4900 (F_ON(F_DSN
, ps_global
) && allow_flowed
)
4901 ? h_send_prompt_dsn_flowed
:
4902 F_ON(F_DSN
, ps_global
) ? h_send_prompt_dsn
:
4903 allow_flowed
? h_send_prompt_flowed
:
4907 rv
= radio_buttons(tmp_20k_buf
, -FOOTER_ROWS(ps_global
), opts
,
4910 ((call_mailer_flags
& CM_DSN_SHOW
)
4911 ? 4 : F_ON(F_DSN
, ps_global
) ? 1 : 0) == 11)
4913 (F_ON(F_DSN
, ps_global
) && allow_flowed
)
4914 ? h_send_prompt_dsn_flowed
:
4915 F_ON(F_DSN
, ps_global
) ? h_send_prompt_dsn
:
4916 allow_flowed
? h_send_prompt_flowed
:
4920 if(rv
== 'y'){ /* user ACCEPTS! */
4923 else if(rv
== 'n'){ /* Declined! */
4924 rstr
= _("No Message Sent");
4927 else if(rv
== 'z'){ /* Cancelled! */
4928 rstr
= _("Send Cancelled");
4931 else if(rv
== 10){ /* PREVIOUS filter */
4932 filters
= filters
->prev
;
4934 else if(rv
== 11){ /* NEXT filter */
4935 filters
= filters
->next
;
4938 lmc
.text_only
= !lmc
.text_only
;
4940 else if(rv
== 12){ /* flip verbose bit */
4941 if(call_mailer_flags
& CM_VERBOSE
)
4942 call_mailer_flags
&= ~CM_VERBOSE
;
4944 call_mailer_flags
|= CM_VERBOSE
;
4946 if((call_mailer_flags
& CM_VERBOSE
) && background_requested
)
4947 background_requested
= 0;
4949 else if(rv
== 22){ /* flip flowing bit */
4950 flowing_requested
= !flowing_requested
;
4953 if((background_requested
= !background_requested
)
4954 && (call_mailer_flags
& CM_VERBOSE
))
4955 call_mailer_flags
&= ~CM_VERBOSE
; /* clear verbose */
4957 else if(call_mailer_flags
& CM_DSN_SHOW
){
4958 if(rv
== 's'){ /* flip success bit */
4959 call_mailer_flags
^= CM_DSN_SUCCESS
;
4960 /* turn off related bits */
4961 if(call_mailer_flags
& CM_DSN_SUCCESS
)
4962 call_mailer_flags
&= ~(CM_DSN_NEVER
);
4964 else if(rv
== 'd'){ /* flip delay bit */
4965 call_mailer_flags
^= CM_DSN_DELAY
;
4966 /* turn off related bits */
4967 if(call_mailer_flags
& CM_DSN_DELAY
)
4968 call_mailer_flags
&= ~(CM_DSN_NEVER
);
4970 else if(rv
== 'x'){ /* flip never bit */
4971 call_mailer_flags
^= CM_DSN_NEVER
;
4972 /* turn off related bits */
4973 if(call_mailer_flags
& CM_DSN_NEVER
)
4974 call_mailer_flags
&= ~(CM_DSN_SUCCESS
| CM_DSN_DELAY
);
4976 else if(rv
== 'h'){ /* flip full bit */
4977 call_mailer_flags
^= CM_DSN_FULL
;
4980 else if(rv
== 'd'){ /* show dsn options */
4982 * When you turn on DSN, the default is to notify on
4983 * failure, success, or delay; and to return the whole
4986 call_mailer_flags
|= (CM_DSN_SHOW
| CM_DSN_SUCCESS
| CM_DSN_DELAY
| CM_DSN_FULL
);
4988 else if(rv
== 'p'){ /* choose X-Priority */
4991 prio
= choose_a_priority(priority_requested
);
4992 if((ps_global
->redrawer
= redraw_pico
) != NULL
){
4993 (*ps_global
->redrawer
)();
4994 fix_windsize(ps_global
);
4998 if(priority_requested
)
4999 fs_give((void **) &priority_requested
);
5002 priority_requested
= prio
;
5004 fs_give((void **) &prio
);
5009 if(ps_global
->smime
)
5010 ps_global
->smime
->do_encrypt
= !ps_global
->smime
->do_encrypt
;
5013 if(ps_global
->smime
)
5014 ps_global
->smime
->do_sign
= !ps_global
->smime
->do_sign
;
5018 snprintf(dsn_string
, sizeof(dsn_string
), "DSN requested[%s%s%s%s]",
5019 (call_mailer_flags
& CM_DSN_NEVER
)
5021 (call_mailer_flags
& CM_DSN_DELAY
)
5023 (call_mailer_flags
& CM_DSN_SUCCESS
)
5025 (call_mailer_flags
& CM_DSN_NEVER
)
5027 : (call_mailer_flags
& CM_DSN_FULL
) ? "-Full"
5029 dsn_string
[sizeof(dsn_string
)-1] = '\0';
5032 /* remember selection */
5033 if(filters
&& filters
->index
> -1)
5034 sending_filter_requested
= ps_global
->VAR_SEND_FILTER
[filters
->index
];
5037 filters
->prev
->next
= NULL
; /* tie off list */
5038 while(filters
){ /* then free it */
5041 fs_give((void **)&filters
->filter
);
5043 fs_give((void **)&filters
);
5049 (void) F_SET(F_CAN_SUSPEND
, ps_global
, 1);
5054 ps_global
->redrawer
= redraw
;
5056 return((rstr
== NULL
) ? 0 : 1);
5061 * Allow user to choose a priority for sending.
5063 * Returns an allocated priority on success, NULL otherwise.
5066 choose_a_priority(char *default_val
)
5068 char *choice
= NULL
;
5069 char **priority_list
, **lp
;
5070 char *starting_val
= NULL
;
5075 for(cnt
= 0, p
= priorities
; p
&& p
->desc
; p
++)
5078 cnt
++; /* for NONE entry */
5079 lp
= priority_list
= (char **) fs_get((cnt
+ 1) * sizeof(*priority_list
));
5080 memset(priority_list
, 0, (cnt
+1) * sizeof(*priority_list
));
5082 for(i
= 0, p
= priorities
; p
&& p
->desc
; p
++){
5083 *lp
= cpystr(p
->desc
);
5084 if(default_val
&& !strcmp(default_val
, p
->desc
))
5085 starting_val
= (*lp
);
5090 none
= _("NONE - No X-Priority header included");
5093 starting_val
= (*lp
);
5095 /* TRANSLATORS: SELECT A PRIORITY is a screen title
5096 TRANSLATORS: Print something1 using something2.
5097 "priorities" is something1 */
5098 choice
= choose_item_from_list(priority_list
, NULL
, _("SELECT A PRIORITY"),
5099 _("priorities"), h_select_priority_screen
,
5100 _("HELP FOR SELECTING A PRIORITY"),
5104 q_status_message(SM_ORDER
, 1, 4, _("No change"));
5105 else if(!strcmp(choice
, none
))
5108 free_list_array(&priority_list
);
5115 dont_flow_this_time(void)
5117 return(flowing_requested
? 0 : 1);
5121 /*----------------------------------------------------------------------
5122 Call back for pico to display mime type of attachment
5124 Args: file -- filename being attached
5126 Returns: returns 1 on success (message queued), zero otherwise (don't know
5127 type so nothing queued).
5130 mime_type_for_pico(char *file
)
5134 void *file_contents
;
5136 body
= mail_newbody();
5137 body
->type
= TYPEOTHER
;
5138 body
->encoding
= ENCOTHER
;
5140 /* don't know where the cursor's been, reset it */
5142 if(!set_mime_type_by_extension(body
, file
)){
5143 if((file_contents
=(void *)so_get(FileStar
,file
,READ_ACCESS
|READ_FROM_LOCALE
)) != NULL
){
5144 body
->contents
.text
.data
= file_contents
;
5145 set_mime_type_by_grope(body
);
5149 if(body
->type
!= TYPEOTHER
){
5151 q_status_message3(SM_ORDER
, 0, 3,
5152 _("File %s attached as type %s/%s"), file
,
5153 body_types
[body
->type
],
5154 body
->subtype
? body
->subtype
: rfc822_default_subtype(body
->type
));
5159 pine_free_body(&body
);
5164 /*----------------------------------------------------------------------
5165 Call back for pico to receive an uploaded message
5167 Args: fname -- name for uploaded file (empty if they want us to assign it)
5168 size -- pointer to long to hold the attachment's size
5170 Notes: the attachment is uploaded to a temp file, and
5172 Returns: TRUE on success, FALSE otherwise
5175 upload_msg_to_pico(char *fname
, size_t fnlen
, long int *size
)
5177 char cmd
[MAXPATH
+1], *fnp
= NULL
;
5178 char *locale_name
= NULL
;
5182 dprint((1, "Upload cmd called to xfer \"%s\"\n",
5183 fname
? fname
: "<NO FILE>"));
5185 if(!fname
) /* no place for file name */
5188 if(!*fname
){ /* caller wants temp file */
5189 if((fnp
= temp_nam(NULL
, "pu")) != NULL
){
5190 strncpy(fname
, fnp
, fnlen
);
5191 fname
[fnlen
-1] = '\0';
5193 fs_give((void **)&fnp
);
5197 locale_name
= convert_to_locale(fname
);
5199 build_updown_cmd(cmd
, sizeof(cmd
), ps_global
->VAR_UPLOAD_CMD_PREFIX
,
5200 ps_global
->VAR_UPLOAD_CMD
, locale_name
? locale_name
: fname
);
5201 if((syspipe
= open_system_pipe(cmd
, NULL
, NULL
, PIPE_USER
| PIPE_RESET
,
5202 0, pipe_callback
, pipe_report_error
)) != NULL
){
5203 (void) close_system_pipe(&syspipe
, NULL
, pipe_callback
);
5204 if((l
= name_file_size(locale_name
? locale_name
: fname
)) < 0L){
5205 q_status_message2(SM_ORDER
| SM_DING
, 3, 4,
5206 "Error determining size of %s: %s", fname
,
5207 fnp
= error_description(errno
));
5209 "!!! Upload cmd \"%s\" failed for \"%s\": %s\n",
5211 fname
? fname
: "?",
5218 fs_give((void **) &locale_name
);
5223 q_status_message(SM_ORDER
| SM_DING
, 3, 4, _("Error opening pipe"));
5226 fs_give((void **) &locale_name
);
5233 cancel_for_pico(void (*redraw_pico
)(void))
5238 _("Cancel message (answering \"Confirm\" will abandon your mail message) ? ");
5239 void (*redraw
)(void) = ps_global
->redrawer
;
5240 static ESCKEY_S opts
[] = {
5241 {'c', 'c', "C", N_("Confirm")},
5242 {'n', 'n', "N", N_("No")},
5247 ps_global
->redrawer
= redraw_pico
;
5248 fix_windsize(ps_global
);
5251 rv
= radio_buttons(prompt
, -FOOTER_ROWS(ps_global
), opts
,
5252 'n', 'x', h_confirm_cancel
, RB_NORM
);
5253 if(rv
== 'c'){ /* user ACCEPTS! */
5258 q_status_message(SM_INFO
, 1, 3, _(" Type \"C\" to cancel message "));
5259 display_message('x');
5265 ps_global
->redrawer
= redraw
;
5270 /*----------------------------------------------------------------------
5271 Pass the first text segment of the message thru the "send filter"
5273 Args: body pointer and address for storage object of old data
5275 Returns: returns 1 on success, zero on error.
5278 filter_message_text(char *fcmd
, ENVELOPE
*outgoing
, struct mail_bodystruct
*body
,
5279 STORE_S
**old
, METAENV
*header
)
5281 char *cmd
, *tmpf
= NULL
, *resultf
= NULL
, *errstr
= NULL
, *mtf
= NULL
;
5282 int key
= 0, include_hdrs
= 0;
5284 STORE_S
**so
= (STORE_S
**)((body
->type
== TYPEMULTIPART
)
5285 ? &body
->nested
.part
->body
.contents
.text
.data
5286 : &body
->contents
.text
.data
),
5287 *tmp_so
= NULL
, *tmpf_so
,
5288 *save_local_so
, *readthis_so
, *our_tmpf_so
= NULL
;
5289 #define DO_HEADERS 1
5292 && (cmd
=expand_filter_tokens(fcmd
, outgoing
, &tmpf
, &resultf
, &mtf
,
5293 &key
, &include_hdrs
, NULL
))){
5296 * We need WRITE_TO_LOCALE here because the user is going to
5297 * be operating on tmpf. We need to change it back after they
5300 if((tmpf_so
= so_get(FileStar
, tmpf
, EDIT_ACCESS
|OWNER_ONLY
|WRITE_TO_LOCALE
)) != NULL
){
5302 so_puts(tmpf_so
, filter_session_key());
5303 so_puts(tmpf_so
, NEWLINE
);
5307 * If the headers are wanted for filtering, we can just
5308 * stick them in the tmpf file that is already there before
5309 * putting the body in.
5312 save_local_so
= lmc
.so
;
5313 lmc
.so
= tmpf_so
; /* write it to tmpf_so */
5314 lmc
.all_written
= lmc
.text_written
= lmc
.text_only
= 0;
5315 pine_rfc822_header(header
, body
, NULL
, NULL
);
5316 lmc
.so
= save_local_so
;
5319 so_seek(*so
, 0L, 0);
5320 gf_set_so_readc(&gc
, *so
);
5321 gf_set_so_writec(&pc
, tmpf_so
);
5323 errstr
= gf_pipe(gc
, pc
);
5324 gf_clear_so_readc(*so
);
5325 gf_clear_so_writec(tmpf_so
);
5329 errstr
= "Can't create space for filter temporary file.";
5331 else if(include_hdrs
){
5333 * Gf_filter wants a single storage object to read from.
5334 * If headers are wanted for filtering we'll have to put them
5335 * and the body into a temp file first and then use that
5336 * as the storage object for gf_filter.
5337 * We don't use WRITE_TO_LOCALE in this case because gf_filter
5338 * takes care of that.
5340 if((our_tmpf_so
= so_get(TmpFileStar
, NULL
, EDIT_ACCESS
|OWNER_ONLY
)) != NULL
){
5341 /* put headers in our_tmpf_so */
5342 save_local_so
= lmc
.so
;
5343 lmc
.so
= our_tmpf_so
; /* write it to our_tmpf_so */
5344 lmc
.all_written
= lmc
.text_written
= lmc
.text_only
= 0;
5345 pine_rfc822_header(header
, body
, NULL
, NULL
);
5346 lmc
.so
= save_local_so
;
5348 /* put body in our_tmpf_so */
5349 so_seek(*so
, 0L, 0);
5350 gf_set_so_readc(&gc
, *so
);
5351 gf_set_so_writec(&pc
, our_tmpf_so
);
5353 errstr
= gf_pipe(gc
, pc
);
5354 gf_clear_so_readc(*so
);
5355 gf_clear_so_writec(our_tmpf_so
);
5357 /* tell gf_filter to read from our_tmpf_so instead of *so */
5358 readthis_so
= our_tmpf_so
;
5361 errstr
= "Can't create space for temporary file.";
5367 if((tmp_so
= so_get(PicoText
, NULL
, EDIT_ACCESS
)) != NULL
){
5368 gf_set_so_writec(&pc
, tmp_so
);
5369 ps_global
->mangled_screen
= 1;
5376 if((fpipe
= open_system_pipe(cmd
, NULL
, NULL
,
5377 PIPE_NOSHELL
| PIPE_RESET
,
5378 0, pipe_callback
, pipe_report_error
)) != NULL
){
5379 if(close_system_pipe(&fpipe
, NULL
, pipe_callback
) == 0){
5381 /* now we undo the WRITE_FROM_LOCALE change in tmpf */
5382 if((tmpf_so
= so_get(FileStar
, tmpf
, READ_ACCESS
|READ_FROM_LOCALE
)) != NULL
){
5383 gf_set_so_readc(&gc
, tmpf_so
);
5385 errstr
= gf_pipe(gc
, pc
);
5386 gf_clear_so_readc(tmpf_so
);
5390 errstr
= "Can't open temp file filter wrote.";
5393 errstr
= "Filter command returned error.";
5396 errstr
= "Can't exec filter text.";
5399 errstr
= gf_filter(cmd
, key
? filter_session_key() : NULL
,
5400 readthis_so
, pc
, NULL
, 0, 0,
5404 so_give(&our_tmpf_so
);
5406 gf_clear_so_writec(tmp_so
);
5411 * Can't really be using stdout, so don't print message that
5412 * gets printed in the else. Ideally the program being called
5413 * will wait after showing the message, we might want to look
5414 * into doing the waiting in console based apps... or not.
5420 fprintf(stdout
, "\r\n%s Hit return to continue.", errstr
);
5422 while((ch
= read_char(300)) != ctrl('M')
5423 && ch
!= NO_OP_IDLE
)
5427 #endif /* _WINDOWS */
5428 BODY
*b
= (body
->type
== TYPEMULTIPART
)
5429 ? &body
->nested
.part
->body
: body
;
5431 *old
= *so
; /* save old so */
5432 *so
= tmp_so
; /* return new one */
5433 (*so
)->attr
= copy_parameters((*old
)->attr
);
5436 * If the command said it would return new MIME
5437 * mime type data, check it out...
5440 char buf
[MAILTMPLEN
], *s
;
5443 if((fp
= our_fopen(mtf
, "rb")) != NULL
){
5444 if(fgets(buf
, sizeof(buf
), fp
)
5445 && !struncmp(buf
, "content-", 8)
5446 && (s
= strchr(buf
+8, ':'))){
5447 BODY
*nb
= mail_newbody();
5449 for(*s
++ = '\0'; *s
== ' '; s
++)
5452 rfc822_parse_content_header(nb
,
5453 (char *) ucase((unsigned char *) buf
+8),s
);
5454 if(nb
->type
== TYPETEXT
5457 || strucmp(b
->subtype
, nb
->subtype
))){
5459 fs_give((void **) &b
->subtype
);
5461 b
->subtype
= nb
->subtype
;
5464 mail_free_body_parameter(&b
->parameter
);
5465 b
->parameter
= nb
->parameter
;
5466 nb
->parameter
= NULL
;
5467 mail_free_body_parameter(&nb
->parameter
);
5470 mail_free_body(&nb
);
5478 * Reevaluate the encoding in case form's changed...
5480 b
->encoding
= ENCOTHER
;
5481 set_mime_type_by_grope(b
);
5488 errstr
= "Can't create space for filtered text.";
5491 fs_give((void **)&cmd
);
5498 fs_give((void **)&tmpf
);
5503 fs_give((void **) &mtf
);
5507 if(name_file_size(resultf
) > 0L)
5508 display_output_file(resultf
, "Filter", NULL
, DOF_BRIEF
);
5509 our_unlink(resultf
);
5510 fs_give((void **)&resultf
);
5516 q_status_message1(SM_ORDER
| SM_DING
, 3, 6, _("Problem filtering: %s"),
5518 dprint((1, "Filter FAILED: %s\n",
5519 errstr
? errstr
: "?"));
5522 return(errstr
== NULL
);
5526 /*----------------------------------------------------------------------
5527 Copy the newsgroup name of the given mailbox into the given buffer
5534 pine_send_newsgroup_name(char *mailbox
, char *group_name
, size_t len
)
5538 if(*mailbox
== '#'){ /* Strip the leading "#news." */
5539 strncpy(group_name
, mailbox
+ 6, len
-1);
5540 group_name
[len
-1] = '\0';
5542 else if(mail_valid_net_parse(mailbox
, &mb
)){
5543 pine_send_newsgroup_name(mb
.mailbox
, group_name
, len
);
5550 /*----------------------------------------------------------------------
5551 Set up fields for passing to pico. Assumes first text part is
5552 intended to be passed along for editing, and is in the form of
5553 of a storage object brought into existence sometime before pico_send().
5556 outgoing2strings(METAENV
*header
, struct mail_bodystruct
*bod
, void **text
,
5557 PATMT
**pico_a
, int from_bounce
)
5562 * SIMPLIFYING ASSUMPTION #37: the first TEXT part's storage object
5563 * is guaranteed to be of type PicoText!
5565 if(bod
->type
== TYPETEXT
){
5566 *text
= so_text((STORE_S
*) bod
->contents
.text
.data
);
5568 /* mark storage object as user edited */
5570 (void) so_attr((STORE_S
*) bod
->contents
.text
.data
, "edited", "1");
5572 else if(bod
->type
== TYPEMULTIPART
){
5575 char *type
, *name
, *p
;
5579 * We used to jump out the window if the first part wasn't text,
5580 * but that may not be the case when bouncing a message with
5581 * a leading non-text segment. So, IT'S UNDERSTOOD that the
5582 * contents of the first part to send is still ALWAYS in a
5583 * PicoText storage object, *AND* if that object doesn't contain
5584 * data of type text, then it must contain THE ENCODED NON-TEXT
5585 * DATA of the piece being sent.
5587 * It's up to the programmer to make sure that such a message is
5588 * sent via pine_simple_send and never get to the composer via
5593 *text
= so_text((STORE_S
*) bod
->nested
.part
->body
.contents
.text
.data
);
5595 /* mark storage object as user edited */
5597 (void) so_attr((STORE_S
*) bod
->nested
.part
->body
.contents
.text
.data
, "edited", "1");
5600 * If we already had a list, blast it now, so we can build a new
5601 * attachment list that reflects what's really there...
5604 free_attachment_list(pico_a
);
5607 /* Simplifyihg assumption #28e. (see cross reference)
5608 All parts in the body passed in here that are not already
5609 in the attachments list are added to the end of the attachments
5610 list. Attachment items not in the body list will be taken care
5611 of in strings2outgoing, but they are unlikely to occur
5614 for(part
= bod
->nested
.part
->next
; part
!= NULL
; part
= part
->next
) {
5615 /* Already in list? */
5617 *ppa
&& strcmp((*ppa
)->id
, part
->body
.id
);
5618 ppa
= &(*ppa
)->next
)
5621 if(!*ppa
){ /* Not in the list! append it... */
5622 *ppa
= (PATMT
*)fs_get(sizeof(PATMT
));
5624 if(part
->body
.description
){
5628 len
= 4*strlen(part
->body
.description
)+1;
5629 p
= (char *)fs_get(len
*sizeof(char));
5630 if(rfc1522_decode_to_utf8((unsigned char *)p
,
5631 len
, part
->body
.description
) == (unsigned char *) p
){
5632 (*ppa
)->description
= p
;
5635 fs_give((void **)&p
);
5636 (*ppa
)->description
= cpystr(part
->body
.description
);
5640 (*ppa
)->description
= cpystr("");
5642 type
= type_desc(part
->body
.type
, part
->body
.subtype
,
5643 part
->body
.parameter
, NULL
, 0);
5646 * If we can find a "name" parm, display that too...
5648 if((name
= parameter_val(part
->body
.parameter
, "name")) != NULL
){
5649 /* Convert any [ or ]'s the name contained */
5650 for(p
= name
; *p
; p
++)
5661 (*ppa
)->filename
= fs_get(strlen(type
) + name_l
+ 5);
5663 snprintf((*ppa
)->filename
, strlen(type
) + name_l
+ 5, "[%s%s%s]", type
,
5664 name
? ": " : "", name
? name
: "");
5665 (*ppa
)->filename
[strlen(type
) + name_l
+ 5 - 1] = '\0';
5668 fs_give((void **) &name
);
5670 (*ppa
)->flags
= A_FLIT
;
5671 (*ppa
)->size
= cpystr(byte_string(
5672 send_body_size(&part
->body
)));
5674 part
->body
.id
= generate_message_id(NULL
);
5676 (*ppa
)->id
= cpystr(part
->body
.id
);
5677 (*ppa
)->next
= NULL
;
5684 /*------------------------------------------------------------------
5685 Malloc strings to pass to composer editor because it expects
5686 such strings so it can realloc them
5687 -----------------------------------------------------------------*/
5689 * turn any address fields into text strings
5692 * SIMPLIFYING ASSUMPTION #116: all header strings are understood
5693 * NOT to be RFC1522 decoded. Said differently, they're understood
5694 * to be RFC1522 ENCODED as necessary. The intent is to preserve
5695 * original charset tagging as far into the compose/send pipe as
5698 for(pf
= header
->local
; pf
&& pf
->name
; pf
= pf
->next
)
5706 pf
->scratch
= addr_list_string(*pf
->addr
, NULL
, 1);
5709 * Scan for and fix-up patently bogus fields.
5711 * NOTE: collaboration with this code and what's done in
5712 * reply.c:reply_cp_addr to package up the bogus stuff
5715 for(p
= pf
->scratch
; (p
= strstr(p
, "@" RAWFIELD
)); )
5717 if(*t
== '&'){ /* find "leading" token */
5721 * Rfc822_cat has been changed so that it now quotes
5722 * this sometimes. So we have to look out for quotes
5723 * which confuse the decoder. It was only quoting
5724 * because we were putting \r \n in the input, I think.
5726 if(t
> pf
->scratch
&& t
[-1] == '\"' && p
[-1] == '\"')
5727 t
[-1] = p
[-1] = ' ';
5729 *t
++ = ' '; /* replace token */
5730 *p
= '\0'; /* tie off string */
5731 u
= rfc822_base64((unsigned char *) t
,
5732 (unsigned long) strlen(t
),
5733 (unsigned long *) &l
);
5737 replacelen
= strlen(t
);
5738 *p
= '@'; /* restore 'p' */
5739 rplstr(p
, strlen(p
), 12, ""); /* clear special token */
5740 rplstr(t
, strlen(u
)-replacelen
+1, replacelen
, u
);
5742 fs_give((void **) &u
);
5745 HE(pf
)->start_here
= 1;
5749 else if(t
== pf
->scratch
)
5752 removing_leading_white_space(pf
->scratch
);
5757 * Replace control characters with ^C notation, unless
5758 * some conditions are met (see istrncpy).
5759 * If user doesn't edit, then we switch back to the
5760 * original version. If user does edit, then all bets
5763 iutf8ncpy((char *)tmp_20k_buf
, pf
->scratch
, SIZEOF_20KBUF
-1);
5764 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
5765 if((l
=strlen((char *)tmp_20k_buf
)) > strlen(pf
->scratch
)){
5766 fs_give((void **)&pf
->scratch
);
5767 pf
->scratch
= (char *)fs_get((l
+1) * sizeof(char));
5770 strncpy(pf
->scratch
, (char *)tmp_20k_buf
, l
+1);
5781 src
= pf
->scratch
? pf
->scratch
5782 : (*pf
->text
) ? *pf
->text
: "";
5784 len
= 4*strlen(src
)+1;
5785 p
= (char *)fs_get(len
* sizeof(char));
5786 if(rfc1522_decode_to_utf8((unsigned char *)p
, len
, src
) == (unsigned char *) p
){
5788 fs_give((void **)&pf
->scratch
);
5793 fs_give((void **)&p
);
5795 pf
->scratch
= cpystr(src
);
5802 * Replace control characters with ^C notation, unless
5803 * some conditions are met (see istrncpy).
5804 * If user doesn't edit, then we switch back to the
5805 * original version. If user does edit, then all bets
5808 iutf8ncpy((char *)tmp_20k_buf
, pf
->scratch
, SIZEOF_20KBUF
-1);
5809 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
5810 if((l
=strlen((char *)tmp_20k_buf
)) > strlen(pf
->scratch
)){
5811 fs_give((void **)&pf
->scratch
);
5812 pf
->scratch
= (char *)fs_get((l
+1) * sizeof(char));
5815 strncpy(pf
->scratch
, (char *)tmp_20k_buf
, l
+1);
5827 /*----------------------------------------------------------------------
5828 Restore fields returned from pico to form useful to sending
5832 strings2outgoing(METAENV
*header
, struct mail_bodystruct
**bod
, PATMT
*attach
, int flow_it
)
5837 we_cancel
= busy_cue(NULL
, NULL
, 1);
5840 * turn any local address strings into address lists
5842 for(pf
= header
->local
; pf
&& pf
->name
; pf
= pf
->next
)
5844 char *the_address
= NULL
;
5848 removing_trailing_white_space(pf
->scratch
);
5850 if((the_address
|| *pf
->scratch
) && pf
->addr
){
5851 ADDRESS
*new_addr
= NULL
;
5852 static char *fakedomain
= "@";
5855 the_address
= pf
->scratch
;
5857 rfc822_parse_adrlist(&new_addr
, the_address
,
5858 (F_ON(F_COMPOSE_REJECTS_UNQUAL
, ps_global
))
5859 ? fakedomain
: ps_global
->maildomain
);
5860 mail_free_address(pf
->addr
); /* free old addrs */
5861 *pf
->addr
= new_addr
; /* assign new addr */
5864 mail_free_address(pf
->addr
); /* free old addrs */
5870 fs_give((void **)pf
->text
);
5873 *pf
->text
= cpystr(pf
->scratch
);
5882 fs_give((void **)&pf
->scratch
); /* free now useless text */
5885 create_message_body(bod
, attach
, flow_it
);
5888 cancel_busy_cue(-1);
5892 /*----------------------------------------------------------------------
5894 The head of the body list here is always either TEXT or MULTIPART. It may be
5895 changed from TEXT to MULTIPART if there are attachments to be added
5896 and it is not already multipart.
5899 create_message_body(struct mail_bodystruct
**b
, PATMT
*attach
, int flow_it
)
5903 BODY
*tmp_body
, *text_body
= NULL
;
5904 void *file_contents
;
5908 TIME_STAMP("create_body start.", 1);
5910 * if conditions are met short circuit MIME wrapping
5912 if((*b
)->type
!= TYPEMULTIPART
&& !attach
){
5914 /* only override assigned encoding if it might need upgrading */
5915 if((*b
)->type
== TYPETEXT
&& (*b
)->encoding
== ENC7BIT
)
5916 (*b
)->encoding
= ENCOTHER
;
5918 create_message_body_text(*b
, flow_it
);
5920 if(F_ON(F_COMPOSE_ALWAYS_DOWNGRADE
, ps_global
)
5921 || !((*b
)->encoding
== ENC8BIT
5922 || (*b
)->encoding
== ENCBINARY
)){
5923 TIME_STAMP("create_body end.", 1);
5926 else /* protect 8bit in multipart */
5930 if((*b
)->type
== TYPETEXT
) {
5931 /*-- Current type is text, but there are attachments to add --*/
5932 /*-- Upgrade to a TYPEMULTIPART --*/
5933 tmp_body
= (BODY
*)mail_newbody();
5934 tmp_body
->type
= TYPEMULTIPART
;
5935 tmp_body
->nested
.part
= mail_newbody_part();
5938 * Why do we do this?
5939 * The problem is that base64 or quoted-printable encoding is
5940 * sensitive to having random data appended to it's end. If
5941 * we use a single part TEXT message and something in between
5942 * us and the end appends advertising without adjusting for
5943 * the encoding, the message is screwed up. So we wrap the
5944 * text part inside a multipart and then the appended data
5945 * will come after the boundary.
5947 * We wish we could do this on the way out the door in a
5948 * child of post_rfc822_output because at that point we know
5949 * the character set and the encoding being used. For example,
5950 * iso-2022-jp is an encoding that is not sensitive to data
5951 * appended to the end, so it wouldn't need to be wrapped.
5952 * We could conceivably have post_rfc822_body inspect the
5953 * body and change it before doing the output. It would work
5954 * but would be very fragile. We'd be passed a body from
5955 * c-client to output and instead of just doing the output
5956 * we'd change the body and then output it. Not worth it
5957 * since the multipart wrapping is completely correct for
5958 * MIME-aware mailers.
5960 (void) copy_body(&(tmp_body
->nested
.part
->body
), *b
);
5961 /* move contents which were NOT copied */
5962 tmp_body
->nested
.part
->body
.contents
.text
.data
= (*b
)->contents
.text
.data
;
5963 (*b
)->contents
.text
.data
= NULL
;
5966 tmp_body
->nested
.part
->body
= **b
;
5968 (*b
)->subtype
= (*b
)->id
= (*b
)->description
= NULL
;
5969 (*b
)->parameter
= NULL
;
5970 (*b
)->contents
.text
.data
= NULL
;
5978 /*-- Now type must be MULTIPART with first part text --*/
5979 (*b
)->nested
.part
->body
.encoding
= ENCOTHER
;
5980 create_message_body_text(&((*b
)->nested
.part
->body
), flow_it
);
5983 /*------ Go through the parts list remove those to be deleted -----*/
5984 for(pp
= &(*b
)->nested
.part
->next
; *pp
;){
5985 for(pa
= attach
; pa
&& (*pp
)->body
.id
; pa
= pa
->next
)
5986 /* already existed? */
5987 if(pa
->id
&& strcmp(pa
->id
, (*pp
)->body
.id
) == 0){
5988 char *orig_descp
= NULL
, *cs
= NULL
;
5991 * decode original to see if it matches what was decoded
5992 * when we sent it in.
5995 if((*pp
)->body
.description
)
5996 orig_descp
= (char *) rfc1522_decode_to_utf8((unsigned char *) tmp_20k_buf
,
5997 SIZEOF_20KBUF
, (*pp
)->body
.description
);
5999 if(!(*pp
)->body
.description
/* update description? */
6000 || (pa
->description
&& strcmp(pa
->description
, orig_descp
))){
6001 if((*pp
)->body
.description
)
6002 fs_give((void **) &(*pp
)->body
.description
);
6004 /* encoding happens as msg text is written */
6005 (*pp
)->body
.description
= cpystr(pa
->description
);
6009 fs_give((void **) &cs
);
6015 p
= *pp
; /* prepare to zap *pp */
6016 *pp
= p
->next
; /* pull next one in list up */
6017 p
->next
= NULL
; /* tie off removed node */
6019 pine_free_body_data(&p
->body
); /* clean up contained data */
6020 mail_free_body_part(&p
); /* free up the part */
6026 /*---------- Now add any new attachments ---------*/
6027 for(p
= (*b
)->nested
.part
; p
->next
!= NULL
; p
= p
->next
);
6028 for(pa
= attach
; pa
!= NULL
; pa
= pa
->next
) {
6030 continue; /* Has an ID, it's old */
6033 * the idea is handle ALL attachments as open FILE *'s. Actual
6034 * encoding and such is handled at the time the message
6035 * is shoved into the mail slot or written to disk...
6037 * Also, we never unlink a file, so it's up to whoever opens
6038 * it to deal with tmpfile issues.
6040 if((file_contents
= (void *)so_get(FileStar
, pa
->filename
,
6041 READ_ACCESS
)) == NULL
){
6042 q_status_message2(SM_ORDER
| SM_DING
, 3, 4,
6043 _("Error \"%s\", couldn't attach file \"%s\""),
6044 error_description(errno
), pa
->filename
);
6045 display_message('x');
6049 p
->next
= mail_newbody_part();
6051 p
->body
.id
= generate_message_id(NULL
);
6052 p
->body
.contents
.text
.data
= file_contents
;
6055 * Set type to unknown and let set_mime_type_by_* figure it out.
6056 * Always encode attachments we add as BINARY.
6058 p
->body
.type
= TYPEOTHER
;
6059 p
->body
.encoding
= ENCBINARY
;
6060 p
->body
.size
.bytes
= name_file_size(pa
->filename
);
6061 if(!set_mime_type_by_extension(&p
->body
, pa
->filename
)){
6062 set_mime_type_by_grope(&p
->body
);
6063 set_charset_possibly_to_ascii(&p
->body
, ps_global
->keyboard_charmap
);
6066 so_release((STORE_S
*)p
->body
.contents
.text
.data
);
6068 if(pa
->description
) /* encoding happens when msg written */
6069 p
->body
.description
= cpystr(pa
->description
);
6071 /* Add name attribute for backward compatibility */
6072 for(parmp
= &p
->body
.parameter
; *parmp
; )
6073 if(!struncmp((*parmp
)->attribute
, "name", 4)
6074 && (!*((*parmp
)->attribute
+ 4)
6075 || *((*parmp
)->attribute
+ 4) == '*')){
6076 PARAMETER
*free_me
= *parmp
;
6077 *parmp
= (*parmp
)->next
;
6078 free_me
->next
= NULL
;
6079 mail_free_body_parameter(&free_me
);
6082 parmp
= &(*parmp
)->next
;
6084 set_parameter(parmp
, "name",
6086 ? ((lc
= last_cmpnt(pa
->filename
)) ? lc
: pa
->filename
)
6089 /* Then set the Content-Disposition ala RFC1806 */
6090 if(!p
->body
.disposition
.type
){
6091 p
->body
.disposition
.type
= cpystr("attachment");
6092 for(parmp
= &p
->body
.disposition
.parameter
; *parmp
; )
6093 if(!struncmp((*parmp
)->attribute
, "filename", 4)
6094 && (!*((*parmp
)->attribute
+ 4)
6095 || *((*parmp
)->attribute
+ 4) == '*')){
6096 PARAMETER
*free_me
= *parmp
;
6097 *parmp
= (*parmp
)->next
;
6098 free_me
->next
= NULL
;
6099 mail_free_body_parameter(&free_me
);
6102 parmp
= &(*parmp
)->next
;
6104 set_parameter(parmp
, "filename",
6106 ? ((lc
= last_cmpnt(pa
->filename
)) ? lc
: pa
->filename
)
6111 pa
->id
= cpystr(p
->body
.id
);
6115 * Now, if this multipart has but one text piece (that is, no
6116 * attachments), then downgrade from a composite type to a discrete
6117 * text/plain message if CTE is not 8bit.
6119 if(!(*b
)->nested
.part
->next
6120 && (*b
)->nested
.part
->body
.type
== TYPETEXT
6121 && (F_ON(F_COMPOSE_ALWAYS_DOWNGRADE
, ps_global
)
6122 || !((*b
)->nested
.part
->body
.encoding
== ENC8BIT
6123 || (*b
)->nested
.part
->body
.encoding
== ENCBINARY
))){
6124 /* Clone the interesting body part */
6125 tmp_body
= mail_newbody();
6126 *tmp_body
= (*b
)->nested
.part
->body
;
6127 /* and rub out what we don't want cleaned up when it's free'd */
6128 mail_initbody(&(*b
)->nested
.part
->body
);
6134 TIME_STAMP("create_body end.", 1);
6139 * Fill in text BODY part's structure
6143 create_message_body_text(struct mail_bodystruct
*b
, int flow_it
)
6145 set_mime_type_by_grope(b
);
6147 remove_parameter(&b
->parameter
, "format"); /* we will set it up below */
6148 remove_parameter(&b
->parameter
, "delsp"); /* we never set this up */
6150 if(F_OFF(F_QUELL_FLOWED_TEXT
, ps_global
)
6151 && F_OFF(F_STRIP_WS_BEFORE_SEND
, ps_global
)
6153 set_parameter(b
? &b
->parameter
: NULL
, "format", "flowed");
6160 * free_attachment_list - free attachments in given list
6163 free_attachment_list(PATMT
**alist
)
6167 while(alist
&& *alist
){ /* pointer pointing to something */
6168 leading
= (*alist
)->next
;
6169 if((*alist
)->description
)
6170 fs_give((void **)&(*alist
)->description
);
6172 if((*alist
)->filename
){
6173 if((*alist
)->flags
& A_TMP
)
6174 if(our_unlink((*alist
)->filename
) < 0)
6175 dprint((1, "-- Can't unlink(%s): %s\n",
6176 (*alist
)->filename
? (*alist
)->filename
: "?",
6177 error_description(errno
)));
6179 fs_give((void **)&(*alist
)->filename
);
6183 fs_give((void **)&(*alist
)->size
);
6186 fs_give((void **)&(*alist
)->id
);
6188 fs_give((void **)alist
);
6196 set_body_size(struct mail_bodystruct
*b
)
6201 we_cancel
= busy_cue(NULL
, NULL
, 1);
6202 so_seek((STORE_S
*)b
->contents
.text
.data
, 0L, 0);
6204 while(so_readc(&c
, (STORE_S
*)b
->contents
.text
.data
))
6208 cancel_busy_cue(-1);
6213 * view_as_rich - set the rich_header flag
6215 * name - name of the header field
6216 * deflt - default value to return if user didn't set it
6218 * Note: if the user tries to turn them all off with "", then
6219 * we take that to mean default, since otherwise there is no
6220 * way to get to the headers.
6223 view_as_rich(char *name
, int deflt
)
6228 p
= ps_global
->VAR_COMP_HDRS
;
6231 for(; (q
= *p
) != NULL
; p
++){
6232 if(!struncmp(q
, name
, strlen(name
)))
6233 return 0; /* 0 means we *do* view it by default */
6236 return 1; /* 1 means it starts out hidden */
6243 * background_posting - return whether or not we're already in the process
6247 background_posting(int gripe
)
6249 if(ps_global
->post
){
6251 q_status_message(SM_ORDER
|SM_DING
, 3, 3,
6252 _("Can't post while posting!"));
6260 /*----------------------------------------------------------------------
6261 Validate the given subject relative to any news groups.
6265 Returns: always returns 1, but also returns error if
6268 valid_subject(char *given
, char **expanded
, char **error
, BUILDER_ARG
*fcc
, int *mangled
)
6270 struct headerentry
*hp
;
6273 *expanded
= cpystr(given
);
6277 * Now look for any header entry we passed to pico that has to do
6278 * with news. If there's no subject, gripe.
6280 for(hp
= pbf
->headents
; hp
->prompt
; hp
++)
6281 if(hp
->help
== h_composer_news
){
6282 if(hp
->hd_text
->text
[0] && !*given
)
6284 _("News postings MUST have a subject! Please add one!"));
6295 * This is the build_address used by the composer to check for an address
6298 * Args: to -- the passed in line to parse
6299 * full_to -- Address of a pointer to return the full address in.
6300 * This will be allocated here and freed by the caller.
6301 * error -- Address of a pointer to return an error message in.
6302 * This will be allocated here and freed by the caller.
6303 * barg -- Address of a pointer to return the fcc in is in
6304 * fcc->tptr. It will have already been allocated by the
6305 * caller but we may free it and reallocate if we wish.
6306 * Caller will free it.
6308 * Result: 0 is returned if address was OK,
6309 * -1 if address wasn't OK.
6311 * Side effect: Can flush addrbook entry cache entries so they need to be
6312 * re-fetched afterwords.
6315 build_address(char *to
, char **full_to
, char **error
, BUILDER_ARG
*barg
, int *mangled
)
6318 int ret_val
, no_repo
= 0, *save_nesting_level
;
6320 PrivateTop
*pt
= NULL
;
6321 PrivateAffector
*af
= NULL
;
6322 char *fcc_local
= NULL
;
6323 jmp_buf save_jmp_buf
;
6325 dprint((5, "- build_address - (%s)\n", to
? to
: "nul"));
6327 /* check to see if to string is empty to avoid work */
6328 for(p
= to
; p
&& *p
&& isspace((unsigned char)*p
); p
++)
6333 *full_to
= cpystr(to
? to
: ""); /* because pico does a strcmp() */
6339 *full_to
= (char *)NULL
;
6342 *error
= (char *)NULL
;
6344 /* No guarantee cursor or status line is how we saved it */
6346 mark_status_unknown();
6348 if(ps_global
->remote_abook_validity
> 0 &&
6349 adrbk_check_and_fix_all(ab_nesting_level
== 0, 0, 0) && mangled
)
6350 *mangled
|= BUILDER_SCREEN_MANGLED
;
6353 * If we end up jumping back here because somebody else changed one of
6354 * our addrbooks out from underneath us, we may well leak some memory.
6355 * That's probably ok since this will be very rare.
6357 * The reason for the memcpy of the jmp_buf is that we may actually
6358 * be indirectly calling this function from within the address book.
6359 * For example, we may be in the address book screen and then run
6360 * the ComposeTo command which puts us in the composer, then we call
6361 * build_address from there which resets addrbook_changed_unexpectedly.
6362 * Once we leave build_address we need to reset addrbook_changed_un...
6363 * because this position on the stack will no longer be valid.
6364 * Same is true of the other setjmp's in this file which are wrapped
6367 save_nesting_level
= cpyint(ab_nesting_level
);
6368 memcpy(save_jmp_buf
, addrbook_changed_unexpectedly
, sizeof(jmp_buf));
6369 if(setjmp(addrbook_changed_unexpectedly
)){
6375 *error
= (char *)NULL
;
6377 if(full_to
&& *full_to
)
6378 fs_give((void **)full_to
);
6380 q_status_message(SM_ORDER
, 3, 5, "Resetting address book...");
6382 "RESETTING address book... build_address(%s)!\n", to
? to
: "?"));
6384 ab_nesting_level
= *save_nesting_level
;
6390 ret_val
= build_address_internal(bldto
, full_to
, error
,
6391 barg
? &fcc_local
: NULL
,
6392 &no_repo
, NULL
, save_and_restore
,
6395 if(save_nesting_level
)
6396 fs_give((void **)&save_nesting_level
);
6399 * Have to rfc1522_decode the full_to string before sending it back.
6401 if(full_to
&& *full_to
){
6405 len
= 4*strlen(*full_to
)+1;
6406 q
= (char *)fs_get(len
* sizeof(char));
6407 p
= (char *)rfc1522_decode_to_utf8((unsigned char *)q
, len
, *full_to
);
6409 /* p == q means that decoding happened, p is decoded *full_to */
6411 fs_give((void **)full_to
);
6415 fs_give((void **)&q
);
6421 /* Pt will point to headents[Fcc].bldr_private */
6423 if(barg
&& barg
->aff
)
6424 pt
= (PrivateTop
*)(*barg
->aff
);
6427 * If *barg->aff is set, that means fcc was set from a list
6428 * during some previous builder call.
6429 * If the current To line contains the old expansion as a prefix, then
6430 * we should leave things as they are. In order to decide that,
6431 * we look at a hash value computed from the strings.
6433 if(pt
&& (af
=pt
->affector
) && af
->who
== BP_To
){
6437 if(len
>= af
->cksumlen
){
6440 save
= to
[af
->cksumlen
];
6441 to
[af
->cksumlen
] = '\0';
6442 csum
= line_hash(to
);
6443 to
[af
->cksumlen
] = save
;
6446 csum
= af
->cksumval
+ 1; /* something not equal to cksumval */
6451 (pt
->affector
->who
== BP_To
&& csum
!= pt
->affector
->cksumval
)){
6453 /* replace fcc value */
6455 fs_give((void **)&barg
->tptr
);
6457 barg
->tptr
= fcc_local
;
6461 *barg
->aff
= (void *)fs_get(sizeof(PrivateTop
));
6462 pt
= (PrivateTop
*)(*barg
->aff
);
6463 memset((void *)pt
, 0, sizeof(PrivateTop
));
6469 (PrivateAffector
*)fs_get(sizeof(PrivateAffector
));
6473 af
->cksumlen
= strlen(((full_to
&& *full_to
)
6475 af
->cksumval
= line_hash(((full_to
&& *full_to
)
6480 * If result is reproducible, we don't keep track here.
6483 fs_give((void **)&pt
->affector
);
6488 fs_give((void **)&fcc_local
); /* unused in this case */
6491 /* This is so pico will erase the old message */
6492 if(error
!= NULL
&& *error
== NULL
)
6493 *error
= cpystr("");
6495 memcpy(addrbook_changed_unexpectedly
, save_jmp_buf
, sizeof(jmp_buf));
6496 flush_status_messages(1);
6502 * This is the builder used by the composer for the Lcc line.
6504 * Args: lcc -- the passed in Lcc line to parse
6505 * full_lcc -- Address of a pointer to return the full address in.
6506 * This will be allocated here and freed by the caller.
6507 * error -- Address of a pointer to return an error message in.
6508 * This is not allocated so should not be freed by the caller.
6509 * barg -- This is a pointer to text for affected entries which
6510 * we may be changing. The first one in the list is the
6511 * To entry. We may put the name of the list in empty
6512 * group syntax form there (like List Name: ;).
6513 * The second one in the list is the fcc field.
6514 * The tptr members already point to text allocated in the
6515 * caller. We may free and reallocate here, caller will
6516 * free the result in any case.
6518 * Result: 0 is returned if address was OK,
6519 * -1 if address wasn't OK.
6521 * Side effect: Can flush addrbook entry cache entries so they need to be
6522 * re-fetched afterwords.
6525 build_addr_lcc(char *lcc
, char **full_lcc
, char **error
, BUILDER_ARG
*barg
, int *mangled
)
6528 no_repo
= 0; /* fcc or lcc not reproducible */
6529 int *save_nesting_level
;
6531 PrivateTop
*pt
= NULL
;
6532 PrivateAffector
*af
= NULL
;
6537 jmp_buf save_jmp_buf
;
6539 dprint((5, "- build_addr_lcc - (%s)\n", lcc
? lcc
: "nul"));
6541 /* check to see if to string is empty to avoid work */
6542 for(p
= lcc
; p
&& *p
&& isspace((unsigned char)*p
); p
++)
6547 *full_lcc
= cpystr(lcc
? lcc
: ""); /* because pico does a strcmp() */
6553 *error
= (char *)NULL
;
6555 if(ps_global
->remote_abook_validity
> 0 &&
6556 adrbk_check_and_fix_all(ab_nesting_level
== 0, 0, 0) && mangled
)
6557 *mangled
|= BUILDER_SCREEN_MANGLED
;
6560 * If we end up jumping back here because somebody else changed one of
6561 * our addrbooks out from underneath us, we may well leak some memory.
6562 * That's probably ok since this will be very rare.
6564 save_nesting_level
= cpyint(ab_nesting_level
);
6565 memcpy(save_jmp_buf
, addrbook_changed_unexpectedly
, sizeof(jmp_buf));
6566 if(setjmp(addrbook_changed_unexpectedly
)){
6573 *error
= (char *)NULL
;
6575 if(full_lcc
&& *full_lcc
)
6576 fs_give((void **)full_lcc
);
6578 q_status_message(SM_ORDER
, 3, 5, "Resetting address book...");
6580 "RESETTING address book... build_address(%s)!\n", lcc
? lcc
: "?"));
6582 ab_nesting_level
= *save_nesting_level
;
6587 bldlcc
.arg
.str
= lcc
;
6590 * To is first affected_entry and Fcc is second.
6591 * The conditional stuff for the fcc argument says to only change the
6592 * fcc if the fcc pointer is passed in non-null, and the To pointer
6593 * is also non-null. If they are null, that means they've already been
6594 * entered (are sticky). We don't affect fcc if either fcc or To has
6597 ret_val
= build_address_internal(bldlcc
,
6600 (barg
&& barg
->next
&& barg
->next
->tptr
&& barg
->tptr
)
6601 ? &fcc_local
: NULL
,
6603 (barg
&& barg
->tptr
) ? &to
: NULL
,
6604 save_and_restore
, 0, mangled
);
6607 if(save_nesting_level
)
6608 fs_give((void **)&save_nesting_level
);
6610 /* full_lcc is what ends up in the Lcc: line */
6611 if(full_lcc
&& *full_lcc
){
6615 * Have to rfc1522_decode the full_lcc string before sending it back.
6617 len
= 4*strlen(*full_lcc
)+1;
6618 p
= (char *)fs_get(len
* sizeof(char));
6619 if(rfc1522_decode_to_utf8((unsigned char *)p
, len
, *full_lcc
) == (unsigned char *)p
){
6620 fs_give((void **)full_lcc
);
6624 fs_give((void **)&p
);
6627 /* to is what ends up in the To: line */
6633 * Have to rfc1522_decode the full_to string before sending it back.
6635 len
= 4*strlen(to
)+1;
6636 p
= (char *)fs_get(len
* sizeof(char));
6638 if(rfc1522_decode_to_utf8((unsigned char *)p
, len
, to
) == (unsigned char *)p
){
6640 * If the caller wants us to try to preserve the charset
6641 * information (they set aff) we copy it into encoded->etext.
6642 * We don't have to worry about pasting together pieces of
6643 * etext like we do in build_address because whenever the
6644 * Lcc line is setting the To line it will be setting the
6645 * whole line, not modifying it.
6646 * Pt will point to headents[To].bldr_private.
6648 if(barg
&& barg
->aff
){
6649 pt
= (PrivateTop
*)(*barg
->aff
);
6652 *barg
->aff
= (void *)fs_get(sizeof(PrivateTop
));
6653 pt
= (PrivateTop
*)(*barg
->aff
);
6654 memset((void *)pt
, 0, sizeof(PrivateTop
));
6658 fs_give((void **)&to
);
6662 fs_give((void **)&p
);
6665 fs_give((void **)&dummy
);
6669 * This part is recording the fact that the To line was set to
6670 * what it is by entering something on the Lcc line. In particular,
6671 * if a list alias was entered here then the fullname of the list
6672 * goes in the To line. We save this affector information so that
6673 * we can tell it shouldn't be modified if we call build_addr_lcc
6674 * again unless we actually modified what's in the Lcc line so that
6675 * it doesn't start with the same thing. The problem we're solving
6676 * is that the contents of the Lcc line no longer look like the
6677 * list they were derived from.
6678 * Pt will point to headents[To].bldr_private.
6680 if(barg
&& barg
->aff
)
6681 pt
= (PrivateTop
*)(*barg
->aff
);
6683 if(pt
&& (af
=pt
->affector
) && af
->who
== BP_Lcc
){
6687 if(len
>= af
->cksumlen
){
6690 save
= lcc
[af
->cksumlen
];
6691 lcc
[af
->cksumlen
] = '\0';
6692 csum
= line_hash(lcc
);
6693 lcc
[af
->cksumlen
] = save
;
6696 csum
= af
->cksumval
+ 1; /* so they aren't equal */
6701 pt
->affector
->who
!= BP_Lcc
||
6702 (pt
->affector
->who
== BP_Lcc
&& csum
!= pt
->affector
->cksumval
)){
6704 /* replace to value */
6705 if(barg
->tptr
&& barg
->tptr
[0]){
6709 l
= strlen(barg
->tptr
) + strlen(to
? to
: "") + 2;
6710 t
= (char *)fs_get((l
+1) * sizeof(char));
6711 snprintf(t
, l
+1, "%s%s%s",
6713 (to
&& *to
) ? ", " : "",
6714 (to
&& *to
) ? to
: "");
6715 fs_give((void **)&barg
->tptr
);
6717 fs_give((void **)&to
);
6723 fs_give((void **)&barg
->tptr
);
6730 *barg
->aff
= (void *)fs_get(sizeof(PrivateTop
));
6731 pt
= (PrivateTop
*)(*barg
->aff
);
6732 memset((void *)pt
, 0, sizeof(PrivateTop
));
6738 (PrivateAffector
*)fs_get(sizeof(PrivateAffector
));
6742 af
->cksumlen
= strlen(((full_lcc
&& *full_lcc
)
6744 af
->cksumval
= line_hash(((full_lcc
&& *full_lcc
)
6749 * If result is reproducible, we don't keep track here.
6752 fs_give((void **)&pt
->affector
);
6757 fs_give((void **)&to
); /* unused in this case */
6764 * If *barg->next->aff is set, that means fcc was set from a list
6765 * during some previous builder call. If the current Lcc line
6766 * contains the old expansion as a prefix, then we should leave
6767 * things as they are. In order to decide that we look at a hash
6768 * value computed from the strings.
6769 * Pt will point to headents[Fcc].bldr_private
6772 if(barg
&& barg
->next
&& barg
->next
->aff
)
6773 pt
= (PrivateTop
*)(*barg
->next
->aff
);
6775 if(pt
&& (af
=pt
->affector
) && af
->who
== BP_Lcc
){
6779 if(len
>= af
->cksumlen
){
6782 save
= lcc
[af
->cksumlen
];
6783 lcc
[af
->cksumlen
] = '\0';
6784 csum
= line_hash(lcc
);
6785 lcc
[af
->cksumlen
] = save
;
6788 csum
= af
->cksumval
+ 1; /* something not equal to cksumval */
6793 pt
->affector
->who
!= BP_Lcc
||
6794 (pt
->affector
->who
== BP_Lcc
&& csum
!= pt
->affector
->cksumval
)){
6796 /* replace fcc value */
6797 if(barg
->next
->tptr
)
6798 fs_give((void **)&barg
->next
->tptr
);
6800 barg
->next
->tptr
= fcc_local
;
6802 if(barg
->next
->aff
){
6804 *barg
->next
->aff
= (void *)fs_get(sizeof(PrivateTop
));
6805 pt
= (PrivateTop
*)(*barg
->next
->aff
);
6806 memset((void *)pt
, 0, sizeof(PrivateTop
));
6812 (PrivateAffector
*)fs_get(sizeof(PrivateAffector
));
6816 af
->cksumlen
= strlen(((full_lcc
&& *full_lcc
)
6818 af
->cksumval
= line_hash(((full_lcc
&& *full_lcc
)
6823 * If result is reproducible, we don't keep track here.
6826 fs_give((void **)&pt
->affector
);
6831 fs_give((void **)&fcc_local
); /* unused in this case */
6835 if(error
!= NULL
&& *error
== NULL
)
6836 *error
= cpystr("");
6838 memcpy(addrbook_changed_unexpectedly
, save_jmp_buf
, sizeof(jmp_buf));
6839 flush_status_messages(0);
6844 /*----------------------------------------------------------------------
6845 Verify and canonicalize news groups names.
6846 Called from the message composer
6848 Args: given_group -- List of groups typed by user
6849 expanded_group -- pointer to point to expanded list, which will be
6850 allocated here and freed in caller. If this is
6851 NULL, don't attempt to validate.
6852 error -- pointer to store error message
6853 fcc -- pointer to point to fcc, which will be
6854 allocated here and freed in caller
6856 Returns: 0 if all is OK
6857 -1 if addresses weren't valid
6859 Test the given list of newstroups against those recognized by our nntp
6860 servers. Testing by actually trying to open the list is much cheaper, both
6861 in bandwidth and memory, than yanking the whole list across the wire.
6864 news_build(char *given_group
, char **expanded_group
, char **error
, BUILDER_ARG
*fcc
, int *mangled
)
6867 char *fccptr
= NULL
;
6869 if(fcc
&& fcc
->tptr
)
6870 fccptr
= cpystr(fcc
->tptr
);
6874 rv
= news_grouper(given_group
, expanded_group
, error
, &fccptr
, news_build_busy
);
6876 /* assign any new fcc to the BUILDER_ARG */
6880 if(fcc
->tptr
&& strcmp(fcc
->tptr
, fccptr
)){
6881 fs_give((void **) &fcc
->tptr
);
6888 fs_give((void **) &fccptr
);
6891 /* deal with any busy indicator */
6895 mark_status_dirty();
6896 display_message('x');
6898 *mangled
|= BUILDER_MESSAGE_DISPLAYED
;
6907 news_build_busy(void)
6909 news_busy_cue
= busy_cue("Validating newsgroup(s)", NULL
, 0);
6913 #if defined(DOS) || defined(OS2)
6915 /*----------------------------------------------------------------------
6916 Verify that the necessary pieces are around to allow for
6917 message sending under DOS
6919 Args: strict -- tells us if a remote stream is required before
6920 sending is permitted.
6922 The idea is to make sure pine knows enough to put together a valid
6923 from line. The things we MUST know are a user-id, user-domain and
6924 smtp server to dump the message off on. Typically these are
6925 provided in pine's configuration file, but if not, the user is
6931 char prompt
[100], answer
[80];
6936 * query for user name portion of address, use IMAP login
6939 if(!ps_global
->VAR_USER_ID
|| ps_global
->VAR_USER_ID
[0] == '\0'){
6941 int no_prompt_user_id
= 0;
6943 if(ps_global
->mail_stream
&& ps_global
->mail_stream
->mailbox
6944 && mail_valid_net_parse(ps_global
->mail_stream
->mailbox
, &mb
)
6946 strncpy(answer
, mb
.user
, sizeof(answer
)-1);
6947 answer
[sizeof(answer
)-1] = '\0';
6949 else if(F_ON(F_QUELL_USER_ID_PROMPT
, ps_global
)){
6950 /* no user-id prompting if set */
6951 no_prompt_user_id
= 1;
6953 if(!ps_global
->mail_stream
)
6954 do_broach_folder(ps_global
->inbox_name
,
6955 ps_global
->context_list
, NULL
, DB_INBOXWOCNTXT
);
6956 if(ps_global
->mail_stream
&& ps_global
->mail_stream
->mailbox
6957 && mail_valid_net_parse(ps_global
->mail_stream
->mailbox
, &mb
)
6959 strncpy(answer
, mb
.user
, sizeof(answer
)-1);
6960 answer
[sizeof(answer
)-1] = '\0';
6968 if(F_ON(F_QUELL_USER_ID_PROMPT
, ps_global
) && answer
[0]){
6969 /* No prompt, just assume mailbox login is user-id */
6970 no_prompt_user_id
= 1;
6974 snprintf(prompt
,sizeof(prompt
),_("User-id for From address : "));
6975 prompt
[sizeof(prompt
)-1] = '\0';
6978 while(!no_prompt_user_id
) {
6979 flags
= OE_APPEND_CURRENT
;
6980 rc
= optionally_enter(answer
,-FOOTER_ROWS(ps_global
),0,
6981 sizeof(answer
),prompt
,NULL
,help
,&flags
);
6986 help
= (help
== NO_HELP
) ? h_sticky_user_id
: NO_HELP
;
6994 if(rc
== 1 || (rc
== 0 && !answer
[0])) {
6995 q_status_message(SM_ORDER
, 3, 4,
6996 _("Send cancelled (User-id must be provided before sending)"));
7001 snprintf(prompt
, sizeof(prompt
), _("Preserve %.*s as \"user-id\" in PINERC"),
7002 sizeof(prompt
)-50, answer
);
7003 prompt
[sizeof(prompt
)-1] = '\0';
7004 if(ps_global
->blank_user_id
7005 && !no_prompt_user_id
7006 && want_to(prompt
, 'y', 'n', NO_HELP
, WT_NORM
) == 'y'){
7007 set_variable(V_USER_ID
, answer
, 1, 1, Main
);
7010 fs_give((void **)&(ps_global
->VAR_USER_ID
));
7011 ps_global
->VAR_USER_ID
= cpystr(answer
);
7015 /* query for personal name */
7016 if(!ps_global
->VAR_PERSONAL_NAME
|| ps_global
->VAR_PERSONAL_NAME
[0]=='\0'
7017 && F_OFF(F_QUELL_PERSONAL_NAME_PROMPT
, ps_global
)){
7019 snprintf(prompt
, sizeof(prompt
), _("Personal name for From address : "));
7020 prompt
[sizeof(prompt
)-1] = '\0';
7024 flags
= OE_APPEND_CURRENT
;
7025 rc
= optionally_enter(answer
,-FOOTER_ROWS(ps_global
),0,
7026 sizeof(answer
),prompt
,NULL
,help
,&flags
);
7031 help
= (help
== NO_HELP
) ? h_sticky_personal_name
: NO_HELP
;
7039 if(rc
== 0 && answer
){ /* save the name */
7040 snprintf(prompt
, sizeof(prompt
), _("Preserve %.*s as \"personal-name\" in PINERC"),
7041 sizeof(prompt
)-50, answer
);
7042 prompt
[sizeof(prompt
)-1] = '\0';
7043 if(ps_global
->blank_personal_name
7044 && want_to(prompt
, 'y', 'n', NO_HELP
, WT_NORM
) == 'y'){
7045 set_variable(V_PERSONAL_NAME
, answer
, 1, 1, Main
);
7048 fs_give((void **)&(ps_global
->VAR_PERSONAL_NAME
));
7049 ps_global
->VAR_PERSONAL_NAME
= cpystr(answer
);
7055 * query for host/domain portion of address, using IMAP
7058 if(ps_global
->blank_user_domain
7059 || ps_global
->maildomain
== ps_global
->localdomain
7060 || ps_global
->maildomain
== ps_global
->hostname
){
7061 if(ps_global
->inbox_name
[0] == '{'){
7063 i
< sizeof(answer
)-1 && ps_global
->inbox_name
[i
+1] != '}'; i
++)
7064 answer
[i
] = ps_global
->inbox_name
[i
+1];
7071 snprintf(prompt
,sizeof(prompt
),_("Host/domain for From address : "));
7072 prompt
[sizeof(prompt
)-1] = '\0';
7076 flags
= OE_APPEND_CURRENT
;
7077 rc
= optionally_enter(answer
,-FOOTER_ROWS(ps_global
),0,
7078 sizeof(answer
),prompt
,NULL
,help
,&flags
);
7083 help
= (help
== NO_HELP
) ? h_sticky_domain
: NO_HELP
;
7091 if(rc
== 1 || (rc
== 0 && !answer
[0])) {
7092 q_status_message(SM_ORDER
, 3, 4,
7093 _("Send cancelled (Host/domain name must be provided before sending)"));
7098 snprintf(prompt
, sizeof(prompt
), _("Preserve %.*s as \"user-domain\" in PINERC"),
7099 sizeof(prompt
)-50, answer
);
7100 prompt
[sizeof(prompt
)-1] = '\0';
7101 if(!ps_global
->userdomain
&& !ps_global
->blank_user_domain
7102 && want_to(prompt
, 'y', 'n', NO_HELP
, WT_NORM
) == 'y'){
7103 set_variable(V_USER_DOMAIN
, answer
, 1, 1, Main
);
7104 fs_give((void **)&(ps_global
->maildomain
)); /* blast old val */
7105 ps_global
->userdomain
= cpystr(answer
);
7106 ps_global
->maildomain
= ps_global
->userdomain
;
7109 fs_give((void **)&(ps_global
->maildomain
));
7110 ps_global
->userdomain
= cpystr(answer
);
7111 ps_global
->maildomain
= ps_global
->userdomain
;
7115 /* check for smtp server */
7116 if(!ps_global
->VAR_SMTP_SERVER
||
7117 !ps_global
->VAR_SMTP_SERVER
[0] ||
7118 !ps_global
->VAR_SMTP_SERVER
[0][0]){
7121 if(ps_global
->inbox_name
[0] == '{'){
7123 i
< sizeof(answer
)-1 && ps_global
->inbox_name
[i
+1] != '}'; i
++)
7124 answer
[i
] = ps_global
->inbox_name
[i
+1];
7131 snprintf(prompt
,sizeof(prompt
),_("SMTP server to forward message : "));
7132 prompt
[sizeof(prompt
)-1] = '\0';
7136 flags
= OE_APPEND_CURRENT
;
7137 rc
= optionally_enter(answer
,-FOOTER_ROWS(ps_global
),0,
7138 sizeof(answer
),prompt
,NULL
,help
,&flags
);
7143 help
= (help
== NO_HELP
) ? h_sticky_smtp
: NO_HELP
;
7151 if(rc
== 1 || (rc
== 0 && answer
[0] == '\0')) {
7152 q_status_message(SM_ORDER
, 3, 4,
7153 _("Send cancelled (SMTP server must be provided before sending)"));
7158 list
= (char **) fs_get(2 * sizeof(char *));
7159 list
[0] = cpystr(answer
);
7161 set_variable_list(V_SMTP_SERVER
, list
, TRUE
, Main
);
7162 fs_give((void *)&list
[0]);
7163 fs_give((void *)list
);
7169 #endif /* defined(DOS) || defined(OS2) */