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
;
608 /*================= Compose new message ===============*/
609 body
= mail_newbody();
610 outgoing
= mail_newenvelope();
613 rfc822_parse_adrlist(&outgoing
->to
, given_to
, ps_global
->maildomain
);
616 * Setup possible role
619 role
= copy_action(role_arg
);
622 /* Setup possible compose role */
623 if(nonempty_patterns(rflags
, &dummy
)){
626 * Msgno = -1 means there is no msg.
627 * This will match roles which have the Compose Use turned
628 * on, and have no patterns set, and match the Current
631 role
= set_role_from_msg(ps_global
, rflags
, -1L, NULL
);
633 if(confirm_role(rflags
, &role
))
634 role
= combine_inherited_role(role
);
635 else{ /* cancel reply */
637 cmd_cancelled("Composition");
644 q_status_message1(SM_ORDER
, 3, 4, _("Composing using role \"%s\""),
648 * set ps_global->hostname to something sensible, if possible,
649 * for purposes of generating a message id
651 hostpart
= cpystr(ps_global
->hostname
);
652 fs_give((void **) &ps_global
->hostname
);
653 if(role
&& role
->from
)
654 ps_global
->hostname
= cpystr(role
->from
->host
? role
->from
->host
: "huh");
655 else if(ps_global
->maildomain
) /* as in generate_from() */
656 ps_global
->hostname
= cpystr(ps_global
->maildomain
);
658 ps_global
->hostname
= cpystr(hostpart
); /* all for nothing */
659 outgoing
->message_id
= generate_message_id(role
);
660 /* undo the changes above */
661 fs_give((void **) &ps_global
->hostname
);
662 ps_global
->hostname
= cpystr(hostpart
);
663 fs_give((void **) &hostpart
);
666 * The type of storage object allocated below is vitally
667 * important. See SIMPLIFYING ASSUMPTION #37
669 if((body
->contents
.text
.data
= (void *) so_get(PicoText
,
670 NULL
, EDIT_ACCESS
)) != NULL
){
674 while((*inc_text_getc
)(&ch
))
675 if(!so_writec(ch
, (STORE_S
*)body
->contents
.text
.data
)){
681 q_status_message(SM_ORDER
| SM_DING
, 3, 4,
682 _("Problem creating space for message text."));
686 if(role
&& role
->template){
689 impl
= 1; /* leave cursor in header if not explicit */
690 filtered
= detoken(role
, NULL
, 0, 0, 0, &redraft_pos
, &impl
);
693 so_puts((STORE_S
*)body
->contents
.text
.data
, filtered
);
695 template_len
= strlen(filtered
);
698 fs_give((void **)&filtered
);
704 if((sig
= detoken(role
, NULL
, 2, 0, 1, &redraft_pos
, &impl
)) != NULL
){
706 redraft_pos
->offset
+= template_len
;
709 so_puts((STORE_S
*)body
->contents
.text
.data
, sig
);
711 fs_give((void **)&sig
);
714 body
->type
= TYPETEXT
;
717 create_message_body(&body
, attach
, 0);
720 ps_global
->prev_screen
= compose_screen
;
721 if(!(fcc_to_free
= fcc
) && !(role
&& role
->fcc
))
722 fcc
= fcc_arg
; /* Didn't pick up fcc, use given */
725 * check whether a build_address-produced fcc is different from
726 * fcc. If same, do nothing, if different, set sticky bit in pine_send.
729 char *tmp_fcc
= NULL
;
732 tmp_fcc
= get_fcc_based_on_to(outgoing
->to
);
733 if(strcmp(fcc
, tmp_fcc
? tmp_fcc
: ""))
734 fcc_is_sticky
++; /* cause sticky bit to get set */
737 else if((tmp_fcc
= get_fcc(NULL
)) != NULL
&&
738 !strcmp(fcc
, tmp_fcc
)){
745 fs_give((void **)&tmp_fcc
);
748 pine_send(outgoing
, &body
, COMPOSE_MAIL_TITLE
, role
, fcc
,
749 reply
, redraft_pos
, lcc
, custom
,
750 (fcc_is_sticky
? PS_STICKY_FCC
: 0) | (to_is_sticky
? PS_STICKY_TO
: 0));
754 fs_give((void **) &reply
->mailbox
);
756 fs_give((void **) &reply
->origmbox
);
758 fs_give((void **) &reply
->prefix
);
759 if(reply
->data
.uid
.msgs
)
760 fs_give((void **) &reply
->data
.uid
.msgs
);
761 fs_give((void **) &reply
);
765 fs_give((void **)&fcc_to_free
);
768 fs_give((void **)&lcc
);
770 mail_free_envelope(&outgoing
);
771 pine_free_body(&body
);
772 free_redraft_pos(&redraft_pos
);
777 /*----------------------------------------------------------------------
778 Args: stream -- This is where we get the postponed messages from
779 We'll expunge and close it here unless it is mail_stream.
781 These are all return values:
797 redraft(MAILSTREAM
**streamp
, ENVELOPE
**outgoing
, struct mail_bodystruct
**body
,
798 char **fcc
, char **lcc
, REPLY_S
**reply
, REDRAFT_POS_S
**redraft_pos
,
799 PINEFIELD
**custom
, ACTION_S
**role
, int flags
)
805 if(!(streamp
&& *streamp
))
811 * If we're manipulating the current folder, don't bother
815 if(REDRAFT_PPND
&flags
)
816 q_status_message(SM_ORDER
| SM_DING
, 3, 5, _("Empty folder! No messages really postponed!"));
818 q_status_message(SM_ORDER
| SM_DING
, 3, 5, _("Empty folder! No messages really interrupted!"));
820 return(redraft_cleanup(streamp
, FALSE
, flags
));
822 else if(stream
== ps_global
->mail_stream
823 && ps_global
->prev_screen
== mail_index_screen
){
825 * Since the user's got this folder already opened and they're
826 * on a selected message, pick that one rather than rebuild
827 * another index screen...
829 cont_msg
= mn_m2raw(ps_global
->msgmap
, mn_get_cur(ps_global
->msgmap
));
831 else if(stream
->nmsgs
> 1L){ /* offer browser ? */
834 if(REDRAFT_PPND
&flags
){ /* set to last message postponed */
835 mn_set_cur(sp_msgmap(stream
),
836 mn_get_revsort(sp_msgmap(stream
))
837 ? 1L : mn_get_total(sp_msgmap(stream
)));
839 else{ /* set to top form letter */
840 mn_set_cur(sp_msgmap(stream
), 1L);
843 clear_index_cache(stream
, 0);
847 ti
= stop_threading_temporarily();
848 rv
= index_lister(ps_global
, NULL
, stream
->mailbox
,
849 stream
, sp_msgmap(stream
));
850 restore_threading(&ti
);
852 cont_msg
= mn_m2raw(sp_msgmap(stream
), mn_get_cur(sp_msgmap(stream
)));
853 if(count_flagged(stream
, F_DEL
)
854 && want_to(INTR_DEL_PMT
, 'n', 0, NO_HELP
, WT_NORM
) == 'n'){
855 if(REDRAFT_PPND
&flags
)
856 q_status_message(SM_ORDER
, 3, 3, _("Undelete messages to remain postponed, and then continue message"));
858 q_status_message(SM_ORDER
, 3, 3, _("Undelete form letters you want to keep, and then continue message"));
866 clear_index_cache(stream
, 0);
869 q_status_message(SM_ORDER
, 0, 3, _("Composition cancelled"));
870 (void) redraft_cleanup(streamp
, FALSE
, flags
);
872 if(!*streamp
&& !ps_global
->mail_stream
){
873 q_status_message2(SM_ORDER
, 3, 7,
874 "No more %.200s, returning to \"%.200s\"",
875 (REDRAFT_PPND
&flags
) ? "postponed messages"
877 ps_global
->inbox_name
);
878 if(ps_global
&& ps_global
->ttyo
){
879 blank_keymenu(ps_global
->ttyo
->screen_rows
- 2, 0);
880 ps_global
->mangled_footer
= 1;
883 do_broach_folder(ps_global
->inbox_name
,
884 ps_global
->context_list
, NULL
, DB_INBOXWOCNTXT
);
886 ps_global
->next_screen
= mail_index_screen
;
889 return(0); /* special case */
893 if((so
= (void *) so_get(PicoText
, NULL
, EDIT_ACCESS
)) != NULL
)
894 return(redraft_work(streamp
, cont_msg
, outgoing
, body
,
895 fcc
, lcc
, reply
, redraft_pos
, custom
,
903 redraft_prompt(char *type
, char *prompt
, int failure
)
905 if(background_posting(FALSE
)){
906 q_status_message1(SM_ORDER
, 0, 3,
907 _("%s folder unavailable while background posting"),
912 return(want_to(prompt
, 'y', 'x', NO_HELP
, WT_NORM
));
916 /* this is for initializing the fixed header elements in pine_send() */
918 prompt::name::help::prwid::maxlen::realaddr::
919 builder::affected_entry::next_affected::selector::key_label::fileedit::
920 display_it::break_on_comma::is_attach::rich_header::only_file_chars::
921 single_space::sticky::dirty::start_here::blank::sticky_special::KS_ODATAVAR
923 static struct headerentry he_template
[]={
924 {"", "X-Auth-Received", NO_HELP
, 10, 0, NULL
,
925 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
926 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KS_NONE
},
927 {"From : ", "From", h_composer_from
, 10, 0, NULL
,
928 build_address
, NULL
, NULL
, addr_book_compose
, "To AddrBk", NULL
, abook_nickname_complete
,
929 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, KS_TOADDRBOOK
},
930 {"Reply-To: ", "Reply To", h_composer_reply_to
, 10, 0, NULL
,
931 build_address
, NULL
, NULL
, addr_book_compose
, "To AddrBk", NULL
, abook_nickname_complete
,
932 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, KS_TOADDRBOOK
},
933 {"To : ", "To", h_composer_to
, 10, 0, NULL
,
934 build_address
, NULL
, NULL
, addr_book_compose
, "To AddrBk", NULL
, abook_nickname_complete
,
935 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, KS_TOADDRBOOK
},
936 {"Cc : ", "Cc", h_composer_cc
, 10, 0, NULL
,
937 build_address
, NULL
, NULL
, addr_book_compose
, "To AddrBk", NULL
, abook_nickname_complete
,
938 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, KS_TOADDRBOOK
},
939 {"Bcc : ", "Bcc", h_composer_bcc
, 10, 0, NULL
,
940 build_address
, NULL
, NULL
, addr_book_compose
, "To AddrBk", NULL
, abook_nickname_complete
,
941 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, KS_TOADDRBOOK
},
942 {"Newsgrps: ", "Newsgroups", h_composer_news
, 10, 0, NULL
,
943 news_build
, NULL
, NULL
, news_group_selector
, "To NwsGrps", NULL
, NULL
,
944 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, KS_NONE
},
945 {"Fcc : ", "Fcc", h_composer_fcc
, 10, 0, NULL
,
946 NULL
, NULL
, NULL
, folders_for_fcc
, "To Fldrs", NULL
, fcc_tab_complete
,
947 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, KS_NONE
},
948 {"Lcc : ", "Lcc", h_composer_lcc
, 10, 0, NULL
,
949 build_addr_lcc
, NULL
, NULL
, addr_book_compose_lcc
,"To AddrBk", NULL
, abook_nickname_complete
,
950 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, KS_NONE
},
951 {"Attchmnt: ", "Attchmnt", h_composer_attachment
, 10, 0, NULL
,
952 NULL
, NULL
, NULL
, NULL
, "To Files", NULL
, NULL
,
953 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, KS_NONE
},
954 {"Subject : ", "Subject", h_composer_subject
, 10, 0, NULL
,
955 valid_subject
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
956 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KS_NONE
},
957 {"", "References", 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 {"", "Date", 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 {"", "In-Reply-To", 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 {"", "Message-ID", 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-Priority", 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 {"", "User-Agent", 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 {"", "To", 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 {"", "X-Post-Error",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-Reply-UID", 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 {"", "X-Reply-Mbox", NO_HELP
, 10, 0, NULL
,
985 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
986 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KS_NONE
},
987 {"", "X-SMTP-Server", NO_HELP
, 10, 0, NULL
,
988 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
989 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KS_NONE
},
990 {"", "X-Cursor-Pos", NO_HELP
, 10, 0, NULL
,
991 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
992 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KS_NONE
},
993 {"", "X-Our-ReplyTo", NO_HELP
, 10, 0, NULL
,
994 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
995 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KS_NONE
},
996 {"", OUR_HDRS_LIST
, NO_HELP
, 10, 0, NULL
,
997 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
998 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KS_NONE
},
999 {"", "X-Auth-Received", NO_HELP
, 10, 0, NULL
,
1000 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1001 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KS_NONE
},
1002 #if !(defined(DOS) || defined(OS2)) || defined(NOAUTH)
1003 {"", "Sender", NO_HELP
, 10, 0, NULL
,
1004 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1005 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KS_NONE
}
1010 static struct headerentry he_custom_addr_templ
={
1011 NULL
, NULL
, h_composer_custom_addr
,10, 0, NULL
,
1012 build_address
, NULL
, NULL
, addr_book_compose
, "To AddrBk", NULL
, abook_nickname_complete
,
1013 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, KS_TOADDRBOOK
};
1015 static struct headerentry he_custom_free_templ
={
1016 NULL
, NULL
, h_composer_custom_free
,10, 0, NULL
,
1017 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1018 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, KS_NONE
};
1021 /*----------------------------------------------------------------------
1022 Get addressee for message, then post message
1024 Args: outgoing -- Partially formatted outgoing ENVELOPE
1025 body -- Body of outgoing message
1026 prmpt_who -- Optional prompt for optionally_enter call
1027 prmpt_cnf -- Optional prompt for confirmation call
1028 used_tobufval -- The string that the to was eventually set equal to.
1029 This gets passed back if non-NULL on entry.
1030 flagsarg -- SS_PROMPTFORTO - Allow user to change recipient
1031 SS_NULLRP - Use null return-path so we'll send an
1034 Result: message "To: " field is provided and message is sent or cancelled.
1043 subject passed in, NOT edited but maybe canonized here
1044 to possibly passed in, edited and canonized here
1050 Can only deal with message bodies that are either TYPETEXT or TYPEMULTIPART
1051 with the first part TYPETEXT! All newlines in the text here also end with
1054 Returns 0 on success, -1 on failure.
1057 pine_simple_send(ENVELOPE
*outgoing
, /* envelope for outgoing message */
1058 struct mail_bodystruct
**body
,
1062 char **used_tobufval
,
1065 char **tobufp
, *p
, tmp
[MAILTMPLEN
];
1067 int done
= 0, retval
= 0, x
;
1068 int lastrc
, rc
= 0, ku
, i
, resize_len
, result
, fcc_result
;
1071 static HISTORY_S
*history
= NULL
;
1075 ACTION_S
*role
= rolep
? *rolep
: NULL
;
1078 dprint((1,"\n === simple send called === \n"));
1080 memset(&ba_fcc
, 0, sizeof(BUILDER_ARG
));
1082 init_hist(&history
, HISTSIZE
);
1084 header
= pine_simple_send_header(outgoing
, &ba_fcc
.tptr
, &tobufp
);
1086 /*----- Fill in a few general parts of the envelope ----*/
1087 if(!outgoing
->date
){
1088 if(F_ON(F_QUELL_TIMEZONE
, ps_global
))
1089 mail_parameters(NULL
, SET_DISABLE822TZTEXT
, (void *) TRUE
);
1091 rfc822_date(tmp_20k_buf
); /* format and copy new date */
1092 if(F_ON(F_QUELL_TIMEZONE
, ps_global
))
1093 mail_parameters(NULL
, SET_DISABLE822TZTEXT
, (void *) FALSE
);
1095 outgoing
->date
= (unsigned char *) cpystr(tmp_20k_buf
);
1098 if(!outgoing
->from
){
1099 if(role
&& role
->from
){
1100 if(ps_global
->never_allow_changing_from
)
1101 q_status_message(SM_ORDER
, 3, 3, _("Site policy doesn't allow changing From address so role's From has no effect"));
1103 outgoing
->from
= copyaddrlist(role
->from
);
1106 outgoing
->from
= generate_from();
1109 if(!(flagsarg
& SS_NULLRP
))
1110 outgoing
->return_path
= rfc822_cpy_adr(outgoing
->from
);
1112 ekey
[i
= 0].ch
= ctrl('T');
1114 ekey
[i
].name
= "^T";
1115 ekey
[i
++].label
= N_("To AddrBk");
1117 if(F_ON(F_ENABLE_TAB_COMPLETE
,ps_global
)){
1118 ekey
[i
].ch
= ctrl('I');
1120 ekey
[i
].name
= "TAB";
1121 ekey
[i
++].label
= N_("Complete");
1124 if(nonempty_patterns(ROLE_DO_ROLES
, &pstate
) && first_pattern(&pstate
)){
1125 ekey
[i
].ch
= ctrl('R');
1127 ekey
[i
].name
= "^R";
1128 ekey
[i
++].label
= "Set Role";
1131 ekey
[i
].ch
= KEY_UP
;
1135 ekey
[i
++].label
= "";
1137 ekey
[i
].ch
= KEY_DOWN
;
1140 ekey
[i
++].label
= "";
1144 if(outgoing
->remail
== NULL
)
1145 strcpy(tmp
, _("FORWARD (as e-mail) to : "));
1147 /*----------------------------------------------------------------------
1148 Loop editing the "To: " field until everything goes well
1155 if(outgoing
->message_id
)
1156 fs_give((void **) &outgoing
->message_id
);
1158 outgoing
->message_id
= generate_message_id(role
);
1160 if(outgoing
->remail
){
1162 snprintf(tmp
, sizeof(tmp
), _("BOUNCE (redirect) message using role \"%s\" to : "), role
->nick
);
1164 strncpy(tmp
, _("BOUNCE (redirect) message to : "), sizeof(tmp
));
1165 tmp
[sizeof(tmp
)-1] = '\0';
1170 outgoing2strings(header
, *body
, &messagebuf
, NULL
, 1);
1174 if(flagsarg
& SS_PROMPTFORTO
){
1176 *tobufp
= cpystr("");
1178 resize_len
= MAX(MAXPATH
, strlen(*tobufp
));
1179 fs_resize((void **) tobufp
, resize_len
+1);
1181 if(items_in_hist(history
) > 0){
1182 ekey
[ku
].name
= HISTORY_UP_KEYNAME
;
1183 ekey
[ku
].label
= HISTORY_KEYLABEL
;
1184 ekey
[ku
+1].name
= HISTORY_DOWN_KEYNAME
;
1185 ekey
[ku
+1].label
= HISTORY_KEYLABEL
;
1189 ekey
[ku
].label
= "";
1190 ekey
[ku
+1].name
= "";
1191 ekey
[ku
+1].label
= "";
1194 flags
= OE_APPEND_CURRENT
;
1196 rc
= optionally_enter(*tobufp
, -FOOTER_ROWS(ps_global
),
1201 ekey
, help
, &flags
);
1208 q_status_message(SM_ORDER
| SM_DING
, 3, 4,
1209 "Internal problem encountered");
1214 case 15 : /* set a role */
1215 {void (*prev_screen
)(struct pine
*) = NULL
, (*redraw
)(void) = NULL
;
1217 redraw
= ps_global
->redrawer
;
1218 ps_global
->redrawer
= NULL
;
1219 prev_screen
= ps_global
->prev_screen
;
1221 ps_global
->next_screen
= SCREEN_FUN_NULL
;
1223 if(role_select_screen(ps_global
, &role
,
1224 outgoing
->remail
? MC_BOUNCE
: MC_FORWARD
) < 0)
1225 cmd_cancelled(_("Set Role"));
1228 role
= combine_inherited_role(role
);
1230 role
= (ACTION_S
*) fs_get(sizeof(*role
));
1231 memset((void *) role
, 0, sizeof(*role
));
1232 role
->nick
= cpystr("Default Role");
1239 ps_global
->next_screen
= prev_screen
;
1240 ps_global
->redrawer
= redraw
;
1241 ps_global
->mangled_screen
= 1;
1243 if(role
&& role
->from
&& !ps_global
->never_allow_changing_from
){
1244 mail_free_address (&outgoing
->from
);
1245 outgoing
->from
= copyaddrlist(role
->from
);
1246 if(!(flagsarg
& SS_NULLRP
)){
1247 fs_give((void **) &outgoing
->return_path
);
1248 outgoing
->return_path
= rfc822_cpy_adr(outgoing
->from
);
1251 if(rolep
) *rolep
= role
;
1256 if((p
= get_prev_hist(history
, *tobufp
, 0, NULL
)) != NULL
){
1257 strncpy(*tobufp
, p
, resize_len
);
1258 (*tobufp
)[resize_len
-1] = '\0';
1266 if((p
= get_next_hist(history
, *tobufp
, 0, NULL
)) != NULL
){
1267 strncpy(*tobufp
, p
, resize_len
);
1268 (*tobufp
)[resize_len
-1] = '\0';
1277 {void (*redraw
) (void) = ps_global
->redrawer
;
1278 char *returned_addr
= NULL
;
1282 int got_something
= 0;
1284 push_titlebar_state();
1285 returned_addr
= addr_book_bounce();
1288 * Just make it look like user typed this list in.
1292 if((l
=resize_len
) < (len
= strlen(returned_addr
)) + 1){
1294 fs_resize((void **) tobufp
, (size_t) (l
+1));
1297 strncpy(*tobufp
, returned_addr
, l
);
1298 (*tobufp
)[l
] = '\0';
1299 fs_give((void **)&returned_addr
);
1303 pop_titlebar_state();
1305 if((ps_global
->redrawer
= redraw
) != NULL
) /* reset old value, and test */
1306 (*ps_global
->redrawer
)();
1312 if(*tobufp
&& **tobufp
!= '\0'){
1313 char *errbuf
, *addr
;
1316 save_hist(history
, *tobufp
, 0, NULL
);
1321 * If role has an fcc, use it instead of what build_address
1324 if(role
&& role
->fcc
){
1326 fs_give((void **) &ba_fcc
.tptr
);
1328 ba_fcc
.tptr
= cpystr(role
->fcc
);
1331 if(build_address(*tobufp
, &addr
, &errbuf
,
1332 (role
&& role
->fcc
) ? NULL
: &ba_fcc
, NULL
) >= 0){
1336 fs_give((void **)&errbuf
);
1338 if((l
=strlen(*tobufp
)) < (tolen
= strlen(addr
)) + 1){
1340 fs_resize((void **) tobufp
, (size_t) (l
+1));
1343 strncpy(*tobufp
, addr
, l
);
1344 (*tobufp
)[l
] = '\0';
1346 *used_tobufval
= cpystr(addr
);
1348 /* confirm address */
1349 if(flagsarg
& SS_PROMPTFORTO
){
1350 char dsn_string
[30];
1351 int dsn_label
= 0, dsn_show
, i
;
1352 int verbose_label
= 0;
1355 strings2outgoing(header
, body
, NULL
, 0);
1357 if((flagsarg
& SS_PROMPTFORTO
)
1358 && ((x
= check_addresses(header
)) == CA_BAD
1359 || (x
== CA_EMPTY
&& F_OFF(F_FCC_ON_BOUNCE
,
1361 /*--- Addresses didn't check out---*/
1368 opts
[i
++].label
= N_("Yes");
1373 opts
[i
++].label
= N_("No");
1375 call_mailer_flags
&= ~CM_VERBOSE
; /* clear verbose */
1376 if(F_ON(F_VERBOSE_POST
, ps_global
)){
1377 /* setup keymenu slot to toggle verbose mode */
1378 opts
[i
].ch
= ctrl('W');
1380 opts
[i
].name
= "^W";
1381 verbose_label
= i
++;
1382 if(F_ON(F_DSN
, ps_global
)){
1386 opts
[i
++].label
= "";
1390 /* clear DSN flags */
1391 call_mailer_flags
&= ~(CM_DSN_NEVER
| CM_DSN_DELAY
| CM_DSN_SUCCESS
| CM_DSN_FULL
);
1392 if(F_ON(F_DSN
, ps_global
)){
1393 /* setup keymenu slots to toggle dsn bits */
1397 opts
[i
].label
= "DSNOpts";
1402 opts
[i
++].label
= "";
1406 opts
[i
++].label
= "";
1410 opts
[i
++].label
= "";
1418 dsn_show
= (call_mailer_flags
& CM_DSN_SHOW
);
1419 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
,
1420 "%s%s%s%s%s%sto \"%s\" ? ",
1421 prmpt_cnf
? prmpt_cnf
: "Send message ",
1422 ((call_mailer_flags
& CM_VERBOSE
)
1425 (call_mailer_flags
& CM_VERBOSE
)
1426 ? "in verbose mode" : "",
1427 (dsn_show
&& (call_mailer_flags
& CM_VERBOSE
))
1429 (dsn_show
) ? dsn_string
: "",
1430 ((call_mailer_flags
& CM_VERBOSE
) || dsn_show
)
1434 : (F_ON(F_FCC_ON_BOUNCE
, ps_global
)
1435 && ba_fcc
.tptr
&& ba_fcc
.tptr
[0])
1438 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
1440 if((strlen(tmp_20k_buf
) >
1441 ps_global
->ttyo
->screen_cols
- 2) &&
1442 ps_global
->ttyo
->screen_cols
>= 7)
1443 strncpy(tmp_20k_buf
+ps_global
->ttyo
->screen_cols
-7,
1444 "...? ", SIZEOF_20KBUF
-ps_global
->ttyo
->screen_cols
-7);
1446 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
1449 opts
[verbose_label
].label
=
1450 /* TRANSLATORS: several possible key labels follow */
1451 (call_mailer_flags
& CM_VERBOSE
) ? N_("Normal") : N_("Verbose");
1453 if(F_ON(F_DSN
, ps_global
)){
1454 if(call_mailer_flags
& CM_DSN_SHOW
){
1455 opts
[dsn_label
].label
=
1456 (call_mailer_flags
& CM_DSN_DELAY
)
1457 ? N_("NoDelay") : N_("Delay");
1458 opts
[dsn_label
+1].ch
= 's';
1459 opts
[dsn_label
+1].label
=
1460 (call_mailer_flags
& CM_DSN_SUCCESS
)
1461 ? N_("NoSuccess") : N_("Success");
1462 opts
[dsn_label
+2].ch
= 'x';
1463 opts
[dsn_label
+2].label
=
1464 (call_mailer_flags
& CM_DSN_NEVER
)
1465 ? N_("ErrRets") : N_("NoErrRets");
1466 opts
[dsn_label
+3].ch
= 'h';
1467 opts
[dsn_label
+3].label
=
1468 (call_mailer_flags
& CM_DSN_FULL
)
1469 ? N_("RetHdrs") : N_("RetFull");
1473 rv
= radio_buttons(tmp_20k_buf
,
1474 -FOOTER_ROWS(ps_global
), opts
,
1475 'y', 'z', NO_HELP
, RB_NORM
);
1476 if(rv
== 'y'){ /* user ACCEPTS! */
1480 else if(rv
== 'n'){ /* Declined! */
1483 else if(rv
== 'z'){ /* Cancelled! */
1486 else if(rv
== 12){ /* flip verbose bit */
1487 if(call_mailer_flags
& CM_VERBOSE
)
1488 call_mailer_flags
&= ~CM_VERBOSE
;
1490 call_mailer_flags
|= CM_VERBOSE
;
1492 else if(call_mailer_flags
& CM_DSN_SHOW
){
1493 if(rv
== 's'){ /* flip success bit */
1494 call_mailer_flags
^= CM_DSN_SUCCESS
;
1495 /* turn off related bits */
1496 if(call_mailer_flags
& CM_DSN_SUCCESS
)
1497 call_mailer_flags
&= ~(CM_DSN_NEVER
);
1499 else if(rv
== 'd'){ /* flip delay bit */
1500 call_mailer_flags
^= CM_DSN_DELAY
;
1501 /* turn off related bits */
1502 if(call_mailer_flags
& CM_DSN_DELAY
)
1503 call_mailer_flags
&= ~(CM_DSN_NEVER
);
1505 else if(rv
== 'x'){ /* flip never bit */
1506 call_mailer_flags
^= CM_DSN_NEVER
;
1507 /* turn off related bits */
1508 if(call_mailer_flags
& CM_DSN_NEVER
)
1509 call_mailer_flags
&= ~(CM_DSN_SUCCESS
| CM_DSN_DELAY
);
1511 else if(rv
== 'h'){ /* flip full bit */
1512 call_mailer_flags
^= CM_DSN_FULL
;
1515 else if(rv
== 'd'){ /* show dsn options */
1516 call_mailer_flags
|= (CM_DSN_SHOW
| CM_DSN_SUCCESS
| CM_DSN_DELAY
| CM_DSN_FULL
);
1519 snprintf(dsn_string
, sizeof(dsn_string
), _("DSN requested[%s%s%s%s]"),
1520 (call_mailer_flags
& CM_DSN_NEVER
)
1522 (call_mailer_flags
& CM_DSN_DELAY
)
1524 (call_mailer_flags
& CM_DSN_SUCCESS
)
1526 (call_mailer_flags
& CM_DSN_NEVER
)
1528 : (call_mailer_flags
& CM_DSN_FULL
) ? "-Full"
1530 dsn_string
[sizeof(dsn_string
)-1] = '\0';
1535 fs_give((void **)&addr
);
1537 if(!(flagsarg
& SS_PROMPTFORTO
) || sendit
){
1539 CONTEXT_S
*fcc_cntxt
= NULL
;
1541 if(F_ON(F_FCC_ON_BOUNCE
, ps_global
)){
1543 fcc
= cpystr(ba_fcc
.tptr
);
1548 * If special name "inbox" then replace it with the
1551 if(ps_global
->VAR_INBOX_PATH
1552 && strucmp(fcc
, ps_global
->inbox_name
) == 0){
1555 replace_fcc
= cpystr(ps_global
->VAR_INBOX_PATH
);
1556 fs_give((void **) &fcc
);
1561 /*---- Check out fcc -----*/
1563 (void) commence_fcc(fcc
, &fcc_cntxt
, FALSE
);
1565 dprint((4,"can't open fcc, cont\n"));
1566 if(!(flagsarg
& SS_PROMPTFORTO
)){
1568 fs_give((void **)&fcc
);
1576 so_truncate(lmc
.so
, fcc_size_guess(*body
) + 2048);
1581 if(!(outgoing
->to
|| outgoing
->cc
|| outgoing
->bcc
1583 q_status_message(SM_ORDER
, 3, 5, _("No recipients specified!"));
1587 if(outgoing
->to
|| outgoing
->cc
|| outgoing
->bcc
){
1588 char **alt_smtp
= NULL
;
1590 if(role
&& role
->smtp
){
1591 if(ps_global
->FIX_SMTP_SERVER
1592 && ps_global
->FIX_SMTP_SERVER
[0])
1593 q_status_message(SM_ORDER
| SM_DING
, 5, 5, _("Use of a role-defined smtp-server is administratively prohibited"));
1595 alt_smtp
= role
->smtp
;
1598 result
= call_mailer(header
, *body
, alt_smtp
,
1600 call_mailer_file_result
,
1602 mark_address_failure_for_pico(header
);
1607 if(result
== 1 && !lmc
.so
)
1608 q_status_message(SM_ORDER
, 0, 3, _("Message sent"));
1610 /*----- Was there an fcc involved? -----*/
1614 && pine_rfc822_output(header
, *body
, NULL
, NULL
))){
1617 strncpy(label
, "Fcc", sizeof(label
));
1618 label
[sizeof(label
)-1] = '\0';
1619 if(strcmp(fcc
, ps_global
->VAR_DEFAULT_FCC
)){
1620 snprintf(label
+ 3, sizeof(label
)-3, " to %s", fcc
);
1621 label
[sizeof(label
)-1] = '\0';
1624 /* Now actually copy to fcc folder and close */
1626 write_fcc(fcc
, fcc_cntxt
, lmc
.so
, NULL
,
1628 F_ON(F_MARK_FCC_SEEN
, ps_global
)
1631 else if(result
== 0){
1632 q_status_message(SM_ORDER
,3,5,
1633 _("Fcc Failed!. No message saved."));
1635 dprint((1, "explicit fcc write failed!\n"));
1642 dprint((1, "Bounce failed\n"));
1643 if(!(flagsarg
& SS_PROMPTFORTO
))
1648 else if(result
== 1){
1650 q_status_message(SM_ORDER
, 0, 3,
1653 int avail
= ps_global
->ttyo
->screen_cols
-2;
1655 char *part1
= "Message sent and ";
1656 char *part2
= fcc_result
? "" : "NOT ";
1657 char *part3
= "copied to ";
1658 fcclen
= strlen(fcc
);
1660 need
= 2 + strlen(part1
) + strlen(part2
) +
1661 strlen(part3
) + fcclen
;
1663 if(need
> avail
&& fcclen
> 6)
1664 fcclen
-= MIN(fcclen
-6, need
-avail
);
1666 q_status_message4(SM_ORDER
, 0, 3,
1668 part1
, part2
, part3
,
1670 (char *)tmp_20k_buf
,
1672 fcclen
, FrontDots
));
1677 fs_give((void **)&fcc
);
1680 q_status_message(SM_ORDER
, 0, 3, _("Send cancelled"));
1685 q_status_message1(SM_ORDER
| SM_DING
, 3, 5,
1686 _("Error in address: %s"), errbuf
);
1688 fs_give((void **)&errbuf
);
1690 if(!(flagsarg
& SS_PROMPTFORTO
))
1698 q_status_message(SM_ORDER
| SM_DING
, 3, 5,
1699 _("No addressee! No e-mail sent."));
1708 q_status_message(SM_ORDER
, 0, 3, _("Send cancelled"));
1714 help
= (help
== NO_HELP
)
1715 ? (outgoing
->remail
== NULL
1723 char *new_nickname
= NULL
;
1727 ambiguity
= abook_nickname_complete(*tobufp
, &new_nickname
,
1728 (lastrc
==rc
&& !(flags
& OE_USER_MODIFIED
)), ANC_AFTERCOMMA
);
1731 if((l
=strlen(new_nickname
)) > resize_len
){
1733 fs_resize((void **) tobufp
, resize_len
+1);
1736 strncpy(*tobufp
, new_nickname
, l
);
1737 (*tobufp
)[l
] = '\0';
1740 fs_give((void **) &new_nickname
);
1749 case 4: /* can't suspend */
1757 fs_give((void **)&ba_fcc
.tptr
);
1759 pine_free_env(&header
);
1766 * pine_simple_send_header - generate header suitable for simple_sending
1769 pine_simple_send_header(ENVELOPE
*outgoing
, char **fccp
, char ***tobufpp
)
1773 static struct headerentry he_dummy
;
1775 header
= pine_new_env(outgoing
, fccp
, tobufpp
, NULL
);
1777 /* assign he_dummy to "To:" field "he" for strings2outgoing */
1778 for(pf
= header
->local
; pf
&& pf
->name
; pf
= pf
->next
)
1779 if(pf
->type
== Address
&& !strucmp(pf
->name
, "to")){
1780 memset((void *) &he_dummy
, 0, sizeof(he_dummy
));
1781 pf
->extdata
= (void *) &he_dummy
;
1791 /*----------------------------------------------------------------------
1792 Prepare data structures for pico, call pico, then post message
1794 Args: outgoing -- Partially formatted outgoing ENVELOPE
1795 body -- Body of outgoing message
1796 editor_title -- Title for anchor line in composer
1797 fcc_arg -- The file carbon copy field
1798 reply -- Struct describing set of msgs being replied-to
1800 custom -- custom header list.
1803 Result: message is edited, then postponed, cancelled or sent.
1812 subject passed in, edited and cannonized here
1813 to possibly passed in, edited and cannonized here
1814 cc possibly passed in, edited and cannonized here
1815 bcc edited and cannonized here
1816 in_reply_to generated in reply() and passed in
1819 Storage for these fields comes from anywhere outside. It is remalloced
1820 here so the composer can realloc them if needed. The copies here are also
1823 Can only deal with message bodies that are either TYPETEXT or TYPEMULTIPART
1824 with the first part TYPETEXT! All newlines in the text here also end with
1827 There's a further assumption that the text in the TYPETEXT part is
1828 stored in a storage object (see filter.c).
1831 pine_send(ENVELOPE
*outgoing
, struct mail_bodystruct
**body
,
1832 char *editor_title
, ACTION_S
*role
, char *fcc_arg
,
1833 REPLY_S
*reply
, REDRAFT_POS_S
*redraft_pos
, char *lcc_arg
,
1834 PINEFIELD
*custom
, int flags
)
1836 int i
, fixed_cnt
, total_cnt
, index
,
1837 editor_result
= 0, body_start
= 0, use_news_order
= 0;
1838 char *p
, *addr
, *fcc
, *fcc_to_free
= NULL
;
1839 char *start_here_name
= NULL
;
1840 char *suggested_nntp_server
= NULL
;
1842 struct headerentry
*he
, *headents
, *he_to
, *he_fcc
, *he_news
= NULL
, *he_lcc
= NULL
,
1844 PINEFIELD
*pfields
, *pf
, *pf_nobody
= NULL
, *pf_to
= NULL
,
1845 *pf_smtp_server
, *pf_nntp_server
,
1846 *pf_fcc
= NULL
, *pf_err
, *pf_uid
, *pf_mbox
, *pf_curpos
,
1847 *pf_ourrep
, *pf_ourhdrs
, **sending_order
;
1849 ADDRESS
*lcc_addr
= NULL
;
1850 ADDRESS
*nobody_addr
= NULL
;
1851 BODY_PARTICULARS_S
*bp
;
1852 STORE_S
*orig_so
= NULL
;
1853 PICO pbuf1
, *save_previous_pbuf
;
1855 REDRAFT_POS_S
*local_redraft_pos
= NULL
;
1857 dprint((1,"\n=== send called ===\n"));
1859 save_previous_pbuf
= pbf
;
1861 standard_picobuf_setup(pbf
);
1864 * Cancel any pending initial commands since pico uses a different
1865 * input routine. If we didn't cancel them, they would happen after
1866 * we returned from the editor, which would be confusing.
1868 if(ps_global
->in_init_seq
){
1869 ps_global
->in_init_seq
= 0;
1870 ps_global
->save_in_init_seq
= 0;
1872 if(ps_global
->initial_cmds
){
1873 if(ps_global
->free_initial_cmds
)
1874 fs_give((void **)&(ps_global
->free_initial_cmds
));
1876 ps_global
->initial_cmds
= 0;
1879 F_SET(F_USE_FK
,ps_global
,ps_global
->orig_use_fkeys
);
1882 #if defined(DOS) || defined(OS2)
1883 if(!dos_valid_from()){
1884 pbf
= save_previous_pbuf
;
1890 pbf
->upload
= (ps_global
->VAR_UPLOAD_CMD
1891 && ps_global
->VAR_UPLOAD_CMD
[0])
1892 ? upload_msg_to_pico
: NULL
;
1895 pbf
->msgntext
= message_format_for_pico
;
1896 pbf
->mimetype
= mime_type_for_pico
;
1897 pbf
->exittest
= send_exit_for_pico
;
1898 pbf
->user_says_noflow
= dont_flow_this_time
;
1899 pbf
->newthread
= new_thread_on_blank_subject
;
1900 ps_global
->newthread
= 0; /* reset this value */
1901 if(F_OFF(F_CANCEL_CONFIRM
, ps_global
))
1902 pbf
->canceltest
= cancel_for_pico
;
1904 pbf
->dict
= (ps_global
->VAR_DICTIONARY
1905 && ps_global
->VAR_DICTIONARY
[0]
1906 && ps_global
->VAR_DICTIONARY
[0][0])
1907 ? ps_global
->VAR_DICTIONARY
: NULL
;
1908 pbf
->chosen_dict
= -1; /* not chosen yet */
1909 #endif /* _WINDOWS */
1910 pbf
->alt_ed
= (ps_global
->VAR_EDITOR
&& ps_global
->VAR_EDITOR
[0] &&
1911 ps_global
->VAR_EDITOR
[0][0])
1912 ? ps_global
->VAR_EDITOR
: NULL
;
1913 pbf
->alt_spell
= (ps_global
->VAR_SPELLER
&& ps_global
->VAR_SPELLER
[0])
1914 ? ps_global
->VAR_SPELLER
: NULL
;
1915 pbf
->always_spell_check
= F_ON(F_ALWAYS_SPELL_CHECK
, ps_global
);
1916 pbf
->quote_str
= reply
&& reply
->prefix
? reply
->prefix
: "> ";
1917 /* We actually want to set this only if message we're sending is flowed */
1918 pbf
->strip_ws_before_send
= F_ON(F_STRIP_WS_BEFORE_SEND
, ps_global
);
1919 pbf
->allow_flowed_text
= (F_OFF(F_QUELL_FLOWED_TEXT
, ps_global
)
1920 && F_OFF(F_STRIP_WS_BEFORE_SEND
, ps_global
)
1921 && (strcmp(pbf
->quote_str
, "> ") == 0
1922 || strcmp(pbf
->quote_str
, ">") == 0));
1923 pbf
->edit_offset
= 0;
1924 title
= cpystr(set_titlebar(editor_title
,
1925 ps_global
->mail_stream
,
1926 ps_global
->context_current
,
1927 ps_global
->cur_folder
,ps_global
->msgmap
,
1928 0, FolderName
, 0, 0, NULL
));
1929 pbf
->pine_anchor
= title
;
1931 #if defined(DOS) || defined(OS2)
1932 if(!pbf
->oper_dir
&& ps_global
->VAR_FILE_DIR
){
1933 pbf
->oper_dir
= ps_global
->VAR_FILE_DIR
;
1937 if(redraft_pos
&& editor_title
&& !strcmp(editor_title
, COMPOSE_MAIL_TITLE
))
1938 pbf
->pine_flags
|= P_CHKPTNOW
;
1940 /* NOTE: initial cursor position set below */
1942 dprint((9, "flags: %x\n", pbf
->pine_flags
));
1945 * When user runs compose and the current folder is a newsgroup,
1946 * offer to post to the current newsgroup.
1948 if(!(outgoing
->to
|| (outgoing
->newsgroups
&& *outgoing
->newsgroups
))
1949 && IS_NEWS(ps_global
->mail_stream
)){
1950 char prompt
[200], news_group
[MAILTMPLEN
];
1952 pine_send_newsgroup_name(ps_global
->mail_stream
->mailbox
, news_group
,
1953 sizeof(news_group
));
1956 * Replies don't get this far because To or Newsgroups will already
1957 * be filled in. So must be either ordinary compose or forward.
1958 * Forward sets subject, so use that to tell the difference.
1960 if(news_group
[0] && !outgoing
->subject
){
1963 char *errmsg
= NULL
;
1964 BUILDER_ARG
*fcc_build
= NULL
;
1966 if(F_OFF(F_COMPOSE_TO_NEWSGRP
,ps_global
)){
1967 snprintf(prompt
, sizeof(prompt
),
1968 _("Post to current newsgroup (%s)"), news_group
);
1969 prompt
[sizeof(prompt
)-1] = '\0';
1970 ch
= want_to(prompt
, 'y', 'x', NO_HELP
, WT_NORM
);
1975 if(outgoing
->newsgroups
)
1976 fs_give((void **)&outgoing
->newsgroups
);
1978 if(!fcc_arg
&& !(role
&& role
->fcc
)){
1979 fcc_build
= (BUILDER_ARG
*)fs_get(sizeof(BUILDER_ARG
));
1980 memset((void *)fcc_build
, 0, sizeof(BUILDER_ARG
));
1981 fcc_build
->tptr
= fcc_to_free
;
1984 ret_val
= news_build(news_group
, &outgoing
->newsgroups
,
1985 &errmsg
, fcc_build
, NULL
);
1988 if(outgoing
->newsgroups
)
1989 fs_give((void **)&outgoing
->newsgroups
);
1991 outgoing
->newsgroups
= cpystr(news_group
);
1994 if(!fcc_arg
&& !(role
&& role
->fcc
)){
1995 fcc_arg
= fcc_to_free
= fcc_build
->tptr
;
1996 fs_give((void **)&fcc_build
);
2001 q_status_message(SM_ORDER
, 3, 3, errmsg
);
2002 display_message(NO_OP_COMMAND
);
2005 fs_give((void **)&errmsg
);
2011 q_status_message(SM_ORDER
, 0, 3, _("Message cancelled"));
2012 dprint((4, "=== send: cancelled\n"));
2013 pbf
= save_previous_pbuf
;
2024 if(F_ON(F_PREDICT_NNTP_SERVER
, ps_global
)
2025 && outgoing
->newsgroups
&& *outgoing
->newsgroups
2026 && IS_NEWS(ps_global
->mail_stream
)){
2029 if(mail_valid_net_parse(ps_global
->mail_stream
->original_mailbox
,
2031 if(!strucmp(news_mb
.service
, "nntp")){
2032 if(*ps_global
->mail_stream
->original_mailbox
== '{'){
2033 char *svcp
= NULL
, *psvcp
;
2035 suggested_nntp_server
=
2036 cpystr(ps_global
->mail_stream
->original_mailbox
+ 1);
2037 if((p
= strindex(suggested_nntp_server
, '}')) != NULL
)
2039 for(p
= strindex(suggested_nntp_server
, '/'); p
&& *p
;
2040 p
= strindex(p
, '/')){
2041 /* take out /nntp, which gets added in nntp_open */
2042 if(!struncmp(p
, "/nntp", 5))
2044 else if(!struncmp(p
, "/service=nntp", 13))
2046 else if(!struncmp(p
, "/service=\"nntp\"", 15))
2053 else if(*svcp
== '/' || *svcp
== ':'){
2054 for(psvcp
= p
; *svcp
; svcp
++, psvcp
++)
2063 suggested_nntp_server
= cpystr(news_mb
.orighost
);
2068 * If we don't already have custom headers set and the role has custom
2069 * headers, then incorporate those custom headers into "custom".
2072 PINEFIELD
*dflthdrs
= NULL
, *rolehdrs
= NULL
;
2074 dflthdrs
= parse_custom_hdrs(ps_global
->VAR_CUSTOM_HDRS
, UseAsDef
);
2076 * If we allow the Combine argument here, we're saying that we want to
2077 * combine the values from the envelope and the role for the fields To,
2078 * Cc, Bcc, and Newsgroups. For example, if we are replying to a message
2079 * we'll have a To in the envelope because we're replying. If our role also
2080 * has a To action, then Combine would combine those two and offer both
2081 * to the user. We've decided against doing this. Instead, we always use
2082 * Replace, and the role's header value replaces the value from the
2083 * envelope. It might also make sense in some cases to do the opposite,
2084 * which would be treating the role headers as defaults, just like
2087 #ifdef WANT_TO_COMBINE_ADDRESSES
2088 if(role
&& role
->cstm
)
2089 rolehdrs
= parse_custom_hdrs(role
->cstm
, Combine
);
2091 if(role
&& role
->cstm
)
2092 rolehdrs
= parse_custom_hdrs(role
->cstm
, Replace
);
2096 custom
= combine_custom_headers(dflthdrs
, rolehdrs
);
2098 free_prompts(dflthdrs
);
2099 free_customs(dflthdrs
);
2103 free_prompts(rolehdrs
);
2104 free_customs(rolehdrs
);
2111 g_rolenick
= role
? role
->nick
: NULL
;
2113 /* how many fixed fields are there? */
2114 for(fixed_cnt
= 0; pf_template
&& pf_template
[fixed_cnt
].name
; fixed_cnt
++)
2117 total_cnt
= fixed_cnt
+ count_custom_hdrs_pf(custom
,1);
2119 /* the fixed part of the PINEFIELDs */
2120 i
= fixed_cnt
* sizeof(PINEFIELD
);
2121 pfields
= (PINEFIELD
*)fs_get((size_t) i
);
2122 memset(pfields
, 0, (size_t) i
);
2124 /* temporary headerentry array for pico */
2125 i
= (total_cnt
+ 1) * sizeof(struct headerentry
);
2126 headents
= (struct headerentry
*)fs_get((size_t) i
);
2127 memset(headents
, 0, (size_t) i
);
2129 i
= total_cnt
* sizeof(PINEFIELD
*);
2130 sending_order
= (PINEFIELD
**)fs_get((size_t) i
);
2131 memset(sending_order
, 0, (size_t) i
);
2133 pbf
->headents
= headents
;
2134 header
.env
= outgoing
;
2135 header
.local
= pfields
;
2136 header
.sending_order
= sending_order
;
2138 /* custom part of PINEFIELDs */
2139 header
.custom
= custom
;
2145 * For Address types, pf->addr points to an ADDRESS *.
2146 * If that address is in the "outgoing" envelope, it will
2147 * be freed by the caller, otherwise, it should be freed here.
2148 * Pf->textbuf for an Address is used a little to set up a default,
2149 * but then is freed right away below. Pf->scratch is used for a
2150 * pointer to some alloced space for pico to edit in. Addresses in
2151 * the custom area are freed by free_customs().
2153 * For FreeText types, pf->addr is not used. Pf->text points to a
2154 * pointer that points to the text. Pf->textbuf points to a copy of
2155 * the text that must be freed before we leave, otherwise, it is
2156 * probably a pointer into the envelope and that gets freed by the
2159 * He->realaddr is the pointer to the text that pico actually edits.
2162 #if !(defined(DOS) || defined(OS2)) || defined(NOAUTH)
2168 if(outgoing
->newsgroups
&& *outgoing
->newsgroups
)
2171 /* initialize the fixed header elements of the two temp arrays */
2172 for(i
=0; i
< fixed_cnt
; i
++, pf
++){
2173 static int news_order
[] = {
2174 N_AUTHRCVD
,N_FROM
, N_REPLYTO
, N_NEWS
, N_TO
, N_CC
, N_BCC
,
2175 N_FCC
, N_LCC
, N_ATTCH
, N_SUBJ
, N_REF
, N_DATE
, N_INREPLY
,
2176 N_MSGID
, N_PRIORITY
, N_USERAGENT
, N_NOBODY
, N_POSTERR
, N_RPLUID
, N_RPLMBOX
,
2177 N_SMTP
, N_NNTP
, N_CURPOS
, N_OURREPLYTO
, N_OURHDRS
2178 #if !(defined(DOS) || defined(OS2)) || defined(NOAUTH)
2184 /* slightly different editing order if sending to news */
2185 if(use_news_order
&&
2186 index
>= 0 && index
< sizeof(news_order
)/sizeof(news_order
[0]))
2187 index
= news_order
[i
];
2189 /* copy the templates */
2190 *he
= he_template
[index
];
2192 pf
->name
= cpystr(pf_template
[index
].name
);
2193 if(index
== N_SENDER
&& F_ON(F_USE_SENDER_NOT_X
, ps_global
)){
2194 /* slide string over so it is Sender instead of X-X-Sender */
2195 for(p
= pf
->name
+4; *p
!= '\0'; p
++)
2199 pf
->type
= pf_template
[index
].type
;
2200 pf
->canedit
= pf_template
[index
].canedit
;
2201 pf
->rcptto
= pf_template
[index
].rcptto
;
2202 pf
->writehdr
= pf_template
[index
].writehdr
;
2203 pf
->localcopy
= pf_template
[index
].localcopy
;
2207 he
->rich_header
= view_as_rich(pf
->name
, he
->rich_header
);
2208 if(F_OFF(F_ENABLE_TAB_COMPLETE
,ps_global
))
2209 he
->nickcmpl
= NULL
;
2212 case FreeText
: /* realaddr points to c-client env */
2213 if(index
== N_NEWS
){
2214 sending_order
[1] = pf
;
2215 he
->realaddr
= &outgoing
->newsgroups
;
2218 switch(set_default_hdrval(pf
, custom
)){
2221 fs_give((void **)he
->realaddr
);
2223 *he
->realaddr
= pf
->textbuf
;
2229 if(*he
->realaddr
){ /* combine values */
2230 if(pf
->textbuf
&& *pf
->textbuf
){
2234 l
= strlen(*he
->realaddr
) + strlen(pf
->textbuf
) + 1;
2235 combined_hdr
= (char *) fs_get((l
+1) * sizeof(char));
2236 strncpy(combined_hdr
, *he
->realaddr
, l
);
2237 combined_hdr
[l
] = '\0';
2238 strncat(combined_hdr
, ",", l
+1-1-strlen(combined_hdr
));
2239 combined_hdr
[l
] = '\0';
2240 strncat(combined_hdr
, pf
->textbuf
, l
+1-1-strlen(combined_hdr
));
2241 combined_hdr
[l
] = '\0';
2243 fs_give((void **)he
->realaddr
);
2244 *he
->realaddr
= combined_hdr
;
2245 q_status_message(SM_ORDER
, 3, 3,
2246 "Adding newsgroup from role");
2251 *he
->realaddr
= pf
->textbuf
;
2258 /* if no value, use default */
2260 *he
->realaddr
= pf
->textbuf
;
2270 /* If there is a newsgroup, we'd better show it */
2271 if(outgoing
->newsgroups
&& *outgoing
->newsgroups
)
2272 he
->rich_header
= 0; /* force on by default */
2275 fs_give((void **)&pf
->textbuf
);
2277 pf
->text
= he
->realaddr
;
2279 else if(index
== N_DATE
){
2280 sending_order
[2] = pf
;
2281 pf
->text
= (char **) &outgoing
->date
;
2284 else if(index
== N_INREPLY
){
2285 sending_order
[NN
+9] = pf
;
2286 pf
->text
= &outgoing
->in_reply_to
;
2289 else if(index
== N_MSGID
){
2290 sending_order
[NN
+10] = pf
;
2291 pf
->text
= &outgoing
->message_id
;
2294 else if(index
== N_REF
){
2295 sending_order
[NN
+11] = pf
;
2296 pf
->text
= &outgoing
->references
;
2299 else if(index
== N_PRIORITY
){
2300 sending_order
[NN
+12] = pf
;
2301 pf
->text
= &pf
->textbuf
;
2304 else if(index
== N_USERAGENT
){
2305 sending_order
[NN
+13] = pf
;
2306 pf
->text
= &pf
->textbuf
;
2307 pf
->textbuf
= generate_user_agent();
2310 else if(index
== N_POSTERR
){
2311 sending_order
[NN
+14] = pf
;
2313 pf
->text
= &pf
->textbuf
;
2316 else if(index
== N_RPLUID
){
2317 sending_order
[NN
+15] = pf
;
2319 pf
->text
= &pf
->textbuf
;
2322 else if(index
== N_RPLMBOX
){
2323 sending_order
[NN
+16] = pf
;
2325 pf
->text
= &pf
->textbuf
;
2328 else if(index
== N_SMTP
){
2329 sending_order
[NN
+17] = pf
;
2330 pf_smtp_server
= pf
;
2331 pf
->text
= &pf
->textbuf
;
2334 else if(index
== N_NNTP
){
2335 sending_order
[NN
+18] = pf
;
2336 pf_nntp_server
= pf
;
2337 pf
->text
= &pf
->textbuf
;
2340 else if(index
== N_CURPOS
){
2341 sending_order
[NN
+19] = pf
;
2343 pf
->text
= &pf
->textbuf
;
2346 else if(index
== N_OURREPLYTO
){
2347 sending_order
[NN
+20] = pf
;
2349 pf
->text
= &pf
->textbuf
;
2352 else if(index
== N_OURHDRS
){
2353 sending_order
[NN
+21] = pf
;
2355 pf
->text
= &pf
->textbuf
;
2358 else if(index
== N_AUTHRCVD
){
2359 sending_order
[0] = pf
;
2361 pf
->text
= &pf
->textbuf
;
2365 q_status_message(SM_ORDER
| SM_DING
, 3, 7,
2366 "Botched: Unmatched FreeText header in pine_send");
2371 /* can't do a default for this one */
2373 /* If there is an attachment already, we'd better show them */
2374 if(body
&& *body
&& (*body
)->type
!= TYPETEXT
)
2375 he
->rich_header
= 0; /* force on by default */
2382 sending_order
[3] = pf
;
2383 pf
->addr
= &outgoing
->from
;
2384 if(role
&& role
->from
){
2385 if(ps_global
->never_allow_changing_from
)
2386 q_status_message(SM_ORDER
, 3, 3, _("Site policy doesn't allow changing From address so role's From has no effect"));
2388 outgoing
->from
= copyaddrlist(role
->from
);
2389 he
->display_it
= 1; /* show it */
2390 he
->rich_header
= 0;
2398 sending_order
[NN
+2] = pf
;
2399 pf
->addr
= &outgoing
->to
;
2400 /* If already set, make it act like we typed it in */
2402 && outgoing
->to
->mailbox
2403 && outgoing
->to
->mailbox
[0]
2404 && flags
& PS_STICKY_TO
)
2412 sending_order
[NN
+5] = pf
;
2414 if(ps_global
->VAR_EMPTY_HDR_MSG
2415 && !ps_global
->VAR_EMPTY_HDR_MSG
[0]){
2419 nobody_addr
= mail_newaddr();
2420 nobody_addr
->next
= mail_newaddr();
2421 nobody_addr
->mailbox
= cpystr(rfc1522_encode(tmp_20k_buf
,
2423 (unsigned char *)(ps_global
->VAR_EMPTY_HDR_MSG
2424 ? ps_global
->VAR_EMPTY_HDR_MSG
2425 : "undisclosed-recipients"),
2426 ps_global
->posting_charmap
));
2427 pf
->addr
= &nobody_addr
;
2433 sending_order
[NN
+3] = pf
;
2434 pf
->addr
= &outgoing
->cc
;
2438 sending_order
[NN
+4] = pf
;
2439 pf
->addr
= &outgoing
->bcc
;
2440 /* if bcc exists, make sure it's exposed so nothing's
2441 * sent by mistake...
2449 sending_order
[NN
+1] = pf
;
2450 pf
->addr
= &outgoing
->reply_to
;
2451 if(role
&& role
->replyto
){
2452 if(outgoing
->reply_to
)
2453 mail_free_address(&outgoing
->reply_to
);
2455 outgoing
->reply_to
= copyaddrlist(role
->replyto
);
2456 he
->display_it
= 1; /* show it */
2457 he
->rich_header
= 0;
2463 sending_order
[NN
+7] = pf
;
2464 pf
->addr
= &lcc_addr
;
2467 build_address(lcc_arg
, &addr
, NULL
, NULL
, NULL
);
2468 rfc822_parse_adrlist(&lcc_addr
, addr
,
2469 ps_global
->maildomain
);
2470 fs_give((void **)&addr
);
2476 #if !(defined(DOS) || defined(OS2)) || defined(NOAUTH)
2478 sending_order
[4] = pf
;
2479 pf
->addr
= &outgoing
->sender
;
2484 q_status_message1(SM_ORDER
,3,7,
2485 "Internal error: Address header %s", comatose(index
));
2490 * If this is a reply to news, don't show the regular email
2491 * recipient headers (unless they are non-empty).
2493 if((outgoing
->newsgroups
&& *outgoing
->newsgroups
)
2494 && (index
== N_TO
|| index
== N_CC
2495 || index
== N_BCC
|| index
== N_LCC
)
2496 && (pf
->addr
&& !*pf
->addr
)){
2497 if((ct
=set_default_hdrval(pf
, custom
)) >= UseAsDef
&&
2498 pf
->textbuf
&& *pf
->textbuf
){
2499 removing_trailing_white_space(pf
->textbuf
);
2500 (void)removing_double_quotes(pf
->textbuf
);
2501 build_address(pf
->textbuf
, &addr
, NULL
, NULL
, NULL
);
2502 rfc822_parse_adrlist(pf
->addr
, addr
,
2503 ps_global
->maildomain
);
2504 fs_give((void **)&addr
);
2509 he
->rich_header
= 1; /* hide */
2513 * If this address doesn't already have a value, then we check
2514 * for a default value assigned by the user.
2516 else if(pf
->addr
&& !*pf
->addr
){
2517 if((ct
=set_default_hdrval(pf
, custom
)) >= UseAsDef
&&
2519 (!ps_global
->never_allow_changing_from
&&
2520 F_ON(F_ALLOW_CHANGING_FROM
, ps_global
))) &&
2521 pf
->textbuf
&& *pf
->textbuf
){
2523 removing_trailing_white_space(pf
->textbuf
);
2524 (void)removing_double_quotes(pf
->textbuf
);
2527 * Try to set To based on Lcc. Don't attempt Fcc.
2529 if(index
== N_LCC
&& !he_to
->sticky
&& pf_to
&& pf_to
->addr
){
2530 BUILDER_ARG
*barg
= NULL
;
2534 ppp
= addr_list_string(*pf_to
->addr
, NULL
, 1);
2539 barg
= (BUILDER_ARG
*) fs_get(sizeof(*barg
));
2540 memset(barg
, 0, sizeof(*barg
));
2541 barg
->me
= &(he
->bldr_private
);
2542 barg
->aff
= &(he_to
->bldr_private
);
2543 barg
->tptr
= cpystr(ppp
);
2545 build_addr_lcc(pf
->textbuf
, &addr
, NULL
, barg
, NULL
);
2548 rfc822_parse_adrlist(pf
->addr
, addr
,
2549 ps_global
->maildomain
);
2551 fs_give((void **) &addr
);
2556 if(barg
&& barg
->tptr
&& strcmp(ppp
, barg
->tptr
)){
2559 rfc822_parse_adrlist(&a
, barg
->tptr
,
2560 ps_global
->maildomain
);
2563 mail_free_address(pf_to
->addr
);
2571 fs_give((void **) &barg
->tptr
);
2573 fs_give((void **) &barg
);
2577 fs_give((void **) &ppp
);
2580 build_address(pf
->textbuf
, &addr
, NULL
, NULL
, NULL
);
2581 rfc822_parse_adrlist(pf
->addr
, addr
,
2582 ps_global
->maildomain
);
2584 fs_give((void **) &addr
);
2591 /* if we still don't have a from */
2592 if(index
== N_FROM
&& !*pf
->addr
)
2593 *pf
->addr
= generate_from();
2597 * Addr is already set in the rest of the cases.
2599 else if((index
== N_FROM
|| index
== N_REPLYTO
) && pf
->addr
){
2600 ADDRESS
*adr
= NULL
;
2603 * We get to this case of the ifelse if the from or reply-to
2604 * addr was set by a role above.
2607 /* figure out the default value */
2608 (void)set_default_hdrval(pf
, custom
);
2609 if(pf
->textbuf
&& *pf
->textbuf
){
2610 removing_trailing_white_space(pf
->textbuf
);
2611 (void)removing_double_quotes(pf
->textbuf
);
2612 build_address(pf
->textbuf
, &addr
, NULL
, NULL
, NULL
);
2613 rfc822_parse_adrlist(&adr
, addr
,
2614 ps_global
->maildomain
);
2615 fs_give((void **)&addr
);
2618 /* if value set by role is different from default, show it */
2619 if(adr
&& !address_is_same(*pf
->addr
, adr
))
2620 he
->display_it
= 1; /* start this off showing */
2623 if(!(*pf
->addr
)->mailbox
){
2624 fs_give((void **)pf
->addr
);
2629 mail_free_address(&adr
);
2631 else if((index
== N_TO
|| index
== N_CC
|| index
== N_BCC
)
2633 ADDRESS
*a
= NULL
, **tail
;
2636 * These three are different from the others because we
2637 * might add the addresses to what is already there instead
2641 switch(set_default_hdrval(pf
, custom
)){
2644 mail_free_address(pf
->addr
);
2646 removing_trailing_white_space(pf
->textbuf
);
2647 (void)removing_double_quotes(pf
->textbuf
);
2648 build_address(pf
->textbuf
, &addr
, NULL
, NULL
, NULL
);
2649 rfc822_parse_adrlist(pf
->addr
, addr
, ps_global
->maildomain
);
2650 fs_give((void **)&addr
);
2655 removing_trailing_white_space(pf
->textbuf
);
2656 (void)removing_double_quotes(pf
->textbuf
);
2657 build_address(pf
->textbuf
, &addr
, NULL
, NULL
, NULL
);
2658 rfc822_parse_adrlist(&a
, addr
, ps_global
->maildomain
);
2659 fs_give((void **)&addr
);
2662 for(tail
= pf
->addr
; *tail
; tail
= &(*tail
)->next
)
2664 *tail
= reply_cp_addr(ps_global
, 0, NULL
, NULL
,
2665 *pf
->addr
, NULL
, a
, RCA_ALL
);
2666 q_status_message(SM_ORDER
, 3, 3,
2667 "Adding addresses from role");
2668 mail_free_address(&a
);
2678 he
->display_it
= 1; /* start this off showing */
2681 switch(set_default_hdrval(pf
, custom
)){
2685 mail_free_address(pf
->addr
);
2687 removing_trailing_white_space(pf
->textbuf
);
2688 (void)removing_double_quotes(pf
->textbuf
);
2689 build_address(pf
->textbuf
, &addr
, NULL
, NULL
, NULL
);
2690 rfc822_parse_adrlist(pf
->addr
, addr
, ps_global
->maildomain
);
2691 fs_give((void **)&addr
);
2703 if(pf
->addr
&& *pf
->addr
&& !(*pf
->addr
)->mailbox
){
2704 mail_free_address(pf
->addr
);
2705 he
->display_it
= 1; /* start this off showing */
2708 if(pf
->textbuf
) /* free default value in any case */
2709 fs_give((void **)&pf
->textbuf
);
2711 /* outgoing2strings will alloc the string pf->scratch below */
2712 he
->realaddr
= &pf
->scratch
;
2716 sending_order
[NN
+8] = pf
;
2718 if(role
&& role
->fcc
)
2721 fcc
= get_fcc(fcc_arg
);
2724 fs_give((void **)&fcc_to_free
);
2728 if(((flags
& PS_STICKY_FCC
) && fcc
[0]) || (role
&& role
->fcc
))
2734 if(strcmp(fcc
, ps_global
->VAR_DEFAULT_FCC
) != 0)
2735 he
->display_it
= 1; /* start this off showing */
2737 he
->realaddr
= &fcc
;
2743 sending_order
[NN
+6] = pf
;
2745 switch(set_default_hdrval(pf
, custom
)){
2748 pf
->scratch
= pf
->textbuf
;
2751 if(outgoing
->subject
)
2752 fs_give((void **)&outgoing
->subject
);
2758 /* if no value, use default */
2759 if(outgoing
->subject
){
2760 pf
->scratch
= cpystr(outgoing
->subject
);
2763 pf
->scratch
= pf
->textbuf
;
2770 he
->realaddr
= &pf
->scratch
;
2771 pf
->text
= &outgoing
->subject
;
2775 q_status_message1(SM_ORDER
,3,7,
2776 "Unknown header type %d in pine_send",
2782 * We may or may not want to give the user the chance to edit
2783 * the From and Reply-To lines. If they are listed in either
2784 * Default-composer-hdrs or Customized-hdrs, then they can edit
2786 * If canedit is not set, that means that this header is not in
2787 * the user's customized-hdrs. If rich_header is set, that
2788 * means that this header is not in the user's
2789 * default-composer-hdrs (since From and Reply-To are rich
2790 * by default). So, don't give it an he to edit with in that case.
2792 * For other types, just not setting canedit will cause it to be
2793 * uneditable, regardless of what the user does.
2797 /* to allow it, we let this fall through to the reply-to case below */
2798 if(ps_global
->never_allow_changing_from
||
2799 (F_OFF(F_ALLOW_CHANGING_FROM
, ps_global
) &&
2800 !(role
&& role
->from
))){
2801 if(pf
->canedit
|| !he
->rich_header
)
2802 q_status_message(SM_ORDER
, 3, 3,
2803 _("Not allowed to change header \"From\""));
2805 memset(he
, 0, (size_t)sizeof(*he
));
2811 if(!pf
->canedit
&& he
->rich_header
){
2812 memset(he
, 0, (size_t)sizeof(*he
));
2824 memset(he
, 0, (size_t)sizeof(*he
));
2835 * This is so the builder can tell the composer to fill the affected
2836 * field based on the value in the field on the left.
2838 * Note that this mechanism isn't completely general. Each entry has
2839 * only a single next_affected, so if some other entry points an
2840 * affected entry at an entry with a next_affected, they all inherit
2841 * that next_affected. Since this isn't used much a careful ordering
2842 * of the affected fields should make it a sufficient mechanism.
2844 he_to
->affected_entry
= he_fcc
;
2845 he_news
->affected_entry
= he_fcc
;
2846 he_lcc
->affected_entry
= he_to
;
2847 he_to
->next_affected
= he_fcc
;
2849 (--pf
)->next
= (total_cnt
!= fixed_cnt
) ? header
.custom
: NULL
;
2851 i
--; /* subtract one because N_ATTCH doesn't get a sending_order slot */
2853 * Set up headerentries for custom fields.
2854 * NOTE: "i" is assumed to now index first custom field in sending
2857 for(pf
= pf
->next
; pf
&& pf
->name
; pf
= pf
->next
){
2871 if(pf
->addr
){ /* better be set */
2872 sending_order
[i
++] = pf
;
2873 *he
= he_custom_addr_templ
;
2874 /* change default text into an ADDRESS */
2875 /* strip quotes around whole default */
2876 removing_trailing_white_space(pf
->textbuf
);
2877 (void)removing_double_quotes(pf
->textbuf
);
2878 build_address(pf
->textbuf
, &addr
, NULL
, NULL
, NULL
);
2879 rfc822_parse_adrlist(pf
->addr
, addr
, ps_global
->maildomain
);
2880 fs_give((void **)&addr
);
2882 fs_give((void **)&pf
->textbuf
);
2884 he
->realaddr
= &pf
->scratch
;
2885 if(F_OFF(F_ENABLE_TAB_COMPLETE
,ps_global
))
2886 he
->nickcmpl
= NULL
;
2892 sending_order
[i
++] = pf
;
2893 *he
= he_custom_free_templ
;
2894 he
->realaddr
= &pf
->textbuf
;
2895 pf
->text
= &pf
->textbuf
;
2896 if(((!pf
->val
|| !pf
->val
[0]) && pf
->textbuf
&& pf
->textbuf
[0]) ||
2897 (pf
->val
&& (!pf
->textbuf
|| strcmp(pf
->textbuf
, pf
->val
))))
2898 he
->display_it
= 1; /* show it */
2903 q_status_message1(SM_ORDER
,0,7,"Unknown custom header type %d",
2908 he
->name
= pf
->name
;
2910 /* use first 8 characters for prompt */
2911 he
->prompt
= cpystr(" : ");
2912 strncpy(he
->prompt
, he
->name
, MIN(strlen(he
->name
), he
->prwid
- 2));
2914 he
->rich_header
= view_as_rich(he
->name
, he
->rich_header
);
2919 * Make sure at least *one* field is displayable...
2921 for(index
= -1, i
=0, pf
=header
.local
; pf
&& pf
->name
; pf
=pf
->next
, i
++)
2922 if(HE(pf
) && !HE(pf
)->rich_header
){
2928 * None displayable!!! Warn and display defaults.
2931 q_status_message(SM_ORDER
,0,5,
2932 "No default-composer-hdrs matched, displaying defaults");
2933 for(i
= 0, pf
= header
.local
; pf
; pf
= pf
->next
, i
++)
2934 if((i
== N_TO
|| i
== N_CC
|| i
== N_SUBJ
|| i
== N_ATTCH
)
2936 HE(pf
)->rich_header
= 0;
2940 * Save information about body which set_mime_type_by_grope might change.
2941 * Then, if we get an error sending, we reset these things so that
2942 * grope can do it's thing again after we edit some more.
2944 if ((*body
)->type
== TYPEMULTIPART
)
2945 bp
= save_body_particulars(&(*body
)->nested
.part
->body
);
2947 bp
= save_body_particulars(*body
);
2950 local_redraft_pos
= redraft_pos
;
2952 /*----------------------------------------------------------------------
2953 Loop calling the editor until everything goes well
2956 int saved_user_timeout
;
2958 /* Reset body to what it was when we started. */
2959 if ((*body
)->type
== TYPEMULTIPART
)
2960 reset_body_particulars(bp
, &(*body
)->nested
.part
->body
);
2962 reset_body_particulars(bp
,*body
);
2964 * set initial cursor position based on how many times we've been
2967 if(reply
&& reply
->pseudo
){
2968 pbf
->pine_flags
|= reply
->data
.pico_flags
;
2970 else if(body_start
){
2971 pbf
->pine_flags
|= P_BODY
;
2972 body_start
= 0; /* maybe not next time */
2974 else if(local_redraft_pos
){
2975 pbf
->edit_offset
= local_redraft_pos
->offset
;
2976 /* set the start_here bit in correct header */
2977 for(pf
= header
.local
; pf
&& pf
->name
; pf
= pf
->next
)
2978 if(strcmp(pf
->name
, local_redraft_pos
->hdrname
) == 0
2980 HE(pf
)->start_here
= 1;
2984 /* If didn't find it, we start in body. */
2985 if(!pf
|| !pf
->name
)
2986 pbf
->pine_flags
|= P_BODY
;
2988 else if(reply
&& (!reply
->forw
&& !reply
->forwarded
)){
2989 pbf
->pine_flags
|= P_BODY
;
2992 /* in case these were turned on in previous pass through loop */
2994 pf_nobody
->writehdr
= 0;
2995 pf_nobody
->localcopy
= 0;
2999 pf_fcc
->localcopy
= 0;
3002 * If a sending attempt failed after we passed the message text
3003 * thru a user-defined filter, "orig_so" points to the original
3004 * text. Replace the body's encoded data with the original...
3007 STORE_S
**so
= (STORE_S
**)(((*body
)->type
== TYPEMULTIPART
)
3008 ? &(*body
)->nested
.part
->body
.contents
.text
.data
3009 : &(*body
)->contents
.text
.data
);
3016 * Convert the envelope and body to the string format that
3019 outgoing2strings(&header
, *body
, &pbf
->msgtext
, &pbf
->attachments
, 0);
3021 for(pf
= header
.local
; pf
&& pf
->name
; pf
= pf
->next
){
3023 * If this isn't the first time through this loop, we may have
3024 * freed some of the FreeText headers below so that they wouldn't
3025 * show up as empty headers in the finished message. Need to
3026 * alloc them again here so they can be edited.
3028 if(pf
->type
== FreeText
&& HE(pf
) && !*HE(pf
)->realaddr
)
3029 *HE(pf
)->realaddr
= cpystr("");
3031 if(pf
->type
!= Attachment
&& HE(pf
) && *HE(pf
)->realaddr
)
3032 HE(pf
)->maxlen
= strlen(*HE(pf
)->realaddr
);
3036 * If From is exposed, probably by a role, then start the cursor
3037 * on the first line which isn't filled in. If it isn't, then we
3038 * don't move the cursor, mostly for back-compat.
3040 if((!reply
|| reply
->forw
|| reply
->forwarded
) &&
3041 !local_redraft_pos
&& !(pbf
->pine_flags
& P_BODY
) && he_from
&&
3042 (he_from
->display_it
|| !he_from
->rich_header
)){
3043 for(pf
= header
.local
; pf
&& pf
->name
; pf
= pf
->next
)
3045 (HE(pf
)->display_it
|| !HE(pf
)->rich_header
) &&
3047 (!*HE(pf
)->realaddr
|| !**HE(pf
)->realaddr
)){
3048 HE(pf
)->start_here
= 1;
3054 mswin_setwindowmenu (MENU_COMPOSER
);
3057 cancel_busy_cue(-1);
3058 flush_status_messages(1);
3060 /* turn off user input timeout when in composer */
3061 saved_user_timeout
= ps_global
->hours_to_timeout
;
3062 ps_global
->hours_to_timeout
= 0;
3063 dprint((1, "\n ---- COMPOSER ----\n"));
3064 editor_result
= pico(pbf
);
3065 dprint((4, "... composer returns (0x%x)\n", editor_result
));
3066 ps_global
->hours_to_timeout
= saved_user_timeout
;
3069 mswin_setwindowmenu (MENU_DEFAULT
);
3071 fix_windsize(ps_global
);
3074 * Only reinitialize signals if we didn't receive an interesting
3075 * one while in pico, since pico's return is part of processing that
3076 * signal and it should continue to be ignored.
3078 if(!(editor_result
& COMP_GOTHUP
))
3079 init_signals(); /* Pico has it's own signal stuff */
3082 * We're going to save in DEADLETTER. Dump attachments first.
3084 if(editor_result
& COMP_CANCEL
)
3085 free_attachment_list(&pbf
->attachments
);
3087 /* Turn strings back into structures */
3088 strings2outgoing(&header
, body
, pbf
->attachments
, flowing_requested
);
3090 /* Make newsgroups NULL if it is "" (so won't show up in headers) */
3091 if(outgoing
->newsgroups
){
3092 sqzspaces(outgoing
->newsgroups
);
3093 if(!outgoing
->newsgroups
[0])
3094 fs_give((void **)&(outgoing
->newsgroups
));
3097 /* Make subject NULL if it is "" (so won't show up in headers) */
3098 if(outgoing
->subject
&& !outgoing
->subject
[0])
3099 fs_give((void **)&(outgoing
->subject
));
3101 /* remove custom fields that are empty */
3102 for(pf
= header
.local
; pf
&& pf
->name
; pf
= pf
->next
){
3103 if(pf
->type
== FreeText
&& pf
->textbuf
){
3104 if(pf
->textbuf
[0] == '\0'){
3105 fs_give((void **)&pf
->textbuf
);
3111 removing_trailing_white_space(fcc
);
3113 /*-------- Stamp it with a current date -------*/
3114 if(outgoing
->date
) /* update old date */
3115 fs_give((void **)&(outgoing
->date
));
3117 if(F_ON(F_QUELL_TIMEZONE
, ps_global
))
3118 mail_parameters(NULL
, SET_DISABLE822TZTEXT
, (void *) TRUE
);
3120 rfc822_date(tmp_20k_buf
); /* format and copy new date */
3121 if(F_ON(F_QUELL_TIMEZONE
, ps_global
))
3122 mail_parameters(NULL
, SET_DISABLE822TZTEXT
, (void *) FALSE
);
3124 outgoing
->date
= (unsigned char *) cpystr(tmp_20k_buf
);
3126 /* Set return_path based on From which is going to be used */
3127 if(outgoing
->return_path
)
3128 mail_free_address(&outgoing
->return_path
);
3130 outgoing
->return_path
= rfc822_cpy_adr(outgoing
->from
);
3133 * Don't ever believe the sender that is there.
3134 * If From doesn't look quite right, generate our own sender.
3136 if(outgoing
->sender
)
3137 mail_free_address(&outgoing
->sender
);
3140 * If the LHS of the address doesn't match, or the RHS
3141 * doesn't match one of localdomain or hostname,
3142 * then add a sender line (really X-X-Sender).
3144 * Don't add a personal_name since the user can change that.
3146 if(F_OFF(F_DISABLE_SENDER
, ps_global
)
3149 || !outgoing
->from
->mailbox
3150 || strucmp(outgoing
->from
->mailbox
, ps_global
->VAR_USER_ID
) != 0
3151 || !outgoing
->from
->host
3152 || !(strucmp(outgoing
->from
->host
, ps_global
->localdomain
) == 0
3153 || strucmp(outgoing
->from
->host
, ps_global
->hostname
) == 0))){
3155 outgoing
->sender
= mail_newaddr();
3156 outgoing
->sender
->mailbox
= cpystr(ps_global
->VAR_USER_ID
);
3157 outgoing
->sender
->host
= cpystr(ps_global
->hostname
);
3160 if(ps_global
->newthread
){
3161 if(outgoing
->in_reply_to
) fs_give((void **)&outgoing
->in_reply_to
);
3162 if(outgoing
->references
) fs_give((void **)&outgoing
->references
);
3165 /*----- Message is edited, now decide what to do with it ----*/
3166 if(editor_result
& (COMP_SUSPEND
| COMP_GOTHUP
| COMP_CANCEL
)){
3167 /*=========== Postpone or Interrupted message ============*/
3168 CONTEXT_S
*fcc_cntxt
= NULL
;
3169 char folder
[MAXPATH
+1];
3173 dprint((4, "pine_send:%s handling\n",
3174 (editor_result
& COMP_SUSPEND
)
3176 : (editor_result
& COMP_GOTHUP
)
3178 : (editor_result
& COMP_CANCEL
)
3179 ? "CANCEL" : "HUH?"));
3180 if((editor_result
& COMP_CANCEL
)
3181 && (F_ON(F_QUELL_DEAD_LETTER
, ps_global
)
3182 || ps_global
->deadlets
== 0)){
3183 q_status_message(SM_ORDER
, 0, 3, "Message cancelled");
3188 * The idea here is to use the Fcc: writing facility
3189 * to append to the special postponed message folder...
3191 * NOTE: the strategy now is to write the message and
3192 * all attachments as they exist at composition time.
3193 * In other words, attachments are postponed by value
3194 * and not reference. This may change later, but we'll
3195 * need a local "message/external-body" type that
3196 * outgoing2strings knows how to properly set up for
3197 * the composer. Maybe later...
3202 if(F_ON(F_COMPOSE_REJECTS_UNQUAL
, ps_global
)
3203 && (editor_result
& COMP_SUSPEND
)
3204 && (check_addresses(&header
) == CA_BAD
)){
3205 /*--- Addresses didn't check out---*/
3206 q_status_message(SM_ORDER
, 7, 7,
3207 _("Not allowed to postpone message until addresses are qualified"));
3212 * Build the local message copy so.
3214 * In the HUP case, we'll write the bezerk delimiter by
3215 * hand and output the message directly into the folder.
3216 * It's not only faster, we don't have to worry about
3217 * c-client reentrance and less hands paw over the data so
3218 * there's less chance of a problem.
3220 * In the Postpone case, just create it if the user wants to
3221 * and create a temporary storage object to write into. */
3223 lmc
.all_written
= lmc
.text_only
= lmc
.text_written
= 0;
3224 if(editor_result
& (COMP_GOTHUP
| COMP_CANCEL
)){
3226 time_t now
= time((time_t *)0);
3228 #if defined(DOS) || defined(OS2)
3230 * we can't assume anything about root or home dirs, so
3231 * just plunk it down in the same place as the pinerc
3233 if(!getenv("HOME")){
3234 char *lc
= last_cmpnt(ps_global
->pinerc
);
3237 strncpy(folder
,ps_global
->pinerc
,
3238 MIN(lc
-ps_global
->pinerc
,sizeof(folder
)-1));
3239 folder
[MIN(lc
-ps_global
->pinerc
,sizeof(folder
)-1)]='\0';
3242 strncat(folder
, (editor_result
& COMP_GOTHUP
)
3243 ? INTERRUPTED_MAIL
: DEADLETTER
,
3244 sizeof(folder
)-strlen(folder
)-1);
3249 ps_global
->VAR_OPER_DIR
3250 ? ps_global
->VAR_OPER_DIR
: ps_global
->home_dir
,
3251 (editor_result
& COMP_GOTHUP
)
3252 ? INTERRUPTED_MAIL
: DEADLETTER
,
3255 if(editor_result
& COMP_CANCEL
){
3256 char filename
[MAXPATH
+1], newfname
[MAXPATH
+1], nbuf
[5];
3258 if(strlen(folder
) + 1 < sizeof(filename
))
3259 for(i
= ps_global
->deadlets
- 1; i
> 0 && i
< 9; i
--){
3260 strncpy(filename
, folder
, sizeof(filename
));
3261 filename
[sizeof(filename
)-1] = '\0';
3262 strncpy(newfname
, filename
, sizeof(newfname
));
3263 newfname
[sizeof(newfname
)-1] = '\0';
3266 snprintf(nbuf
, sizeof(nbuf
), "%d", i
);
3267 nbuf
[sizeof(nbuf
)-1] = '\0';
3268 strncat(filename
, nbuf
,
3269 sizeof(filename
)-strlen(filename
)-1);
3270 filename
[sizeof(filename
)-1] = '\0';
3273 snprintf(nbuf
, sizeof(nbuf
), "%d", i
+1);
3274 nbuf
[sizeof(nbuf
)-1] = '\0';
3275 strncat(newfname
, nbuf
,
3276 sizeof(newfname
)-strlen(newfname
)-1);
3277 newfname
[sizeof(newfname
)-1] = '\0';
3278 (void) rename_file(filename
, newfname
);
3284 newfile
= can_access(folder
, ACCESS_EXISTS
);
3286 if((lmc
.so
= so_get(FCC_SOURCE
, NULL
, WRITE_ACCESS
)) != NULL
){
3287 if (outgoing
->from
){
3288 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, "%sFrom %s@%s %.24s\015\012",
3289 newfile
? "" : "\015\012",
3290 outgoing
->from
->mailbox
,
3291 outgoing
->from
->host
, ctime(&now
));
3292 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
3293 if(!so_puts(lmc
.so
, tmp_20k_buf
)){
3294 if(editor_result
& COMP_CANCEL
)
3295 q_status_message2(SM_ORDER
| SM_DING
, 3, 3,
3296 "Can't write \"%s\": %s",
3297 folder
, error_description(errno
));
3299 dprint((1, "* * * CAN'T WRITE %s: %s\n",
3300 folder
? folder
: "?",
3301 error_description(errno
)));
3306 else{ /* Must be COMP_SUSPEND */
3307 if(!ps_global
->VAR_POSTPONED_FOLDER
3308 || !ps_global
->VAR_POSTPONED_FOLDER
[0]){
3309 q_status_message(SM_ORDER
| SM_DING
, 3, 3,
3310 _("No postponed file defined"));
3315 * Store the cursor position
3317 * First find the header entry with the start_here
3318 * bit set, if any. This means the editor is telling
3319 * us to start on this header field next time.
3321 start_here_name
= NULL
;
3322 for(pf
= header
.local
; pf
&& pf
->name
; pf
= pf
->next
)
3323 if(HE(pf
) && HE(pf
)->start_here
){
3324 start_here_name
= pf
->name
;
3328 /* If there wasn't one, ":" means we start in the body. */
3329 if(!start_here_name
|| !*start_here_name
)
3330 start_here_name
= ":";
3332 if(ps_global
->VAR_FORM_FOLDER
3333 && ps_global
->VAR_FORM_FOLDER
[0]
3334 && postpone_prompt() == 'f'){
3335 strncpy(folder
, ps_global
->VAR_FORM_FOLDER
,
3337 folder
[sizeof(folder
)-1] = '\0';
3338 strncpy(label
, "form letter", sizeof(label
));
3339 label
[sizeof(label
)-1] = '\0';
3342 strncpy(folder
, ps_global
->VAR_POSTPONED_FOLDER
,
3344 folder
[sizeof(folder
)-1] = '\0';
3345 strncpy(label
, "postponed message", sizeof(label
));
3346 label
[sizeof(label
)-1] = '\0';
3349 lmc
.so
= open_fcc(folder
,&fcc_cntxt
, 1, NULL
, NULL
);
3356 /* copy fcc line to postponed or interrupted folder */
3358 pf_fcc
->localcopy
= 1;
3360 /* plug error into header for later display to user */
3361 if((editor_result
& ~0xff) && (lmq
= last_message_queued()) != NULL
){
3362 pf_err
->writehdr
= 1;
3363 pf_err
->localcopy
= 1;
3364 pf_err
->textbuf
= lmq
;
3368 * if reply, write (UID)folder header field so we can
3369 * later flag the replied-to message \\ANSWERED
3370 * DON'T save MSGNO's.
3372 if(reply
&& reply
->uid
){
3373 char uidbuf
[MAILTMPLEN
], *p
;
3376 for(i
= 0L, p
= tmp_20k_buf
; reply
->data
.uid
.msgs
[i
]; i
++){
3378 sstrncpy(&p
, ",", SIZEOF_20KBUF
-(p
-tmp_20k_buf
));
3380 sstrncpy(&p
,ulong2string(reply
->data
.uid
.msgs
[i
]),SIZEOF_20KBUF
-(p
-tmp_20k_buf
));
3383 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
3385 pf_uid
->writehdr
= 1;
3386 pf_uid
->localcopy
= 1;
3387 snprintf(uidbuf
, sizeof(uidbuf
), "(%s%s%s)(%ld %lu %s)%s",
3388 reply
->prefix
? int2string(strlen(reply
->prefix
))
3389 : (reply
->forwarded
) ? "": "0 ",
3390 reply
->prefix
? " " : "",
3391 reply
->prefix
? reply
->prefix
: "",
3392 i
, reply
->data
.uid
.validity
,
3393 tmp_20k_buf
, reply
->mailbox
);
3394 uidbuf
[sizeof(uidbuf
)-1] = '\0';
3395 pf_uid
->textbuf
= cpystr(uidbuf
);
3398 * Logically, this ought to be part of pf_uid, but this
3399 * was added later and so had to be in a separate header
3400 * for backwards compatibility.
3402 pf_mbox
->writehdr
= 1;
3403 pf_mbox
->localcopy
= 1;
3404 pf_mbox
->textbuf
= cpystr(reply
->origmbox
3409 /* Save cursor position */
3410 if(start_here_name
&& *start_here_name
){
3411 char curposbuf
[MAILTMPLEN
];
3413 pf_curpos
->writehdr
= 1;
3414 pf_curpos
->localcopy
= 1;
3415 snprintf(curposbuf
, sizeof(curposbuf
), "%s %ld", start_here_name
,
3417 curposbuf
[sizeof(curposbuf
)-1] = '\0';
3418 pf_curpos
->textbuf
= cpystr(curposbuf
);
3422 * Work around c-client reply-to bug. C-client will
3423 * return a reply_to in an envelope even if there is
3424 * no reply-to header field. We want to note here whether
3425 * the reply-to is real or not.
3427 if(outgoing
->reply_to
|| hdr_is_in_list("reply-to", custom
)){
3428 pf_ourrep
->writehdr
= 1;
3429 pf_ourrep
->localcopy
= 1;
3430 if(outgoing
->reply_to
)
3431 pf_ourrep
->textbuf
= cpystr("Full");
3433 pf_ourrep
->textbuf
= cpystr("Empty");
3436 /* Save the role-specific smtp server */
3437 if(role
&& role
->smtp
&& role
->smtp
[0]){
3438 char *q
, *smtp
= NULL
;
3443 * Turn the list of smtp servers into a space-
3444 * delimited list in a single string.
3446 for(lp
= role
->smtp
; (q
= *lp
) != NULL
; lp
++)
3447 len
+= (strlen(q
) + 1);
3450 smtp
= (char *) fs_get(len
* sizeof(char));
3452 for(lp
= role
->smtp
; (q
= *lp
) != NULL
; lp
++){
3453 if(lp
!= role
->smtp
)
3454 strncat(smtp
, " ", len
-strlen(smtp
)-1);
3456 strncat(smtp
, q
, len
-strlen(smtp
)-1);
3462 pf_smtp_server
->writehdr
= 1;
3463 pf_smtp_server
->localcopy
= 1;
3465 pf_smtp_server
->textbuf
= smtp
;
3467 pf_smtp_server
->textbuf
= cpystr("");
3470 /* Save the role-specific nntp server */
3471 if(suggested_nntp_server
||
3472 (role
&& role
->nntp
&& role
->nntp
[0])){
3473 char *q
, *nntp
= NULL
;
3477 if(role
&& role
->nntp
&& role
->nntp
[0]){
3479 * Turn the list of nntp servers into a space-
3480 * delimited list in a single string.
3482 for(lp
= role
->nntp
; (q
= *lp
) != NULL
; lp
++)
3483 len
+= (strlen(q
) + 1);
3486 nntp
= (char *) fs_get(len
* sizeof(char));
3488 for(lp
= role
->nntp
; (q
= *lp
) != NULL
; lp
++){
3489 if(lp
!= role
->nntp
)
3490 strncat(nntp
, " ", len
-strlen(nntp
)-1);
3492 strncat(nntp
, q
, len
-strlen(nntp
)-1);
3499 nntp
= cpystr(suggested_nntp_server
);
3501 pf_nntp_server
->writehdr
= 1;
3502 pf_nntp_server
->localcopy
= 1;
3504 pf_nntp_server
->textbuf
= nntp
;
3506 pf_nntp_server
->textbuf
= cpystr("");
3510 * Write the list of custom headers to the
3511 * X-Our-Headers header so that we can recover the
3515 for(pf
= header
.custom
; pf
&& pf
->name
; pf
= pf
->next
)
3516 sz
+= strlen(pf
->name
) + 1;
3521 pf_ourhdrs
->writehdr
= 1;
3522 pf_ourhdrs
->localcopy
= 1;
3523 pf_ourhdrs
->textbuf
= (char *)fs_get(sz
);
3524 memset(pf_ourhdrs
->textbuf
, 0, sz
);
3525 q
= pf_ourhdrs
->textbuf
;
3526 for(pf
= header
.custom
; pf
&& pf
->name
; pf
= pf
->next
){
3527 if(pf
!= header
.custom
)
3528 sstrncpy(&q
, ",", sz
-(q
-pf_ourhdrs
->textbuf
));
3530 sstrncpy(&q
, pf
->name
, sz
-(q
-pf_ourhdrs
->textbuf
));
3533 pf_ourhdrs
->textbuf
[sz
-1] = '\0';;
3537 * We need to make sure any header values that got cleared
3538 * get written to the postponed message (they won't if
3539 * pf->text is NULL). Otherwise, we can't tell previously
3540 * non-existent custom headers or default values from
3541 * custom (or other) headers that got blanked in the
3544 for(pf
= header
.local
; pf
&& pf
->name
; pf
= pf
->next
)
3545 if(pf
->type
== FreeText
&& HE(pf
) && !*(HE(pf
)->realaddr
))
3546 *(HE(pf
)->realaddr
) = cpystr("");
3549 * We're saving the message for use later. It may be that the
3550 * characters in the message are not all convertible to the
3551 * user's posting_charmap. We'll save it as UTF-8 instead
3552 * and worry about that the next time they try to send it.
3553 * Use a different save pointer just to be sure we don't
3554 * mess up the other stuff. We should probably make the
3555 * charset an argument.
3557 * We also need to fix the charset of the body part
3558 * the user is editing so that we can read it back
3559 * successfully when we resume the composition.
3561 ps_global
->post_utf8
= 1;
3566 if((*body
)->type
== TYPEMULTIPART
)
3567 bp
= &(*body
)->nested
.part
->body
;
3571 for(pm
= bp
->parameter
;
3572 pm
&& strucmp(pm
->attribute
, "charset") != 0;
3578 fs_give((void **) &pm
->value
);
3580 pm
->value
= cpystr("UTF-8");
3584 if(pine_rfc822_output(&header
,*body
,NULL
,NULL
) >= 0L){
3585 if(editor_result
& (COMP_GOTHUP
| COMP_CANCEL
)){
3591 if(editor_result
& COMP_CANCEL
){
3592 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
,
3593 "Saving to \"%s\"", folder
);
3594 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
3595 we_cancel
= busy_cue((char *)tmp_20k_buf
, NULL
, 1);
3599 so_get(FileStar
, folder
, WRITE_ACCESS
|OWNER_ONLY
)) != NULL
){
3600 gf_set_so_readc(&gc
, lmc
.so
);
3601 gf_set_so_writec(&pc
, hup_so
);
3602 so_seek(lmc
.so
, 0L, 0); /* read msg copy and */
3603 so_seek(hup_so
, 0L, 2); /* append to folder */
3605 gf_link_filter(gf_nvtnl_local
, NULL
);
3606 if(!(fcc_result
= !(err
= gf_pipe(gc
, pc
))))
3607 dprint((1, "*** PIPE FAILED: %s\n",
3610 gf_clear_so_readc(lmc
.so
);
3611 gf_clear_so_writec(hup_so
);
3615 dprint((1, "*** CAN'T CREATE %s: %s\n",
3616 folder
? folder
: "?",
3617 error_description(errno
)));
3620 cancel_busy_cue(-1);
3623 fcc_result
= write_fcc(folder
, fcc_cntxt
,
3624 lmc
.so
, NULL
, label
, NULL
);
3627 /* discontinue coerced UTF-8 posting */
3628 ps_global
->post_utf8
= 0;
3633 dprint((1, "***CAN'T ALLOCATE temp store: %s ",
3634 error_description(errno
)));
3636 if(editor_result
& COMP_GOTHUP
){
3638 * Special Hack #291: if any hi-byte bits are set in
3639 * editor's result, we put them there.
3641 if(editor_result
& 0xff00)
3642 exit(editor_result
>> 8);
3644 dprint((1, "Save composition on HUP %sED\n",
3645 fcc_result
? "SUCCEED" : "FAIL"));
3646 hup_signal(); /* Do what we normally do on SIGHUP */
3648 else if((editor_result
& COMP_SUSPEND
) && fcc_result
){
3649 if(ps_global
->VAR_FORM_FOLDER
3650 && ps_global
->VAR_FORM_FOLDER
[0]
3651 && !strcmp(folder
, ps_global
->VAR_FORM_FOLDER
))
3652 q_status_message(SM_ORDER
, 0, 3,
3653 _("Composition saved to Form Letter Folder. Select Compose to send."));
3655 q_status_message(SM_ORDER
, 0, 3,
3656 _("Composition postponed. Select Compose to resume."));
3658 break; /* postpone went OK, get out of here */
3660 else if(editor_result
& COMP_CANCEL
){
3663 if(fcc_result
&& folder
)
3664 lc
= last_cmpnt(folder
);
3666 q_status_message3(SM_ORDER
, 0, 3,
3667 _("Message cancelled%s%s%s"),
3668 (lc
&& *lc
) ? " and copied to \"" : "",
3669 (lc
&& *lc
) ? lc
: "",
3670 (lc
&& *lc
) ? "\" file" : "");
3674 q_status_message(SM_ORDER
, 0, 4,
3675 _("Continuing composition. Message not postponed or sent"));
3677 continue; /* postpone failed, jump back in to composer */
3681 /*------ Must be sending mail or posting ! -----*/
3682 int result
, valid_addr
, continue_with_only_fcc
= 0;
3683 CONTEXT_S
*fcc_cntxt
= NULL
;
3686 dprint((4, "=== sending: "));
3688 /* --- If posting, confirm with user ----*/
3689 if(outgoing
->newsgroups
&& *outgoing
->newsgroups
3690 && F_OFF(F_QUELL_EXTRA_POST_PROMPT
, ps_global
)
3691 && want_to(POST_PMT
, 'n', 'n', NO_HELP
, WT_NORM
) == 'n'){
3692 q_status_message(SM_ORDER
, 0, 3, _("Message not posted"));
3693 dprint((4, "no post, continuing\n"));
3697 if(!(outgoing
->to
|| outgoing
->cc
|| outgoing
->bcc
|| lcc_addr
3698 || outgoing
->newsgroups
)){
3700 if(F_OFF(F_AUTO_FCC_ONLY
, ps_global
) &&
3701 want_to(_("No recipients, really copy only to Fcc "),
3702 'n', 'n', h_send_fcc_only
, WT_NORM
) != 'y')
3705 continue_with_only_fcc
++;
3708 q_status_message(SM_ORDER
, 3, 4,
3709 _("No recipients specified!"));
3710 dprint((4, "no recip, continuing\n"));
3715 if((valid_addr
= check_addresses(&header
)) == CA_BAD
){
3716 /*--- Addresses didn't check out---*/
3717 dprint((4, "addrs failed, continuing\n"));
3721 if(F_ON(F_WARN_ABOUT_NO_TO_OR_CC
, ps_global
)
3722 && !continue_with_only_fcc
3723 && !(outgoing
->to
|| outgoing
->cc
|| lcc_addr
3724 || outgoing
->newsgroups
)
3725 && (want_to(_("No To, Cc, or Newsgroup specified, send anyway "),
3726 'n', 'n', h_send_check_to_cc
, WT_NORM
) != 'y')){
3727 dprint((4, "No To or CC or Newsgroup, continuing\n"));
3728 if(local_redraft_pos
&& local_redraft_pos
!= redraft_pos
)
3729 free_redraft_pos(&local_redraft_pos
);
3732 = (REDRAFT_POS_S
*) fs_get(sizeof(*local_redraft_pos
));
3733 memset((void *) local_redraft_pos
,0,sizeof(*local_redraft_pos
));
3734 local_redraft_pos
->hdrname
= cpystr(TONAME
);
3738 if(F_ON(F_WARN_ABOUT_NO_SUBJECT
, ps_global
)
3739 && check_for_subject(&header
) == CF_MISSING
){
3740 dprint((4, "No subject, continuing\n"));
3741 if(local_redraft_pos
&& local_redraft_pos
!= redraft_pos
)
3742 free_redraft_pos(&local_redraft_pos
);
3745 = (REDRAFT_POS_S
*) fs_get(sizeof(*local_redraft_pos
));
3746 memset((void *) local_redraft_pos
,0,sizeof(*local_redraft_pos
));
3747 local_redraft_pos
->hdrname
= cpystr(SUBJNAME
);
3751 if(F_ON(F_WARN_ABOUT_NO_FCC
, ps_global
)
3752 && check_for_fcc(fcc
) == CF_MISSING
){
3753 dprint((4, "No fcc, continuing\n"));
3754 if(local_redraft_pos
&& local_redraft_pos
!= redraft_pos
)
3755 free_redraft_pos(&local_redraft_pos
);
3758 = (REDRAFT_POS_S
*) fs_get(sizeof(*local_redraft_pos
));
3759 memset((void *) local_redraft_pos
,0,sizeof(*local_redraft_pos
));
3760 local_redraft_pos
->hdrname
= cpystr("Fcc");
3766 /*---- Check out fcc -----*/
3769 * If special name "inbox" then replace it with the
3772 if(ps_global
->VAR_INBOX_PATH
3773 && strucmp(fcc
, ps_global
->inbox_name
) == 0){
3776 replace_fcc
= cpystr(ps_global
->VAR_INBOX_PATH
);
3777 fs_give((void **)&fcc
);
3781 lmc
.all_written
= lmc
.text_written
= 0;
3782 /* lmc.text_only set on command line */
3783 if(!(lmc
.so
= open_fcc(fcc
, &fcc_cntxt
, 0, NULL
, NULL
))){
3784 /* ---- Open or allocation of fcc failed ----- */
3785 dprint((4,"can't open/allocate fcc, cont'g\n"));
3788 * Find field entry associated with fcc, and start
3791 for(pf
= header
.local
; pf
&& pf
->name
; pf
= pf
->next
)
3792 if(pf
->type
== Fcc
&& HE(pf
))
3793 HE(pf
)->start_here
= 1;
3798 so_truncate(lmc
.so
, fcc_size_guess(*body
) + 2048);
3803 /*---- Take care of any requested prefiltering ----*/
3804 if(sending_filter_requested
3805 && !filter_message_text(sending_filter_requested
, outgoing
,
3806 *body
, &orig_so
, &header
)){
3807 q_status_message1(SM_ORDER
, 3, 3,
3808 _("Problem filtering! Nothing sent%s."),
3809 fcc
? " or saved to fcc" : "");
3813 /*------ Actually post -------*/
3814 if(outgoing
->newsgroups
){
3815 char **alt_nntp
= NULL
, *alt_nntp_p
[2];
3816 if(((role
&& role
->nntp
)
3817 || suggested_nntp_server
)){
3818 if(ps_global
->FIX_NNTP_SERVER
3819 && ps_global
->FIX_NNTP_SERVER
[0])
3820 q_status_message(SM_ORDER
| SM_DING
, 5, 5,
3821 "Using nntp-server that is administratively fixed");
3822 else if(role
&& role
->nntp
)
3823 alt_nntp
= role
->nntp
;
3825 alt_nntp_p
[0] = suggested_nntp_server
;
3826 alt_nntp_p
[1] = NULL
;
3827 alt_nntp
= alt_nntp_p
;
3830 if(news_poster(&header
, *body
, alt_nntp
, pipe_callback
) < 0){
3831 dprint((1, "Post failed, continuing\n"));
3832 if(outgoing
->message_id
)
3833 fs_give((void **) &outgoing
->message_id
);
3835 outgoing
->message_id
= generate_message_id(role
);
3840 result
|= P_NEWS_WIN
;
3844 * BUG: IF we've posted the message *and* an fcc was specified
3845 * then we've already got a neatly formatted message in the
3846 * lmc.so. It'd be nice not to have to re-encode everything
3847 * to insert it into the smtp slot...
3851 * Turn on "undisclosed recipients" header if no To or cc.
3853 if(!(outgoing
->to
|| outgoing
->cc
)
3854 && (outgoing
->bcc
|| lcc_addr
) && pf_nobody
&& pf_nobody
->addr
){
3855 pf_nobody
->writehdr
= 1;
3856 pf_nobody
->localcopy
= 1;
3859 if(priority_requested
){
3860 (void) set_priority_header(&header
, priority_requested
);
3861 fs_give((void **) &priority_requested
);
3864 #if defined(BACKGROUND_POST) && defined(SIGCHLD)
3866 * If requested, launch background posting...
3868 if(background_requested
&& !(call_mailer_flags
& CM_VERBOSE
)){
3869 ps_global
->post
= (POST_S
*)fs_get(sizeof(POST_S
));
3870 memset(ps_global
->post
, 0, sizeof(POST_S
));
3872 ps_global
->post
->fcc
= cpystr(fcc
);
3874 if((ps_global
->post
->pid
= fork()) == 0){
3876 * Put us in new process group...
3878 setpgrp(0, ps_global
->post
->pid
);
3880 /* BUG: should fix argv[0] to indicate what we're up to */
3883 * If there are any live streams, pretend we never
3884 * knew them. Problem is two processes writing
3885 * same server process.
3886 * This is not clean but we're just going to exit
3887 * right away anyway. We just want to be sure to leave
3888 * the stuff that the parent is going to use alone.
3889 * The next three lines will disable the re-use of the
3890 * existing streams and cause us to open a new one if
3893 ps_global
->mail_stream
= NULL
;
3894 ps_global
->s_pool
.streams
= NULL
;
3895 ps_global
->s_pool
.nstream
= 0;
3897 /* quell any display output */
3898 ps_global
->in_init_seq
= 1;
3900 /*------- Actually mail the message ------*/
3901 if(valid_addr
== CA_OK
3902 && (outgoing
->to
|| outgoing
->cc
3903 || outgoing
->bcc
|| lcc_addr
)){
3904 char **alt_smtp
= NULL
;
3906 if(role
&& role
->smtp
){
3907 if(ps_global
->FIX_SMTP_SERVER
3908 && ps_global
->FIX_SMTP_SERVER
[0])
3909 q_status_message(SM_ORDER
| SM_DING
, 5, 5, "Use of a role-defined smtp-server is administratively prohibited");
3911 alt_smtp
= role
->smtp
;
3914 result
|= (call_mailer(&header
, *body
, alt_smtp
,
3916 call_mailer_file_result
,
3918 ? P_MAIL_WIN
: P_MAIL_LOSE
;
3920 if(result
& P_MAIL_LOSE
)
3921 mark_address_failure_for_pico(&header
);
3924 /*----- Was there an fcc involved? -----*/
3926 /*------ Write it if at least something worked ------*/
3927 if((result
& (P_MAIL_WIN
| P_NEWS_WIN
))
3928 || (!(result
& (P_MAIL_BITS
| P_NEWS_BITS
))
3929 && pine_rfc822_output(&header
, *body
,
3933 strncpy(label
, "Fcc", sizeof(label
));
3934 label
[sizeof(label
)-1] = '\0';
3935 if(strcmp(fcc
, ps_global
->VAR_DEFAULT_FCC
)){
3936 snprintf(label
+ 3, sizeof(label
)-3, " to %s", fcc
);
3937 label
[sizeof(label
)-1] = '\0';
3940 /*-- Now actually copy to fcc folder and close --*/
3941 result
|= (write_fcc(fcc
, fcc_cntxt
, lmc
.so
,
3943 F_ON(F_MARK_FCC_SEEN
, ps_global
)
3945 ? P_FCC_WIN
: P_FCC_LOSE
;
3947 else if(!(result
& (P_MAIL_BITS
| P_NEWS_BITS
))){
3948 q_status_message(SM_ORDER
, 3, 5,
3949 _("Fcc Failed!. No message saved."));
3951 "explicit fcc write failed!\n"));
3952 result
|= P_FCC_LOSE
;
3958 if(result
& (P_MAIL_LOSE
| P_NEWS_LOSE
| P_FCC_LOSE
)){
3960 * Encode child's result in hi-byte of
3963 editor_result
= ((result
<< 8) | COMP_GOTHUP
);
3970 if(ps_global
->post
->pid
> 0){
3971 q_status_message(SM_ORDER
, 3, 3,
3972 _("Message handed off for posting"));
3973 break; /* up to our child now */
3976 q_status_message1(SM_ORDER
| SM_DING
, 3, 3,
3977 "Can't fork for send: %s",
3978 error_description(errno
));
3979 if(ps_global
->post
->fcc
)
3980 fs_give((void **) &ps_global
->post
->fcc
);
3982 fs_give((void **) &ps_global
->post
);
3985 if(lmc
.so
) /* throw away unused store obj */
3988 if(outgoing
->message_id
)
3989 fs_give((void **) &outgoing
->message_id
);
3991 outgoing
->message_id
= generate_message_id(role
);
3993 continue; /* if we got here, there was a prob */
3995 #endif /* BACKGROUND_POST */
3997 /*------- Actually mail the message ------*/
3998 if(valid_addr
== CA_OK
3999 && (outgoing
->to
|| outgoing
->cc
|| outgoing
->bcc
|| lcc_addr
)){
4000 char **alt_smtp
= NULL
;
4002 if(role
&& role
->smtp
){
4003 if(ps_global
->FIX_SMTP_SERVER
4004 && ps_global
->FIX_SMTP_SERVER
[0])
4005 q_status_message(SM_ORDER
| SM_DING
, 5, 5, "Use of a role-defined smtp-server is administratively prohibited");
4007 alt_smtp
= role
->smtp
;
4010 result
|= (call_mailer(&header
, *body
, alt_smtp
,
4012 call_mailer_file_result
,
4014 ? P_MAIL_WIN
: P_MAIL_LOSE
;
4016 if(result
& P_MAIL_LOSE
)
4017 mark_address_failure_for_pico(&header
);
4020 /*----- Was there an fcc involved? -----*/
4022 /*------ Write it if at least something worked ------*/
4023 if((result
& (P_MAIL_WIN
| P_NEWS_WIN
))
4024 || (!(result
& (P_MAIL_BITS
| P_NEWS_BITS
))
4025 && pine_rfc822_output(&header
, *body
, NULL
, NULL
))){
4028 strncpy(label
, "Fcc", sizeof(label
));
4029 label
[sizeof(label
)-1] = '\0';
4030 if(strcmp(fcc
, ps_global
->VAR_DEFAULT_FCC
)){
4031 snprintf(label
+ 3, sizeof(label
)-3, " to %s", fcc
);
4032 label
[sizeof(label
)-1] = '\0';
4035 /*-- Now actually copy to fcc folder and close --*/
4036 result
|= (write_fcc(fcc
, fcc_cntxt
, lmc
.so
, NULL
, label
,
4037 F_ON(F_MARK_FCC_SEEN
, ps_global
)
4039 ? P_FCC_WIN
: P_FCC_LOSE
;
4041 else if(!(result
& (P_MAIL_BITS
| P_NEWS_BITS
))){
4042 q_status_message(SM_ORDER
,3,5,
4043 _("Fcc Failed!. No message saved."));
4044 dprint((1, "explicit fcc write failed!\n"));
4045 result
|= P_FCC_LOSE
;
4051 /*----- Mail Post FAILED, back to composer -----*/
4052 if(result
& (P_MAIL_LOSE
| P_FCC_LOSE
)){
4053 dprint((1, "Send failed, continuing\n"));
4055 if(result
& P_FCC_LOSE
){
4057 * Find field entry associated with fcc, and start
4060 for(pf
= header
.local
; pf
&& pf
->name
; pf
= pf
->next
)
4061 if(pf
->type
== Fcc
&& HE(pf
))
4062 HE(pf
)->start_here
= 1;
4064 q_status_message(SM_ORDER
| SM_DING
, 3, 3,
4065 pine_send_status(result
, fcc
,
4066 tmp_20k_buf
, SIZEOF_20KBUF
, NULL
));
4069 if(outgoing
->message_id
)
4070 fs_give((void **) &outgoing
->message_id
);
4072 outgoing
->message_id
= generate_message_id(role
);
4078 * If message sent *completely* successfully, there's a
4079 * reply struct AND we're allowed to write back state, do it.
4080 * But also protect against shifted message numbers due
4081 * to new mail arrival. Since the number passed is based
4082 * on the real imap msg no, AND we're sure no expunge has
4083 * been done, just fix up the sorted number...
4085 update_answered_flags(reply
);
4087 /*----- Signed, sealed, delivered! ------*/
4088 q_status_message(SM_ORDER
, 0, 3,
4089 pine_send_status(result
, fcc
, tmp_20k_buf
, SIZEOF_20KBUF
, NULL
));
4091 break; /* All's well, pop out of here */
4099 fs_give((void **)&fcc
);
4101 free_body_particulars(bp
);
4103 free_attachment_list(&pbf
->attachments
);
4105 standard_picobuf_teardown(pbf
);
4107 for(i
=0; i
< fixed_cnt
; i
++){
4108 if(pfields
[i
].textbuf
)
4109 fs_give((void **)&pfields
[i
].textbuf
);
4111 fs_give((void **)&pfields
[i
].name
);
4115 mail_free_address(&lcc_addr
);
4118 mail_free_address(&nobody_addr
);
4120 free_prompts(header
.custom
);
4121 free_customs(header
.custom
);
4122 fs_give((void **)&pfields
);
4123 free_headents(&headents
);
4124 fs_give((void **)&sending_order
);
4125 if(suggested_nntp_server
)
4126 fs_give((void **)&suggested_nntp_server
);
4128 fs_give((void **)&title
);
4130 if(local_redraft_pos
&& local_redraft_pos
!= redraft_pos
)
4131 free_redraft_pos(&local_redraft_pos
);
4133 pbf
= save_previous_pbuf
;
4136 dprint((4, "=== send returning ===\n"));
4141 * Check for subject in outgoing message.
4143 * Asks user whether to proceed with no subject.
4146 check_for_subject(METAENV
*header
)
4151 for(pf
= header
->local
; pf
&& pf
->name
; pf
= pf
->next
)
4152 if(pf
->type
== Subject
){
4153 if(pf
->text
&& *pf
->text
&& **pf
->text
)
4156 if(want_to("No Subject, send anyway ",
4157 'n', 'n', h_send_check_subj
, WT_NORM
) == 'y')
4172 * Check for fcc in outgoing message.
4174 * Asks user whether to proceed with no fcc.
4177 check_for_fcc(char *fcc
)
4184 if(want_to("No Fcc, send anyway ", 'n', 'n', h_send_check_fcc
, WT_NORM
) == 'y')
4195 * Confirm that the user wants to send to MAILER-DAEMON
4198 confirm_daemon_send(void)
4200 return(want_to("Really send this message to the MAILER-DAEMON",
4201 'n', 'n', NO_HELP
, WT_NORM
) == 'y');
4206 free_prompts(PINEFIELD
*head
)
4210 for(pf
= head
; pf
&& pf
->name
; pf
= pf
->next
){
4211 if(HE(pf
) && HE(pf
)->prompt
)
4212 fs_give((void **)& HE(pf
)->prompt
);
4218 postpone_prompt(void)
4220 static ESCKEY_S pstpn_form_opt
[] = { {'p', 'p', "P", N_("Postponed Folder")},
4221 {'f', 'f', "F", N_("Form Letter Folder")},
4222 {-1, 0, NULL
, NULL
} };
4224 return(radio_buttons(PSTPN_FORM_PMT
, -FOOTER_ROWS(ps_global
),
4225 pstpn_form_opt
, 'p', 0, NO_HELP
, RB_FLUSH_IN
));
4230 * call__mailer_file_result - some results from call_mailer might be in a file.
4231 * dislplay that file.
4234 call_mailer_file_result(char *filename
, int style
)
4237 if(style
& CM_BR_VERBOSE
){
4238 display_output_file(filename
, "Verbose SMTP Interaction", NULL
, DOF_BRIEF
);
4241 display_output_file(filename
, "POSTING ERRORS", "Posting Error", DOF_EMPTY
);
4247 mark_address_failure_for_pico(METAENV
*header
)
4251 int error_count
= 0;
4252 struct headerentry
*last_he
= NULL
;
4254 for(pf
= header
->local
; pf
&& pf
->name
; pf
= pf
->next
)
4255 if(pf
->type
== Address
&& pf
->rcptto
&& pf
->addr
&& *pf
->addr
)
4256 for(a
= *pf
->addr
; a
!= NULL
; a
= a
->next
)
4258 && error_count
++ < MAX_ADDR_ERROR
4260 if(last_he
) /* start last reported err */
4261 last_he
->start_here
= 0;
4263 (last_he
= HE(pf
))->start_here
= 1;
4270 * This is specialized routine. It assumes that the only things that we
4271 * care about restoring are the body type, subtype, encoding and the
4272 * state of the charset parameter. It also assumes that if the charset
4273 * parameter exists when we save it, it won't be removed later.
4275 BODY_PARTICULARS_S
*
4276 save_body_particulars(struct mail_bodystruct
*body
)
4278 BODY_PARTICULARS_S
*bp
;
4281 bp
= (BODY_PARTICULARS_S
*)fs_get(sizeof(BODY_PARTICULARS_S
));
4283 bp
->type
= body
->type
;
4284 bp
->encoding
= body
->encoding
;
4285 bp
->subtype
= body
->subtype
? cpystr(body
->subtype
) : NULL
;
4286 bp
->parameter
= body
->parameter
;
4287 for(pm
= bp
->parameter
;
4288 pm
&& strucmp(pm
->attribute
, "charset") != 0;
4290 ;/* searching for possible charset parameter */
4292 if(pm
){ /* found one */
4293 bp
->had_csp
= 1; /* saved body had charset parameter */
4294 bp
->charset
= pm
->value
? cpystr(pm
->value
) : NULL
;
4306 reset_body_particulars(BODY_PARTICULARS_S
*bp
, struct mail_bodystruct
*body
)
4308 body
->type
= bp
->type
;
4309 body
->encoding
= bp
->encoding
;
4311 fs_give((void **)&body
->subtype
);
4313 body
->subtype
= bp
->subtype
? cpystr(bp
->subtype
) : NULL
;
4316 PARAMETER
*pm
, *pm_prev
= NULL
;
4318 for(pm
= body
->parameter
;
4319 pm
&& strucmp(pm
->attribute
, "charset") != 0;
4323 if(pm
){ /* body has charset parameter */
4324 if(bp
->had_csp
){ /* reset to what it used to be */
4326 fs_give((void **)&pm
->value
);
4328 pm
->value
= bp
->charset
? cpystr(bp
->charset
) : NULL
;
4330 else{ /* remove charset parameter */
4332 pm_prev
->next
= pm
->next
;
4334 body
->parameter
= pm
->next
;
4336 mail_free_body_parameter(&pm
);
4342 * This can't happen because grope never removes
4343 * the charset parameter.
4345 q_status_message(SM_ORDER
| SM_DING
, 5, 5,
4346 "Programmer error: saved charset but no current charset param in pine_send");
4350 ok, still no parameter
4357 mail_free_body_parameter(&body
->parameter
);
4359 body
->parameter
= NULL
;
4365 free_body_particulars(BODY_PARTICULARS_S
*bp
)
4369 fs_give((void **)&bp
->subtype
);
4372 fs_give((void **)&bp
->charset
);
4374 fs_give((void **)&bp
);
4379 /*----------------------------------------------------------------------
4380 Build a status message suitable for framing
4382 Returns: pointer to resulting buffer
4385 pine_send_status(int result
, char *fcc_name
, char *buf
, size_t buflen
, int *goodorbad
)
4387 int avail
= ps_global
->ttyo
->screen_cols
- 2;
4388 int fixedneed
, need
, lenfcc
;
4389 char *part1
, *part2
, *part3
, *part4
, *part5
;
4390 char fbuf
[MAILTMPLEN
+1];
4392 part1
= (result
& P_NEWS_WIN
)
4394 : (result
& P_NEWS_LOSE
)
4397 part2
= ((result
& P_NEWS_BITS
) && (result
& P_MAIL_BITS
)
4398 && (result
& P_FCC_BITS
))
4400 : ((result
& P_NEWS_BITS
) && (result
& (P_MAIL_BITS
| P_FCC_BITS
)))
4403 part3
= (result
& P_MAIL_WIN
)
4405 : (result
& P_MAIL_LOSE
)
4408 part4
= ((result
& P_MAIL_BITS
) && (result
& P_FCC_BITS
))
4411 part5
= ((result
& P_FCC_WIN
) && !(result
& (P_MAIL_WIN
| P_NEWS_WIN
)))
4413 : (result
& P_FCC_WIN
)
4415 : (result
& P_FCC_LOSE
)
4418 lenfcc
= MIN(sizeof(fbuf
)-1, (result
& P_FCC_BITS
) ? strlen(fcc_name
) : 0);
4420 fixedneed
= 9 + strlen(part1
) + strlen(part2
) + strlen(part3
) +
4421 strlen(part4
) + strlen(part5
);
4422 need
= fixedneed
+ ((result
& P_FCC_BITS
) ? 2 : 0) + lenfcc
;
4424 if(need
> avail
&& fixedneed
+ 3 >= avail
){
4425 /* dots on end of fixed, no fcc */
4426 snprintf(fbuf
, sizeof(fbuf
), "Message %s%s%s%s%s ",
4427 part1
, part2
, part3
, part4
, part5
);
4428 short_str(fbuf
, buf
, buflen
, avail
, EndDots
);
4430 else if(need
> avail
){
4431 /* include whole fixed part, quotes and dots at end of fcc name */
4433 lenfcc
= MAX(1, lenfcc
-(need
-avail
));
4435 snprintf(buf
, buflen
, "Message %s%s%s%s%s%s%s%s.",
4436 part1
, part2
, part3
, part4
, part5
,
4437 (result
& P_FCC_BITS
) ? "\"" : "",
4438 short_str((result
& P_FCC_BITS
) ? fcc_name
: "",
4439 fbuf
, sizeof(fbuf
), lenfcc
, FrontDots
),
4440 (result
& P_FCC_BITS
) ? "\"" : "");
4444 snprintf(buf
, buflen
, "Message %s%s%s%s%s%s%s%s.",
4445 part1
, part2
, part3
, part4
, part5
,
4446 (result
& P_FCC_BITS
) ? "\"" : "",
4447 (result
& P_FCC_BITS
) ? fcc_name
: "",
4448 (result
& P_FCC_BITS
) ? "\"" : "");
4452 *goodorbad
= (result
& (P_MAIL_LOSE
| P_NEWS_LOSE
| P_FCC_LOSE
)) == 0;
4457 /* Callback from Pico to set the conditions for Alpine to start a new thread
4461 new_thread_on_blank_subject(void)
4463 ps_global
->newthread
= F_ON(F_NEW_THREAD_ON_BLANK_SUBJECT
, ps_global
);
4468 /*----------------------------------------------------------------------
4469 Call back for pico to insert the specified message's text
4471 Args: n -- message number to format
4472 f -- function to use to output the formatted message
4475 Returns: returns msg number formatted on success, zero on error.
4478 message_format_for_pico(long int n
, int (*f
) (int))
4482 char *old_quote
= NULL
;
4485 if(!(n
> 0L && n
<= mn_get_total(ps_global
->msgmap
)
4486 && (e
= pine_mail_fetchstructure(ps_global
->mail_stream
,
4487 mn_m2raw(ps_global
->msgmap
, n
), &b
)))){
4488 q_status_message(SM_ORDER
|SM_DING
,3,3,"Error inserting Message");
4489 flush_status_messages(0);
4493 /* temporarily assign a new quote string */
4494 old_quote
= pbf
->quote_str
;
4495 pbf
->quote_str
= reply_quote_str(e
);
4497 /* build separator line */
4498 reply_delimiter(e
, NULL
, f
);
4500 /* actually write message text */
4501 if(!format_message(mn_m2raw(ps_global
->msgmap
, n
), e
, b
, NULL
,
4502 FM_NEW_MESS
| FM_DISPLAY
| FM_NOCOLOR
| FM_NOINDENT
, f
)){
4503 q_status_message(SM_ORDER
|SM_DING
,3,3,"Error inserting Message");
4504 flush_status_messages(0);
4508 fs_give((void **)&pbf
->quote_str
);
4509 pbf
->quote_str
= old_quote
;
4514 /*----------------------------------------------------------------------
4515 Call back for pico to prompt the user for exit confirmation
4517 Args: dflt -- default answer for confirmation prompt
4519 Returns: either NULL if the user accepts exit, or string containing
4520 reason why the user declined.
4523 send_exit_for_pico(struct headerentry
*he
, void (*redraw_pico
)(void), int allow_flowed
,
4526 int i
, rv
, c
, verbose_label
= 0, bg_label
= 0, old_suspend
;
4527 int dsn_label
= 0, fcc_label
= 0, lparen
;
4528 int flowing_label
= 0, double_rad
;
4529 char *rstr
= NULL
, *p
, *lc
, *optp
;
4530 char dsn_string
[30];
4531 void (*redraw
)(void) = ps_global
->redrawer
;
4536 struct filters
*prev
, *next
;
4537 } *filters
= NULL
, *fp
;
4539 sending_filter_requested
= NULL
;
4540 call_mailer_flags
= 0;
4541 background_requested
= 0;
4542 flowing_requested
= allow_flowed
? 1 : 0;
4543 lmc
.text_only
= F_ON(F_NO_FCC_ATTACH
, ps_global
) != 0;
4544 if(priority_requested
)
4545 fs_give((void **) &priority_requested
);
4547 if(background_posting(FALSE
)){
4549 *result
= "Can't send while background posting. Use postpone.";
4554 if(F_ON(F_SEND_WO_CONFIRM
, ps_global
)){
4561 ps_global
->redrawer
= redraw_pico
;
4563 if((old_suspend
= F_ON(F_CAN_SUSPEND
, ps_global
)) != 0)
4564 (void) F_SET(F_CAN_SUSPEND
, ps_global
, 0);
4567 * Build list of available filters...
4569 for(i
=0; ps_global
->VAR_SEND_FILTER
&& ps_global
->VAR_SEND_FILTER
[i
]; i
++){
4570 for(p
= ps_global
->VAR_SEND_FILTER
[i
];
4571 *p
&& !isspace((unsigned char)*p
); p
++)
4576 if(!(is_absolute_path(ps_global
->VAR_SEND_FILTER
[i
])
4577 && can_access(ps_global
->VAR_SEND_FILTER
[i
],EXECUTE_ACCESS
) ==0)){
4582 fp
= (struct filters
*)fs_get(sizeof(struct filters
));
4584 if((lc
= last_cmpnt(ps_global
->VAR_SEND_FILTER
[i
])) != NULL
){
4585 fp
->filter
= cpystr(lc
);
4587 else if((p
- ps_global
->VAR_SEND_FILTER
[i
]) > 20){
4588 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, "...%s", p
- 17);
4589 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
4590 fp
->filter
= cpystr(tmp_20k_buf
);
4593 fp
->filter
= cpystr(ps_global
->VAR_SEND_FILTER
[i
]);
4599 fp
->prev
= filters
->prev
;
4600 fp
->prev
->next
= filters
->prev
= fp
;
4603 filters
= (struct filters
*)fs_get(sizeof(struct filters
));
4604 filters
->index
= -1;
4605 filters
->filter
= NULL
;
4606 filters
->next
= filters
->prev
= fp
;
4607 fp
->next
= fp
->prev
= filters
;
4615 opts
[i
++].label
= N_("Yes");
4620 opts
[i
++].label
= N_("No");
4623 /* set global_filter_pointer to desired filter or NULL if none */
4624 /* prepare two keymenu slots for selecting filter */
4625 opts
[i
].ch
= ctrl('P');
4627 opts
[i
].name
= "^P";
4628 opts
[i
++].label
= N_("Prev Filter");
4630 opts
[i
].ch
= ctrl('N');
4632 opts
[i
].name
= "^N";
4633 opts
[i
++].label
= N_("Next Filter");
4635 if(F_ON(F_FIRST_SEND_FILTER_DFLT
, ps_global
))
4636 filters
= filters
->next
;
4639 if(F_ON(F_VERBOSE_POST
, ps_global
)){
4640 /* setup keymenu slot to toggle verbose mode */
4641 opts
[i
].ch
= ctrl('W');
4643 opts
[i
].name
= "^W";
4644 verbose_label
= i
++;
4648 /* setup keymenu slot to toggle flowed mode */
4649 opts
[i
].ch
= ctrl('V');
4651 opts
[i
].name
= "^V";
4652 flowing_label
= i
++;
4653 flowing_requested
= 1;
4656 if(F_ON(F_NO_FCC_ATTACH
, ps_global
)){
4657 /* setup keymenu slot to toggle attacment on fcc */
4658 opts
[i
].ch
= ctrl('F');
4660 opts
[i
].name
= "^F";
4664 #if defined(BACKGROUND_POST) && defined(SIGCHLD)
4665 if(F_ON(F_BACKGROUND_POST
, ps_global
)){
4666 opts
[i
].ch
= ctrl('R');
4668 opts
[i
].name
= "^R";
4676 opts
[i
++].label
= N_("Priority");
4679 if(F_OFF(F_DONT_DO_SMIME
, ps_global
)){
4683 opts
[i
++].label
= "Encrypt";
4688 opts
[i
++].label
= "Sign";
4690 if(ps_global
->smime
){
4691 ps_global
->smime
->do_encrypt
= F_ON(F_ENCRYPT_DEFAULT_ON
, ps_global
);
4692 ps_global
->smime
->do_sign
= F_ON(F_SIGN_DEFAULT_ON
, ps_global
);
4699 if(F_ON(F_DSN
, ps_global
)){
4700 /* setup keymenu slots to toggle dsn bits */
4704 opts
[i
].label
= N_("DSNOpts");
4709 opts
[i
++].label
= "";
4713 opts
[i
++].label
= "";
4717 opts
[i
++].label
= "";
4721 opts
[i
].ch
= KEY_UP
;
4724 opts
[i
++].label
= "";
4726 opts
[i
].ch
= KEY_DOWN
;
4729 opts
[i
++].label
= "";
4734 fix_windsize(ps_global
);
4737 if(filters
&& filters
->filter
&& (p
= strindex(filters
->filter
, ' ')))
4743 strncpy(tmp_20k_buf
, "Send message", SIZEOF_20KBUF
);
4744 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
4745 optp
= tmp_20k_buf
+ strlen(tmp_20k_buf
);
4747 if(F_ON(F_NO_FCC_ATTACH
, ps_global
) && !lmc
.text_only
)
4748 sstrncpy(&optp
, " and Fcc Atmts", SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4750 if(allow_flowed
&& !flowing_requested
){
4751 if((optp
-tmp_20k_buf
)+2 < SIZEOF_20KBUF
){
4761 sstrncpy(&optp
, "not flowed", SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4765 if((optp
-tmp_20k_buf
)+2 < SIZEOF_20KBUF
){
4777 if(filters
->filter
){
4778 sstrncpy(&optp
, "filtered thru \"", SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4779 sstrncpy(&optp
, filters
->filter
, SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4780 if((optp
-tmp_20k_buf
) < SIZEOF_20KBUF
)
4784 sstrncpy(&optp
, "unfiltered", SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4787 if((call_mailer_flags
& CM_VERBOSE
) || background_requested
){
4788 if((optp
-tmp_20k_buf
)+2 < SIZEOF_20KBUF
){
4798 sstrncpy(&optp
, "in ", SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4799 if(call_mailer_flags
& CM_VERBOSE
)
4800 sstrncpy(&optp
, "verbose ", SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4802 if(background_requested
)
4803 sstrncpy(&optp
, "background ", SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4805 sstrncpy(&optp
, "mode", SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4808 if(g_rolenick
&& !(he
&& he
[N_FROM
].dirty
)){
4809 if((optp
-tmp_20k_buf
)+2 < SIZEOF_20KBUF
){
4819 sstrncpy(&optp
, "as \"", SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4820 sstrncpy(&optp
, g_rolenick
, SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4821 sstrncpy(&optp
, "\"", SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4824 if(call_mailer_flags
& CM_DSN_SHOW
){
4825 if((optp
-tmp_20k_buf
)+2 < SIZEOF_20KBUF
){
4837 sstrncpy(&optp
, dsn_string
, SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4841 if(ps_global
->smime
&& ps_global
->smime
->do_encrypt
){
4842 if((optp
-tmp_20k_buf
)+2 < SIZEOF_20KBUF
){
4854 sstrncpy(&optp
, "Encrypted", SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4857 if(ps_global
->smime
&& ps_global
->smime
->do_sign
){
4858 if((optp
-tmp_20k_buf
)+2 < SIZEOF_20KBUF
){
4870 sstrncpy(&optp
, "Signed", SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4874 if(lparen
&& (optp
-tmp_20k_buf
) < SIZEOF_20KBUF
)
4877 sstrncpy(&optp
, "? ", SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4878 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
4884 opts
[flowing_label
].label
= flowing_requested
? N_("NoFlow") : N_("Flow");
4887 opts
[verbose_label
].label
= (call_mailer_flags
& CM_VERBOSE
) ? N_("Normal") : N_("Verbose");
4890 opts
[bg_label
].label
= background_requested
4891 ? N_("Foreground") : N_("Background");
4894 opts
[fcc_label
].label
= lmc
.text_only
? N_("Fcc Attchmnts")
4895 : N_("No Fcc Atmts ");
4897 if(F_ON(F_DSN
, ps_global
)){
4898 if(call_mailer_flags
& CM_DSN_SHOW
){
4899 opts
[dsn_label
].label
= (call_mailer_flags
& CM_DSN_DELAY
)
4900 ? N_("NoDelay") : N_("Delay");
4901 opts
[dsn_label
+1].ch
= 's';
4902 opts
[dsn_label
+1].label
= (call_mailer_flags
& CM_DSN_SUCCESS
)
4903 ? N_("NoSuccess") : N_("Success");
4904 opts
[dsn_label
+2].ch
= 'x';
4905 opts
[dsn_label
+2].label
= (call_mailer_flags
& CM_DSN_NEVER
)
4906 ? N_("ErrRets") : N_("NoErrRets");
4907 opts
[dsn_label
+3].ch
= 'h';
4908 opts
[dsn_label
+3].label
= (call_mailer_flags
& CM_DSN_FULL
)
4909 ? N_("RetHdrs") : N_("RetFull");
4914 ((call_mailer_flags
& CM_DSN_SHOW
)
4915 ? 4 : F_ON(F_DSN
, ps_global
) ? 1 : 0) > 11)
4916 rv
= double_radio_buttons(tmp_20k_buf
, -FOOTER_ROWS(ps_global
), opts
,
4918 (F_ON(F_DSN
, ps_global
) && allow_flowed
)
4919 ? h_send_prompt_dsn_flowed
:
4920 F_ON(F_DSN
, ps_global
) ? h_send_prompt_dsn
:
4921 allow_flowed
? h_send_prompt_flowed
:
4925 rv
= radio_buttons(tmp_20k_buf
, -FOOTER_ROWS(ps_global
), opts
,
4928 ((call_mailer_flags
& CM_DSN_SHOW
)
4929 ? 4 : F_ON(F_DSN
, ps_global
) ? 1 : 0) == 11)
4931 (F_ON(F_DSN
, ps_global
) && allow_flowed
)
4932 ? h_send_prompt_dsn_flowed
:
4933 F_ON(F_DSN
, ps_global
) ? h_send_prompt_dsn
:
4934 allow_flowed
? h_send_prompt_flowed
:
4938 if(rv
== 'y'){ /* user ACCEPTS! */
4941 else if(rv
== 'n'){ /* Declined! */
4942 rstr
= _("No Message Sent");
4945 else if(rv
== 'z'){ /* Cancelled! */
4946 rstr
= _("Send Cancelled");
4949 else if(rv
== 10){ /* PREVIOUS filter */
4950 filters
= filters
->prev
;
4952 else if(rv
== 11){ /* NEXT filter */
4953 filters
= filters
->next
;
4956 lmc
.text_only
= !lmc
.text_only
;
4958 else if(rv
== 12){ /* flip verbose bit */
4959 if(call_mailer_flags
& CM_VERBOSE
)
4960 call_mailer_flags
&= ~CM_VERBOSE
;
4962 call_mailer_flags
|= CM_VERBOSE
;
4964 if((call_mailer_flags
& CM_VERBOSE
) && background_requested
)
4965 background_requested
= 0;
4967 else if(rv
== 22){ /* flip flowing bit */
4968 flowing_requested
= !flowing_requested
;
4971 if((background_requested
= !background_requested
)
4972 && (call_mailer_flags
& CM_VERBOSE
))
4973 call_mailer_flags
&= ~CM_VERBOSE
; /* clear verbose */
4975 else if(call_mailer_flags
& CM_DSN_SHOW
){
4976 if(rv
== 's'){ /* flip success bit */
4977 call_mailer_flags
^= CM_DSN_SUCCESS
;
4978 /* turn off related bits */
4979 if(call_mailer_flags
& CM_DSN_SUCCESS
)
4980 call_mailer_flags
&= ~(CM_DSN_NEVER
);
4982 else if(rv
== 'd'){ /* flip delay bit */
4983 call_mailer_flags
^= CM_DSN_DELAY
;
4984 /* turn off related bits */
4985 if(call_mailer_flags
& CM_DSN_DELAY
)
4986 call_mailer_flags
&= ~(CM_DSN_NEVER
);
4988 else if(rv
== 'x'){ /* flip never bit */
4989 call_mailer_flags
^= CM_DSN_NEVER
;
4990 /* turn off related bits */
4991 if(call_mailer_flags
& CM_DSN_NEVER
)
4992 call_mailer_flags
&= ~(CM_DSN_SUCCESS
| CM_DSN_DELAY
);
4994 else if(rv
== 'h'){ /* flip full bit */
4995 call_mailer_flags
^= CM_DSN_FULL
;
4998 else if(rv
== 'd'){ /* show dsn options */
5000 * When you turn on DSN, the default is to notify on
5001 * failure, success, or delay; and to return the whole
5004 call_mailer_flags
|= (CM_DSN_SHOW
| CM_DSN_SUCCESS
| CM_DSN_DELAY
| CM_DSN_FULL
);
5006 else if(rv
== 'p'){ /* choose X-Priority */
5009 prio
= choose_a_priority(priority_requested
);
5010 if((ps_global
->redrawer
= redraw_pico
) != NULL
){
5011 (*ps_global
->redrawer
)();
5012 fix_windsize(ps_global
);
5016 if(priority_requested
)
5017 fs_give((void **) &priority_requested
);
5020 priority_requested
= prio
;
5022 fs_give((void **) &prio
);
5027 if(ps_global
->smime
)
5028 ps_global
->smime
->do_encrypt
= !ps_global
->smime
->do_encrypt
;
5031 if(ps_global
->smime
)
5032 ps_global
->smime
->do_sign
= !ps_global
->smime
->do_sign
;
5036 snprintf(dsn_string
, sizeof(dsn_string
), "DSN requested[%s%s%s%s]",
5037 (call_mailer_flags
& CM_DSN_NEVER
)
5039 (call_mailer_flags
& CM_DSN_DELAY
)
5041 (call_mailer_flags
& CM_DSN_SUCCESS
)
5043 (call_mailer_flags
& CM_DSN_NEVER
)
5045 : (call_mailer_flags
& CM_DSN_FULL
) ? "-Full"
5047 dsn_string
[sizeof(dsn_string
)-1] = '\0';
5050 /* remember selection */
5051 if(filters
&& filters
->index
> -1)
5052 sending_filter_requested
= ps_global
->VAR_SEND_FILTER
[filters
->index
];
5055 filters
->prev
->next
= NULL
; /* tie off list */
5056 while(filters
){ /* then free it */
5059 fs_give((void **)&filters
->filter
);
5061 fs_give((void **)&filters
);
5067 (void) F_SET(F_CAN_SUSPEND
, ps_global
, 1);
5072 ps_global
->redrawer
= redraw
;
5074 return((rstr
== NULL
) ? 0 : 1);
5079 * Allow user to choose a priority for sending.
5081 * Returns an allocated priority on success, NULL otherwise.
5084 choose_a_priority(char *default_val
)
5086 char *choice
= NULL
;
5087 char **priority_list
, **lp
;
5088 char *starting_val
= NULL
;
5093 for(cnt
= 0, p
= priorities
; p
&& p
->desc
; p
++)
5096 cnt
++; /* for NONE entry */
5097 lp
= priority_list
= (char **) fs_get((cnt
+ 1) * sizeof(*priority_list
));
5098 memset(priority_list
, 0, (cnt
+1) * sizeof(*priority_list
));
5100 for(i
= 0, p
= priorities
; p
&& p
->desc
; p
++){
5101 *lp
= cpystr(p
->desc
);
5102 if(default_val
&& !strcmp(default_val
, p
->desc
))
5103 starting_val
= (*lp
);
5108 none
= _("NONE - No X-Priority header included");
5111 starting_val
= (*lp
);
5113 /* TRANSLATORS: SELECT A PRIORITY is a screen title
5114 TRANSLATORS: Print something1 using something2.
5115 "priorities" is something1 */
5116 choice
= choose_item_from_list(priority_list
, NULL
, _("SELECT A PRIORITY"),
5117 _("priorities"), h_select_priority_screen
,
5118 _("HELP FOR SELECTING A PRIORITY"),
5122 q_status_message(SM_ORDER
, 1, 4, _("No change"));
5123 else if(!strcmp(choice
, none
))
5126 free_list_array(&priority_list
);
5133 dont_flow_this_time(void)
5135 return(flowing_requested
? 0 : 1);
5139 /*----------------------------------------------------------------------
5140 Call back for pico to display mime type of attachment
5142 Args: file -- filename being attached
5144 Returns: returns 1 on success (message queued), zero otherwise (don't know
5145 type so nothing queued).
5148 mime_type_for_pico(char *file
)
5152 void *file_contents
;
5154 body
= mail_newbody();
5155 body
->type
= TYPEOTHER
;
5156 body
->encoding
= ENCOTHER
;
5158 /* don't know where the cursor's been, reset it */
5160 if(!set_mime_type_by_extension(body
, file
)){
5161 if((file_contents
=(void *)so_get(FileStar
,file
,READ_ACCESS
|READ_FROM_LOCALE
)) != NULL
){
5162 body
->contents
.text
.data
= file_contents
;
5163 set_mime_type_by_grope(body
);
5167 if(body
->type
!= TYPEOTHER
){
5169 q_status_message3(SM_ORDER
, 0, 3,
5170 _("File %s attached as type %s/%s"), file
,
5171 body_types
[body
->type
],
5172 body
->subtype
? body
->subtype
: rfc822_default_subtype(body
->type
));
5177 pine_free_body(&body
);
5182 /*----------------------------------------------------------------------
5183 Call back for pico to receive an uploaded message
5185 Args: fname -- name for uploaded file (empty if they want us to assign it)
5186 size -- pointer to long to hold the attachment's size
5188 Notes: the attachment is uploaded to a temp file, and
5190 Returns: TRUE on success, FALSE otherwise
5193 upload_msg_to_pico(char *fname
, size_t fnlen
, long int *size
)
5195 char cmd
[MAXPATH
+1], *fnp
= NULL
;
5196 char *locale_name
= NULL
;
5200 dprint((1, "Upload cmd called to xfer \"%s\"\n",
5201 fname
? fname
: "<NO FILE>"));
5203 if(!fname
) /* no place for file name */
5206 if(!*fname
){ /* caller wants temp file */
5207 if((fnp
= temp_nam(NULL
, "pu")) != NULL
){
5208 strncpy(fname
, fnp
, fnlen
);
5209 fname
[fnlen
-1] = '\0';
5211 fs_give((void **)&fnp
);
5215 locale_name
= convert_to_locale(fname
);
5217 build_updown_cmd(cmd
, sizeof(cmd
), ps_global
->VAR_UPLOAD_CMD_PREFIX
,
5218 ps_global
->VAR_UPLOAD_CMD
, locale_name
? locale_name
: fname
);
5219 if((syspipe
= open_system_pipe(cmd
, NULL
, NULL
, PIPE_USER
| PIPE_RESET
,
5220 0, pipe_callback
, pipe_report_error
)) != NULL
){
5221 (void) close_system_pipe(&syspipe
, NULL
, pipe_callback
);
5222 if((l
= name_file_size(locale_name
? locale_name
: fname
)) < 0L){
5223 q_status_message2(SM_ORDER
| SM_DING
, 3, 4,
5224 "Error determining size of %s: %s", fname
,
5225 fnp
= error_description(errno
));
5227 "!!! Upload cmd \"%s\" failed for \"%s\": %s\n",
5229 fname
? fname
: "?",
5236 fs_give((void **) &locale_name
);
5241 q_status_message(SM_ORDER
| SM_DING
, 3, 4, _("Error opening pipe"));
5244 fs_give((void **) &locale_name
);
5251 cancel_for_pico(void (*redraw_pico
)(void))
5256 _("Cancel message (answering \"Confirm\" will abandon your mail message) ? ");
5257 void (*redraw
)(void) = ps_global
->redrawer
;
5258 static ESCKEY_S opts
[] = {
5259 {'c', 'c', "C", N_("Confirm")},
5260 {'n', 'n', "N", N_("No")},
5265 ps_global
->redrawer
= redraw_pico
;
5266 fix_windsize(ps_global
);
5269 rv
= radio_buttons(prompt
, -FOOTER_ROWS(ps_global
), opts
,
5270 'n', 'x', h_confirm_cancel
, RB_NORM
);
5271 if(rv
== 'c'){ /* user ACCEPTS! */
5276 q_status_message(SM_INFO
, 1, 3, _(" Type \"C\" to cancel message "));
5277 display_message('x');
5283 ps_global
->redrawer
= redraw
;
5288 /*----------------------------------------------------------------------
5289 Pass the first text segment of the message thru the "send filter"
5291 Args: body pointer and address for storage object of old data
5293 Returns: returns 1 on success, zero on error.
5296 filter_message_text(char *fcmd
, ENVELOPE
*outgoing
, struct mail_bodystruct
*body
,
5297 STORE_S
**old
, METAENV
*header
)
5299 char *cmd
, *tmpf
= NULL
, *resultf
= NULL
, *errstr
= NULL
, *mtf
= NULL
;
5300 int key
= 0, include_hdrs
= 0;
5302 STORE_S
**so
= (STORE_S
**)((body
->type
== TYPEMULTIPART
)
5303 ? &body
->nested
.part
->body
.contents
.text
.data
5304 : &body
->contents
.text
.data
),
5305 *tmp_so
= NULL
, *tmpf_so
,
5306 *save_local_so
, *readthis_so
, *our_tmpf_so
= NULL
;
5307 #define DO_HEADERS 1
5310 && (cmd
=expand_filter_tokens(fcmd
, outgoing
, &tmpf
, &resultf
, &mtf
,
5311 &key
, &include_hdrs
, NULL
))){
5314 * We need WRITE_TO_LOCALE here because the user is going to
5315 * be operating on tmpf. We need to change it back after they
5318 if((tmpf_so
= so_get(FileStar
, tmpf
, EDIT_ACCESS
|OWNER_ONLY
|WRITE_TO_LOCALE
)) != NULL
){
5320 so_puts(tmpf_so
, filter_session_key());
5321 so_puts(tmpf_so
, NEWLINE
);
5325 * If the headers are wanted for filtering, we can just
5326 * stick them in the tmpf file that is already there before
5327 * putting the body in.
5330 save_local_so
= lmc
.so
;
5331 lmc
.so
= tmpf_so
; /* write it to tmpf_so */
5332 lmc
.all_written
= lmc
.text_written
= lmc
.text_only
= 0;
5333 pine_rfc822_header(header
, body
, NULL
, NULL
);
5334 lmc
.so
= save_local_so
;
5337 so_seek(*so
, 0L, 0);
5338 gf_set_so_readc(&gc
, *so
);
5339 gf_set_so_writec(&pc
, tmpf_so
);
5341 errstr
= gf_pipe(gc
, pc
);
5342 gf_clear_so_readc(*so
);
5343 gf_clear_so_writec(tmpf_so
);
5347 errstr
= "Can't create space for filter temporary file.";
5349 else if(include_hdrs
){
5351 * Gf_filter wants a single storage object to read from.
5352 * If headers are wanted for filtering we'll have to put them
5353 * and the body into a temp file first and then use that
5354 * as the storage object for gf_filter.
5355 * We don't use WRITE_TO_LOCALE in this case because gf_filter
5356 * takes care of that.
5358 if((our_tmpf_so
= so_get(TmpFileStar
, NULL
, EDIT_ACCESS
|OWNER_ONLY
)) != NULL
){
5359 /* put headers in our_tmpf_so */
5360 save_local_so
= lmc
.so
;
5361 lmc
.so
= our_tmpf_so
; /* write it to our_tmpf_so */
5362 lmc
.all_written
= lmc
.text_written
= lmc
.text_only
= 0;
5363 pine_rfc822_header(header
, body
, NULL
, NULL
);
5364 lmc
.so
= save_local_so
;
5366 /* put body in our_tmpf_so */
5367 so_seek(*so
, 0L, 0);
5368 gf_set_so_readc(&gc
, *so
);
5369 gf_set_so_writec(&pc
, our_tmpf_so
);
5371 errstr
= gf_pipe(gc
, pc
);
5372 gf_clear_so_readc(*so
);
5373 gf_clear_so_writec(our_tmpf_so
);
5375 /* tell gf_filter to read from our_tmpf_so instead of *so */
5376 readthis_so
= our_tmpf_so
;
5379 errstr
= "Can't create space for temporary file.";
5385 if((tmp_so
= so_get(PicoText
, NULL
, EDIT_ACCESS
)) != NULL
){
5386 gf_set_so_writec(&pc
, tmp_so
);
5387 ps_global
->mangled_screen
= 1;
5394 if((fpipe
= open_system_pipe(cmd
, NULL
, NULL
,
5395 PIPE_NOSHELL
| PIPE_RESET
,
5396 0, pipe_callback
, pipe_report_error
)) != NULL
){
5397 if(close_system_pipe(&fpipe
, NULL
, pipe_callback
) == 0){
5399 /* now we undo the WRITE_FROM_LOCALE change in tmpf */
5400 if((tmpf_so
= so_get(FileStar
, tmpf
, READ_ACCESS
|READ_FROM_LOCALE
)) != NULL
){
5401 gf_set_so_readc(&gc
, tmpf_so
);
5403 errstr
= gf_pipe(gc
, pc
);
5404 gf_clear_so_readc(tmpf_so
);
5408 errstr
= "Can't open temp file filter wrote.";
5411 errstr
= "Filter command returned error.";
5414 errstr
= "Can't exec filter text.";
5417 errstr
= gf_filter(cmd
, key
? filter_session_key() : NULL
,
5418 readthis_so
, pc
, NULL
, 0, 0,
5422 so_give(&our_tmpf_so
);
5424 gf_clear_so_writec(tmp_so
);
5429 * Can't really be using stdout, so don't print message that
5430 * gets printed in the else. Ideally the program being called
5431 * will wait after showing the message, we might want to look
5432 * into doing the waiting in console based apps... or not.
5438 fprintf(stdout
, "\r\n%s Hit return to continue.", errstr
);
5440 while((ch
= read_char(300)) != ctrl('M')
5441 && ch
!= NO_OP_IDLE
)
5445 #endif /* _WINDOWS */
5446 BODY
*b
= (body
->type
== TYPEMULTIPART
)
5447 ? &body
->nested
.part
->body
: body
;
5449 *old
= *so
; /* save old so */
5450 *so
= tmp_so
; /* return new one */
5451 (*so
)->attr
= copy_parameters((*old
)->attr
);
5454 * If the command said it would return new MIME
5455 * mime type data, check it out...
5458 char buf
[MAILTMPLEN
], *s
;
5461 if((fp
= our_fopen(mtf
, "rb")) != NULL
){
5462 if(fgets(buf
, sizeof(buf
), fp
)
5463 && !struncmp(buf
, "content-", 8)
5464 && (s
= strchr(buf
+8, ':'))){
5465 BODY
*nb
= mail_newbody();
5467 for(*s
++ = '\0'; *s
== ' '; s
++)
5470 rfc822_parse_content_header(nb
,
5471 (char *) ucase((unsigned char *) buf
+8),s
);
5472 if(nb
->type
== TYPETEXT
5475 || strucmp(b
->subtype
, nb
->subtype
))){
5477 fs_give((void **) &b
->subtype
);
5479 b
->subtype
= nb
->subtype
;
5482 mail_free_body_parameter(&b
->parameter
);
5483 b
->parameter
= nb
->parameter
;
5484 nb
->parameter
= NULL
;
5485 mail_free_body_parameter(&nb
->parameter
);
5488 mail_free_body(&nb
);
5496 * Reevaluate the encoding in case form's changed...
5498 b
->encoding
= ENCOTHER
;
5499 set_mime_type_by_grope(b
);
5506 errstr
= "Can't create space for filtered text.";
5509 fs_give((void **)&cmd
);
5516 fs_give((void **)&tmpf
);
5521 fs_give((void **) &mtf
);
5525 if(name_file_size(resultf
) > 0L)
5526 display_output_file(resultf
, "Filter", NULL
, DOF_BRIEF
);
5527 our_unlink(resultf
);
5528 fs_give((void **)&resultf
);
5534 q_status_message1(SM_ORDER
| SM_DING
, 3, 6, _("Problem filtering: %s"),
5536 dprint((1, "Filter FAILED: %s\n",
5537 errstr
? errstr
: "?"));
5540 return(errstr
== NULL
);
5544 /*----------------------------------------------------------------------
5545 Copy the newsgroup name of the given mailbox into the given buffer
5552 pine_send_newsgroup_name(char *mailbox
, char *group_name
, size_t len
)
5556 if(*mailbox
== '#'){ /* Strip the leading "#news." */
5557 strncpy(group_name
, mailbox
+ 6, len
-1);
5558 group_name
[len
-1] = '\0';
5560 else if(mail_valid_net_parse(mailbox
, &mb
)){
5561 pine_send_newsgroup_name(mb
.mailbox
, group_name
, len
);
5568 /*----------------------------------------------------------------------
5569 Set up fields for passing to pico. Assumes first text part is
5570 intended to be passed along for editing, and is in the form of
5571 of a storage object brought into existence sometime before pico_send().
5574 outgoing2strings(METAENV
*header
, struct mail_bodystruct
*bod
, void **text
,
5575 PATMT
**pico_a
, int from_bounce
)
5580 * SIMPLIFYING ASSUMPTION #37: the first TEXT part's storage object
5581 * is guaranteed to be of type PicoText!
5583 if(bod
->type
== TYPETEXT
){
5584 *text
= so_text((STORE_S
*) bod
->contents
.text
.data
);
5586 /* mark storage object as user edited */
5588 (void) so_attr((STORE_S
*) bod
->contents
.text
.data
, "edited", "1");
5590 else if(bod
->type
== TYPEMULTIPART
){
5593 char *type
, *name
, *p
;
5597 * We used to jump out the window if the first part wasn't text,
5598 * but that may not be the case when bouncing a message with
5599 * a leading non-text segment. So, IT'S UNDERSTOOD that the
5600 * contents of the first part to send is still ALWAYS in a
5601 * PicoText storage object, *AND* if that object doesn't contain
5602 * data of type text, then it must contain THE ENCODED NON-TEXT
5603 * DATA of the piece being sent.
5605 * It's up to the programmer to make sure that such a message is
5606 * sent via pine_simple_send and never get to the composer via
5611 *text
= so_text((STORE_S
*) bod
->nested
.part
->body
.contents
.text
.data
);
5613 /* mark storage object as user edited */
5615 (void) so_attr((STORE_S
*) bod
->nested
.part
->body
.contents
.text
.data
, "edited", "1");
5618 * If we already had a list, blast it now, so we can build a new
5619 * attachment list that reflects what's really there...
5622 free_attachment_list(pico_a
);
5625 /* Simplifyihg assumption #28e. (see cross reference)
5626 All parts in the body passed in here that are not already
5627 in the attachments list are added to the end of the attachments
5628 list. Attachment items not in the body list will be taken care
5629 of in strings2outgoing, but they are unlikely to occur
5632 for(part
= bod
->nested
.part
->next
; part
!= NULL
; part
= part
->next
) {
5633 /* Already in list? */
5635 *ppa
&& strcmp((*ppa
)->id
, part
->body
.id
);
5636 ppa
= &(*ppa
)->next
)
5639 if(!*ppa
){ /* Not in the list! append it... */
5640 *ppa
= (PATMT
*)fs_get(sizeof(PATMT
));
5642 if(part
->body
.description
){
5646 len
= 4*strlen(part
->body
.description
)+1;
5647 p
= (char *)fs_get(len
*sizeof(char));
5648 if(rfc1522_decode_to_utf8((unsigned char *)p
,
5649 len
, part
->body
.description
) == (unsigned char *) p
){
5650 (*ppa
)->description
= p
;
5653 fs_give((void **)&p
);
5654 (*ppa
)->description
= cpystr(part
->body
.description
);
5658 (*ppa
)->description
= cpystr("");
5660 type
= type_desc(part
->body
.type
, part
->body
.subtype
,
5661 part
->body
.parameter
, NULL
, 0);
5664 * If we can find a "name" parm, display that too...
5666 if((name
= parameter_val(part
->body
.parameter
, "name")) != NULL
){
5667 /* Convert any [ or ]'s the name contained */
5668 for(p
= name
; *p
; p
++)
5679 (*ppa
)->filename
= fs_get(strlen(type
) + name_l
+ 5);
5681 snprintf((*ppa
)->filename
, strlen(type
) + name_l
+ 5, "[%s%s%s]", type
,
5682 name
? ": " : "", name
? name
: "");
5683 (*ppa
)->filename
[strlen(type
) + name_l
+ 5 - 1] = '\0';
5686 fs_give((void **) &name
);
5688 (*ppa
)->flags
= A_FLIT
;
5689 (*ppa
)->size
= cpystr(byte_string(
5690 send_body_size(&part
->body
)));
5692 part
->body
.id
= generate_message_id(NULL
);
5694 (*ppa
)->id
= cpystr(part
->body
.id
);
5695 (*ppa
)->next
= NULL
;
5702 /*------------------------------------------------------------------
5703 Malloc strings to pass to composer editor because it expects
5704 such strings so it can realloc them
5705 -----------------------------------------------------------------*/
5707 * turn any address fields into text strings
5710 * SIMPLIFYING ASSUMPTION #116: all header strings are understood
5711 * NOT to be RFC1522 decoded. Said differently, they're understood
5712 * to be RFC1522 ENCODED as necessary. The intent is to preserve
5713 * original charset tagging as far into the compose/send pipe as
5716 for(pf
= header
->local
; pf
&& pf
->name
; pf
= pf
->next
)
5724 pf
->scratch
= addr_list_string(*pf
->addr
, NULL
, 1);
5727 * Scan for and fix-up patently bogus fields.
5729 * NOTE: collaboration with this code and what's done in
5730 * reply.c:reply_cp_addr to package up the bogus stuff
5733 for(p
= pf
->scratch
; (p
= strstr(p
, "@" RAWFIELD
)); )
5735 if(*t
== '&'){ /* find "leading" token */
5739 * Rfc822_cat has been changed so that it now quotes
5740 * this sometimes. So we have to look out for quotes
5741 * which confuse the decoder. It was only quoting
5742 * because we were putting \r \n in the input, I think.
5744 if(t
> pf
->scratch
&& t
[-1] == '\"' && p
[-1] == '\"')
5745 t
[-1] = p
[-1] = ' ';
5747 *t
++ = ' '; /* replace token */
5748 *p
= '\0'; /* tie off string */
5749 u
= rfc822_base64((unsigned char *) t
,
5750 (unsigned long) strlen(t
),
5751 (unsigned long *) &l
);
5755 replacelen
= strlen(t
);
5756 *p
= '@'; /* restore 'p' */
5757 rplstr(p
, strlen(p
), 12, ""); /* clear special token */
5758 rplstr(t
, strlen(u
)-replacelen
+1, replacelen
, u
);
5760 fs_give((void **) &u
);
5763 HE(pf
)->start_here
= 1;
5767 else if(t
== pf
->scratch
)
5770 removing_leading_white_space(pf
->scratch
);
5775 * Replace control characters with ^C notation, unless
5776 * some conditions are met (see istrncpy).
5777 * If user doesn't edit, then we switch back to the
5778 * original version. If user does edit, then all bets
5781 iutf8ncpy((char *)tmp_20k_buf
, pf
->scratch
, SIZEOF_20KBUF
-1);
5782 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
5783 if((l
=strlen((char *)tmp_20k_buf
)) > strlen(pf
->scratch
)){
5784 fs_give((void **)&pf
->scratch
);
5785 pf
->scratch
= (char *)fs_get((l
+1) * sizeof(char));
5788 strncpy(pf
->scratch
, (char *)tmp_20k_buf
, l
+1);
5799 src
= pf
->scratch
? pf
->scratch
5800 : (*pf
->text
) ? *pf
->text
: "";
5802 len
= 4*strlen(src
)+1;
5803 p
= (char *)fs_get(len
* sizeof(char));
5804 if(rfc1522_decode_to_utf8((unsigned char *)p
, len
, src
) == (unsigned char *) p
){
5806 fs_give((void **)&pf
->scratch
);
5811 fs_give((void **)&p
);
5813 pf
->scratch
= cpystr(src
);
5820 * Replace control characters with ^C notation, unless
5821 * some conditions are met (see istrncpy).
5822 * If user doesn't edit, then we switch back to the
5823 * original version. If user does edit, then all bets
5826 iutf8ncpy((char *)tmp_20k_buf
, pf
->scratch
, SIZEOF_20KBUF
-1);
5827 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
5828 if((l
=strlen((char *)tmp_20k_buf
)) > strlen(pf
->scratch
)){
5829 fs_give((void **)&pf
->scratch
);
5830 pf
->scratch
= (char *)fs_get((l
+1) * sizeof(char));
5833 strncpy(pf
->scratch
, (char *)tmp_20k_buf
, l
+1);
5845 /*----------------------------------------------------------------------
5846 Restore fields returned from pico to form useful to sending
5850 strings2outgoing(METAENV
*header
, struct mail_bodystruct
**bod
, PATMT
*attach
, int flow_it
)
5855 we_cancel
= busy_cue(NULL
, NULL
, 1);
5858 * turn any local address strings into address lists
5860 for(pf
= header
->local
; pf
&& pf
->name
; pf
= pf
->next
)
5862 char *the_address
= NULL
;
5866 removing_trailing_white_space(pf
->scratch
);
5868 if((the_address
|| *pf
->scratch
) && pf
->addr
){
5869 ADDRESS
*new_addr
= NULL
;
5870 static char *fakedomain
= "@";
5873 the_address
= pf
->scratch
;
5875 rfc822_parse_adrlist(&new_addr
, the_address
,
5876 (F_ON(F_COMPOSE_REJECTS_UNQUAL
, ps_global
))
5877 ? fakedomain
: ps_global
->maildomain
);
5878 mail_free_address(pf
->addr
); /* free old addrs */
5879 *pf
->addr
= new_addr
; /* assign new addr */
5882 mail_free_address(pf
->addr
); /* free old addrs */
5888 fs_give((void **)pf
->text
);
5891 *pf
->text
= cpystr(pf
->scratch
);
5900 fs_give((void **)&pf
->scratch
); /* free now useless text */
5903 create_message_body(bod
, attach
, flow_it
);
5906 cancel_busy_cue(-1);
5910 /*----------------------------------------------------------------------
5912 The head of the body list here is always either TEXT or MULTIPART. It may be
5913 changed from TEXT to MULTIPART if there are attachments to be added
5914 and it is not already multipart.
5917 create_message_body(struct mail_bodystruct
**b
, PATMT
*attach
, int flow_it
)
5921 BODY
*tmp_body
, *text_body
= NULL
;
5922 void *file_contents
;
5926 TIME_STAMP("create_body start.", 1);
5928 * if conditions are met short circuit MIME wrapping
5930 if((*b
)->type
!= TYPEMULTIPART
&& !attach
){
5932 /* only override assigned encoding if it might need upgrading */
5933 if((*b
)->type
== TYPETEXT
&& (*b
)->encoding
== ENC7BIT
)
5934 (*b
)->encoding
= ENCOTHER
;
5936 create_message_body_text(*b
, flow_it
);
5938 if(F_ON(F_COMPOSE_ALWAYS_DOWNGRADE
, ps_global
)
5939 || !((*b
)->encoding
== ENC8BIT
5940 || (*b
)->encoding
== ENCBINARY
)){
5941 TIME_STAMP("create_body end.", 1);
5944 else /* protect 8bit in multipart */
5948 if((*b
)->type
== TYPETEXT
) {
5949 /*-- Current type is text, but there are attachments to add --*/
5950 /*-- Upgrade to a TYPEMULTIPART --*/
5951 tmp_body
= (BODY
*)mail_newbody();
5952 tmp_body
->type
= TYPEMULTIPART
;
5953 tmp_body
->nested
.part
= mail_newbody_part();
5956 * Why do we do this?
5957 * The problem is that base64 or quoted-printable encoding is
5958 * sensitive to having random data appended to it's end. If
5959 * we use a single part TEXT message and something in between
5960 * us and the end appends advertising without adjusting for
5961 * the encoding, the message is screwed up. So we wrap the
5962 * text part inside a multipart and then the appended data
5963 * will come after the boundary.
5965 * We wish we could do this on the way out the door in a
5966 * child of post_rfc822_output because at that point we know
5967 * the character set and the encoding being used. For example,
5968 * iso-2022-jp is an encoding that is not sensitive to data
5969 * appended to the end, so it wouldn't need to be wrapped.
5970 * We could conceivably have post_rfc822_body inspect the
5971 * body and change it before doing the output. It would work
5972 * but would be very fragile. We'd be passed a body from
5973 * c-client to output and instead of just doing the output
5974 * we'd change the body and then output it. Not worth it
5975 * since the multipart wrapping is completely correct for
5976 * MIME-aware mailers.
5978 (void) copy_body(&(tmp_body
->nested
.part
->body
), *b
);
5979 /* move contents which were NOT copied */
5980 tmp_body
->nested
.part
->body
.contents
.text
.data
= (*b
)->contents
.text
.data
;
5981 (*b
)->contents
.text
.data
= NULL
;
5984 tmp_body
->nested
.part
->body
= **b
;
5986 (*b
)->subtype
= (*b
)->id
= (*b
)->description
= NULL
;
5987 (*b
)->parameter
= NULL
;
5988 (*b
)->contents
.text
.data
= NULL
;
5996 /*-- Now type must be MULTIPART with first part text --*/
5997 (*b
)->nested
.part
->body
.encoding
= ENCOTHER
;
5998 create_message_body_text(&((*b
)->nested
.part
->body
), flow_it
);
6001 /*------ Go through the parts list remove those to be deleted -----*/
6002 for(pp
= &(*b
)->nested
.part
->next
; *pp
;){
6003 for(pa
= attach
; pa
&& (*pp
)->body
.id
; pa
= pa
->next
)
6004 /* already existed? */
6005 if(pa
->id
&& strcmp(pa
->id
, (*pp
)->body
.id
) == 0){
6006 char *orig_descp
= NULL
, *cs
= NULL
;
6009 * decode original to see if it matches what was decoded
6010 * when we sent it in.
6013 if((*pp
)->body
.description
)
6014 orig_descp
= (char *) rfc1522_decode_to_utf8((unsigned char *) tmp_20k_buf
,
6015 SIZEOF_20KBUF
, (*pp
)->body
.description
);
6017 if(!(*pp
)->body
.description
/* update description? */
6018 || (pa
->description
&& strcmp(pa
->description
, orig_descp
))){
6019 if((*pp
)->body
.description
)
6020 fs_give((void **) &(*pp
)->body
.description
);
6022 /* encoding happens as msg text is written */
6023 (*pp
)->body
.description
= cpystr(pa
->description
);
6027 fs_give((void **) &cs
);
6033 p
= *pp
; /* prepare to zap *pp */
6034 *pp
= p
->next
; /* pull next one in list up */
6035 p
->next
= NULL
; /* tie off removed node */
6037 pine_free_body_data(&p
->body
); /* clean up contained data */
6038 mail_free_body_part(&p
); /* free up the part */
6044 /*---------- Now add any new attachments ---------*/
6045 for(p
= (*b
)->nested
.part
; p
->next
!= NULL
; p
= p
->next
);
6046 for(pa
= attach
; pa
!= NULL
; pa
= pa
->next
) {
6048 continue; /* Has an ID, it's old */
6051 * the idea is handle ALL attachments as open FILE *'s. Actual
6052 * encoding and such is handled at the time the message
6053 * is shoved into the mail slot or written to disk...
6055 * Also, we never unlink a file, so it's up to whoever opens
6056 * it to deal with tmpfile issues.
6058 if((file_contents
= (void *)so_get(FileStar
, pa
->filename
,
6059 READ_ACCESS
)) == NULL
){
6060 q_status_message2(SM_ORDER
| SM_DING
, 3, 4,
6061 _("Error \"%s\", couldn't attach file \"%s\""),
6062 error_description(errno
), pa
->filename
);
6063 display_message('x');
6067 p
->next
= mail_newbody_part();
6069 p
->body
.id
= generate_message_id(NULL
);
6070 p
->body
.contents
.text
.data
= file_contents
;
6073 * Set type to unknown and let set_mime_type_by_* figure it out.
6074 * Always encode attachments we add as BINARY.
6076 p
->body
.type
= TYPEOTHER
;
6077 p
->body
.encoding
= ENCBINARY
;
6078 p
->body
.size
.bytes
= name_file_size(pa
->filename
);
6079 if(!set_mime_type_by_extension(&p
->body
, pa
->filename
)){
6080 set_mime_type_by_grope(&p
->body
);
6081 set_charset_possibly_to_ascii(&p
->body
, ps_global
->keyboard_charmap
);
6084 so_release((STORE_S
*)p
->body
.contents
.text
.data
);
6086 if(pa
->description
) /* encoding happens when msg written */
6087 p
->body
.description
= cpystr(pa
->description
);
6089 /* Add name attribute for backward compatibility */
6090 for(parmp
= &p
->body
.parameter
; *parmp
; )
6091 if(!struncmp((*parmp
)->attribute
, "name", 4)
6092 && (!*((*parmp
)->attribute
+ 4)
6093 || *((*parmp
)->attribute
+ 4) == '*')){
6094 PARAMETER
*free_me
= *parmp
;
6095 *parmp
= (*parmp
)->next
;
6096 free_me
->next
= NULL
;
6097 mail_free_body_parameter(&free_me
);
6100 parmp
= &(*parmp
)->next
;
6102 set_parameter(parmp
, "name",
6104 ? ((lc
= last_cmpnt(pa
->filename
)) ? lc
: pa
->filename
)
6107 /* Then set the Content-Disposition ala RFC1806 */
6108 if(!p
->body
.disposition
.type
){
6109 p
->body
.disposition
.type
= cpystr("attachment");
6110 for(parmp
= &p
->body
.disposition
.parameter
; *parmp
; )
6111 if(!struncmp((*parmp
)->attribute
, "filename", 4)
6112 && (!*((*parmp
)->attribute
+ 4)
6113 || *((*parmp
)->attribute
+ 4) == '*')){
6114 PARAMETER
*free_me
= *parmp
;
6115 *parmp
= (*parmp
)->next
;
6116 free_me
->next
= NULL
;
6117 mail_free_body_parameter(&free_me
);
6120 parmp
= &(*parmp
)->next
;
6122 set_parameter(parmp
, "filename",
6124 ? ((lc
= last_cmpnt(pa
->filename
)) ? lc
: pa
->filename
)
6129 pa
->id
= cpystr(p
->body
.id
);
6133 * Now, if this multipart has but one text piece (that is, no
6134 * attachments), then downgrade from a composite type to a discrete
6135 * text/plain message if CTE is not 8bit.
6137 if(!(*b
)->nested
.part
->next
6138 && (*b
)->nested
.part
->body
.type
== TYPETEXT
6139 && (F_ON(F_COMPOSE_ALWAYS_DOWNGRADE
, ps_global
)
6140 || !((*b
)->nested
.part
->body
.encoding
== ENC8BIT
6141 || (*b
)->nested
.part
->body
.encoding
== ENCBINARY
))){
6142 /* Clone the interesting body part */
6143 tmp_body
= mail_newbody();
6144 *tmp_body
= (*b
)->nested
.part
->body
;
6145 /* and rub out what we don't want cleaned up when it's free'd */
6146 mail_initbody(&(*b
)->nested
.part
->body
);
6152 TIME_STAMP("create_body end.", 1);
6157 * Fill in text BODY part's structure
6161 create_message_body_text(struct mail_bodystruct
*b
, int flow_it
)
6163 set_mime_type_by_grope(b
);
6165 remove_parameter(&b
->parameter
, "format"); /* we will set it up below */
6166 remove_parameter(&b
->parameter
, "delsp"); /* we never set this up */
6168 if(F_OFF(F_QUELL_FLOWED_TEXT
, ps_global
)
6169 && F_OFF(F_STRIP_WS_BEFORE_SEND
, ps_global
)
6171 set_parameter(b
? &b
->parameter
: NULL
, "format", "flowed");
6178 * free_attachment_list - free attachments in given list
6181 free_attachment_list(PATMT
**alist
)
6185 while(alist
&& *alist
){ /* pointer pointing to something */
6186 leading
= (*alist
)->next
;
6187 if((*alist
)->description
)
6188 fs_give((void **)&(*alist
)->description
);
6190 if((*alist
)->filename
){
6191 if((*alist
)->flags
& A_TMP
)
6192 if(our_unlink((*alist
)->filename
) < 0)
6193 dprint((1, "-- Can't unlink(%s): %s\n",
6194 (*alist
)->filename
? (*alist
)->filename
: "?",
6195 error_description(errno
)));
6197 fs_give((void **)&(*alist
)->filename
);
6201 fs_give((void **)&(*alist
)->size
);
6204 fs_give((void **)&(*alist
)->id
);
6206 fs_give((void **)alist
);
6214 set_body_size(struct mail_bodystruct
*b
)
6219 we_cancel
= busy_cue(NULL
, NULL
, 1);
6220 so_seek((STORE_S
*)b
->contents
.text
.data
, 0L, 0);
6222 while(so_readc(&c
, (STORE_S
*)b
->contents
.text
.data
))
6226 cancel_busy_cue(-1);
6231 * view_as_rich - set the rich_header flag
6233 * name - name of the header field
6234 * deflt - default value to return if user didn't set it
6236 * Note: if the user tries to turn them all off with "", then
6237 * we take that to mean default, since otherwise there is no
6238 * way to get to the headers.
6241 view_as_rich(char *name
, int deflt
)
6246 p
= ps_global
->VAR_COMP_HDRS
;
6249 for(; (q
= *p
) != NULL
; p
++){
6250 if(!struncmp(q
, name
, strlen(name
)))
6251 return 0; /* 0 means we *do* view it by default */
6254 return 1; /* 1 means it starts out hidden */
6261 * background_posting - return whether or not we're already in the process
6265 background_posting(int gripe
)
6267 if(ps_global
->post
){
6269 q_status_message(SM_ORDER
|SM_DING
, 3, 3,
6270 _("Can't post while posting!"));
6278 /*----------------------------------------------------------------------
6279 Validate the given subject relative to any news groups.
6283 Returns: always returns 1, but also returns error if
6286 valid_subject(char *given
, char **expanded
, char **error
, BUILDER_ARG
*fcc
, int *mangled
)
6288 struct headerentry
*hp
;
6291 *expanded
= cpystr(given
);
6295 * Now look for any header entry we passed to pico that has to do
6296 * with news. If there's no subject, gripe.
6298 for(hp
= pbf
->headents
; hp
->prompt
; hp
++)
6299 if(hp
->help
== h_composer_news
){
6300 if(hp
->hd_text
->text
[0] && !*given
)
6302 _("News postings MUST have a subject! Please add one!"));
6313 * This is the build_address used by the composer to check for an address
6316 * Args: to -- the passed in line to parse
6317 * full_to -- Address of a pointer to return the full address in.
6318 * This will be allocated here and freed by the caller.
6319 * error -- Address of a pointer to return an error message in.
6320 * This will be allocated here and freed by the caller.
6321 * barg -- Address of a pointer to return the fcc in is in
6322 * fcc->tptr. It will have already been allocated by the
6323 * caller but we may free it and reallocate if we wish.
6324 * Caller will free it.
6326 * Result: 0 is returned if address was OK,
6327 * -1 if address wasn't OK.
6329 * Side effect: Can flush addrbook entry cache entries so they need to be
6330 * re-fetched afterwords.
6333 build_address(char *to
, char **full_to
, char **error
, BUILDER_ARG
*barg
, int *mangled
)
6336 int ret_val
, no_repo
= 0, *save_nesting_level
;
6338 PrivateTop
*pt
= NULL
;
6339 PrivateAffector
*af
= NULL
;
6340 char *fcc_local
= NULL
;
6341 jmp_buf save_jmp_buf
;
6343 dprint((5, "- build_address - (%s)\n", to
? to
: "nul"));
6345 /* check to see if to string is empty to avoid work */
6346 for(p
= to
; p
&& *p
&& isspace((unsigned char)*p
); p
++)
6351 *full_to
= cpystr(to
? to
: ""); /* because pico does a strcmp() */
6357 *full_to
= (char *)NULL
;
6360 *error
= (char *)NULL
;
6362 /* No guarantee cursor or status line is how we saved it */
6364 mark_status_unknown();
6366 if(ps_global
->remote_abook_validity
> 0 &&
6367 adrbk_check_and_fix_all(ab_nesting_level
== 0, 0, 0) && mangled
)
6368 *mangled
|= BUILDER_SCREEN_MANGLED
;
6371 * If we end up jumping back here because somebody else changed one of
6372 * our addrbooks out from underneath us, we may well leak some memory.
6373 * That's probably ok since this will be very rare.
6375 * The reason for the memcpy of the jmp_buf is that we may actually
6376 * be indirectly calling this function from within the address book.
6377 * For example, we may be in the address book screen and then run
6378 * the ComposeTo command which puts us in the composer, then we call
6379 * build_address from there which resets addrbook_changed_unexpectedly.
6380 * Once we leave build_address we need to reset addrbook_changed_un...
6381 * because this position on the stack will no longer be valid.
6382 * Same is true of the other setjmp's in this file which are wrapped
6385 save_nesting_level
= cpyint(ab_nesting_level
);
6386 memcpy(save_jmp_buf
, addrbook_changed_unexpectedly
, sizeof(jmp_buf));
6387 if(setjmp(addrbook_changed_unexpectedly
)){
6393 *error
= (char *)NULL
;
6395 if(full_to
&& *full_to
)
6396 fs_give((void **)full_to
);
6398 q_status_message(SM_ORDER
, 3, 5, "Resetting address book...");
6400 "RESETTING address book... build_address(%s)!\n", to
? to
: "?"));
6402 ab_nesting_level
= *save_nesting_level
;
6408 ret_val
= build_address_internal(bldto
, full_to
, error
,
6409 barg
? &fcc_local
: NULL
,
6410 &no_repo
, NULL
, save_and_restore
,
6413 if(save_nesting_level
)
6414 fs_give((void **)&save_nesting_level
);
6417 * Have to rfc1522_decode the full_to string before sending it back.
6419 if(full_to
&& *full_to
){
6423 len
= 4*strlen(*full_to
)+1;
6424 q
= (char *)fs_get(len
* sizeof(char));
6425 p
= (char *)rfc1522_decode_to_utf8((unsigned char *)q
, len
, *full_to
);
6427 /* p == q means that decoding happened, p is decoded *full_to */
6429 fs_give((void **)full_to
);
6433 fs_give((void **)&q
);
6439 /* Pt will point to headents[Fcc].bldr_private */
6441 if(barg
&& barg
->aff
)
6442 pt
= (PrivateTop
*)(*barg
->aff
);
6445 * If *barg->aff is set, that means fcc was set from a list
6446 * during some previous builder call.
6447 * If the current To line contains the old expansion as a prefix, then
6448 * we should leave things as they are. In order to decide that,
6449 * we look at a hash value computed from the strings.
6451 if(pt
&& (af
=pt
->affector
) && af
->who
== BP_To
){
6455 if(len
>= af
->cksumlen
){
6458 save
= to
[af
->cksumlen
];
6459 to
[af
->cksumlen
] = '\0';
6460 csum
= line_hash(to
);
6461 to
[af
->cksumlen
] = save
;
6464 csum
= af
->cksumval
+ 1; /* something not equal to cksumval */
6469 (pt
->affector
->who
== BP_To
&& csum
!= pt
->affector
->cksumval
)){
6471 /* replace fcc value */
6473 fs_give((void **)&barg
->tptr
);
6475 barg
->tptr
= fcc_local
;
6479 *barg
->aff
= (void *)fs_get(sizeof(PrivateTop
));
6480 pt
= (PrivateTop
*)(*barg
->aff
);
6481 memset((void *)pt
, 0, sizeof(PrivateTop
));
6487 (PrivateAffector
*)fs_get(sizeof(PrivateAffector
));
6491 af
->cksumlen
= strlen(((full_to
&& *full_to
)
6493 af
->cksumval
= line_hash(((full_to
&& *full_to
)
6498 * If result is reproducible, we don't keep track here.
6501 fs_give((void **)&pt
->affector
);
6506 fs_give((void **)&fcc_local
); /* unused in this case */
6509 /* This is so pico will erase the old message */
6510 if(error
!= NULL
&& *error
== NULL
)
6511 *error
= cpystr("");
6513 memcpy(addrbook_changed_unexpectedly
, save_jmp_buf
, sizeof(jmp_buf));
6514 flush_status_messages(1);
6520 * This is the builder used by the composer for the Lcc line.
6522 * Args: lcc -- the passed in Lcc line to parse
6523 * full_lcc -- Address of a pointer to return the full address in.
6524 * This will be allocated here and freed by the caller.
6525 * error -- Address of a pointer to return an error message in.
6526 * This is not allocated so should not be freed by the caller.
6527 * barg -- This is a pointer to text for affected entries which
6528 * we may be changing. The first one in the list is the
6529 * To entry. We may put the name of the list in empty
6530 * group syntax form there (like List Name: ;).
6531 * The second one in the list is the fcc field.
6532 * The tptr members already point to text allocated in the
6533 * caller. We may free and reallocate here, caller will
6534 * free the result in any case.
6536 * Result: 0 is returned if address was OK,
6537 * -1 if address wasn't OK.
6539 * Side effect: Can flush addrbook entry cache entries so they need to be
6540 * re-fetched afterwords.
6543 build_addr_lcc(char *lcc
, char **full_lcc
, char **error
, BUILDER_ARG
*barg
, int *mangled
)
6546 no_repo
= 0; /* fcc or lcc not reproducible */
6547 int *save_nesting_level
;
6549 PrivateTop
*pt
= NULL
;
6550 PrivateAffector
*af
= NULL
;
6555 jmp_buf save_jmp_buf
;
6557 dprint((5, "- build_addr_lcc - (%s)\n", lcc
? lcc
: "nul"));
6559 /* check to see if to string is empty to avoid work */
6560 for(p
= lcc
; p
&& *p
&& isspace((unsigned char)*p
); p
++)
6565 *full_lcc
= cpystr(lcc
? lcc
: ""); /* because pico does a strcmp() */
6571 *error
= (char *)NULL
;
6573 if(ps_global
->remote_abook_validity
> 0 &&
6574 adrbk_check_and_fix_all(ab_nesting_level
== 0, 0, 0) && mangled
)
6575 *mangled
|= BUILDER_SCREEN_MANGLED
;
6578 * If we end up jumping back here because somebody else changed one of
6579 * our addrbooks out from underneath us, we may well leak some memory.
6580 * That's probably ok since this will be very rare.
6582 save_nesting_level
= cpyint(ab_nesting_level
);
6583 memcpy(save_jmp_buf
, addrbook_changed_unexpectedly
, sizeof(jmp_buf));
6584 if(setjmp(addrbook_changed_unexpectedly
)){
6591 *error
= (char *)NULL
;
6593 if(full_lcc
&& *full_lcc
)
6594 fs_give((void **)full_lcc
);
6596 q_status_message(SM_ORDER
, 3, 5, "Resetting address book...");
6598 "RESETTING address book... build_address(%s)!\n", lcc
? lcc
: "?"));
6600 ab_nesting_level
= *save_nesting_level
;
6605 bldlcc
.arg
.str
= lcc
;
6608 * To is first affected_entry and Fcc is second.
6609 * The conditional stuff for the fcc argument says to only change the
6610 * fcc if the fcc pointer is passed in non-null, and the To pointer
6611 * is also non-null. If they are null, that means they've already been
6612 * entered (are sticky). We don't affect fcc if either fcc or To has
6615 ret_val
= build_address_internal(bldlcc
,
6618 (barg
&& barg
->next
&& barg
->next
->tptr
&& barg
->tptr
)
6619 ? &fcc_local
: NULL
,
6621 (barg
&& barg
->tptr
) ? &to
: NULL
,
6622 save_and_restore
, 0, mangled
);
6625 if(save_nesting_level
)
6626 fs_give((void **)&save_nesting_level
);
6628 /* full_lcc is what ends up in the Lcc: line */
6629 if(full_lcc
&& *full_lcc
){
6633 * Have to rfc1522_decode the full_lcc string before sending it back.
6635 len
= 4*strlen(*full_lcc
)+1;
6636 p
= (char *)fs_get(len
* sizeof(char));
6637 if(rfc1522_decode_to_utf8((unsigned char *)p
, len
, *full_lcc
) == (unsigned char *)p
){
6638 fs_give((void **)full_lcc
);
6642 fs_give((void **)&p
);
6645 /* to is what ends up in the To: line */
6651 * Have to rfc1522_decode the full_to string before sending it back.
6653 len
= 4*strlen(to
)+1;
6654 p
= (char *)fs_get(len
* sizeof(char));
6656 if(rfc1522_decode_to_utf8((unsigned char *)p
, len
, to
) == (unsigned char *)p
){
6658 * If the caller wants us to try to preserve the charset
6659 * information (they set aff) we copy it into encoded->etext.
6660 * We don't have to worry about pasting together pieces of
6661 * etext like we do in build_address because whenever the
6662 * Lcc line is setting the To line it will be setting the
6663 * whole line, not modifying it.
6664 * Pt will point to headents[To].bldr_private.
6666 if(barg
&& barg
->aff
){
6667 pt
= (PrivateTop
*)(*barg
->aff
);
6670 *barg
->aff
= (void *)fs_get(sizeof(PrivateTop
));
6671 pt
= (PrivateTop
*)(*barg
->aff
);
6672 memset((void *)pt
, 0, sizeof(PrivateTop
));
6676 fs_give((void **)&to
);
6680 fs_give((void **)&p
);
6683 fs_give((void **)&dummy
);
6687 * This part is recording the fact that the To line was set to
6688 * what it is by entering something on the Lcc line. In particular,
6689 * if a list alias was entered here then the fullname of the list
6690 * goes in the To line. We save this affector information so that
6691 * we can tell it shouldn't be modified if we call build_addr_lcc
6692 * again unless we actually modified what's in the Lcc line so that
6693 * it doesn't start with the same thing. The problem we're solving
6694 * is that the contents of the Lcc line no longer look like the
6695 * list they were derived from.
6696 * Pt will point to headents[To].bldr_private.
6698 if(barg
&& barg
->aff
)
6699 pt
= (PrivateTop
*)(*barg
->aff
);
6701 if(pt
&& (af
=pt
->affector
) && af
->who
== BP_Lcc
){
6705 if(len
>= af
->cksumlen
){
6708 save
= lcc
[af
->cksumlen
];
6709 lcc
[af
->cksumlen
] = '\0';
6710 csum
= line_hash(lcc
);
6711 lcc
[af
->cksumlen
] = save
;
6714 csum
= af
->cksumval
+ 1; /* so they aren't equal */
6719 pt
->affector
->who
!= BP_Lcc
||
6720 (pt
->affector
->who
== BP_Lcc
&& csum
!= pt
->affector
->cksumval
)){
6722 /* replace to value */
6723 if(barg
->tptr
&& barg
->tptr
[0]){
6727 l
= strlen(barg
->tptr
) + strlen(to
? to
: "") + 2;
6728 t
= (char *)fs_get((l
+1) * sizeof(char));
6729 snprintf(t
, l
+1, "%s%s%s",
6731 (to
&& *to
) ? ", " : "",
6732 (to
&& *to
) ? to
: "");
6733 fs_give((void **)&barg
->tptr
);
6735 fs_give((void **)&to
);
6741 fs_give((void **)&barg
->tptr
);
6748 *barg
->aff
= (void *)fs_get(sizeof(PrivateTop
));
6749 pt
= (PrivateTop
*)(*barg
->aff
);
6750 memset((void *)pt
, 0, sizeof(PrivateTop
));
6756 (PrivateAffector
*)fs_get(sizeof(PrivateAffector
));
6760 af
->cksumlen
= strlen(((full_lcc
&& *full_lcc
)
6762 af
->cksumval
= line_hash(((full_lcc
&& *full_lcc
)
6767 * If result is reproducible, we don't keep track here.
6770 fs_give((void **)&pt
->affector
);
6775 fs_give((void **)&to
); /* unused in this case */
6782 * If *barg->next->aff is set, that means fcc was set from a list
6783 * during some previous builder call. If the current Lcc line
6784 * contains the old expansion as a prefix, then we should leave
6785 * things as they are. In order to decide that we look at a hash
6786 * value computed from the strings.
6787 * Pt will point to headents[Fcc].bldr_private
6790 if(barg
&& barg
->next
&& barg
->next
->aff
)
6791 pt
= (PrivateTop
*)(*barg
->next
->aff
);
6793 if(pt
&& (af
=pt
->affector
) && af
->who
== BP_Lcc
){
6797 if(len
>= af
->cksumlen
){
6800 save
= lcc
[af
->cksumlen
];
6801 lcc
[af
->cksumlen
] = '\0';
6802 csum
= line_hash(lcc
);
6803 lcc
[af
->cksumlen
] = save
;
6806 csum
= af
->cksumval
+ 1; /* something not equal to cksumval */
6811 pt
->affector
->who
!= BP_Lcc
||
6812 (pt
->affector
->who
== BP_Lcc
&& csum
!= pt
->affector
->cksumval
)){
6814 /* replace fcc value */
6815 if(barg
->next
->tptr
)
6816 fs_give((void **)&barg
->next
->tptr
);
6818 barg
->next
->tptr
= fcc_local
;
6820 if(barg
->next
->aff
){
6822 *barg
->next
->aff
= (void *)fs_get(sizeof(PrivateTop
));
6823 pt
= (PrivateTop
*)(*barg
->next
->aff
);
6824 memset((void *)pt
, 0, sizeof(PrivateTop
));
6830 (PrivateAffector
*)fs_get(sizeof(PrivateAffector
));
6834 af
->cksumlen
= strlen(((full_lcc
&& *full_lcc
)
6836 af
->cksumval
= line_hash(((full_lcc
&& *full_lcc
)
6841 * If result is reproducible, we don't keep track here.
6844 fs_give((void **)&pt
->affector
);
6849 fs_give((void **)&fcc_local
); /* unused in this case */
6853 if(error
!= NULL
&& *error
== NULL
)
6854 *error
= cpystr("");
6856 memcpy(addrbook_changed_unexpectedly
, save_jmp_buf
, sizeof(jmp_buf));
6857 flush_status_messages(0);
6862 /*----------------------------------------------------------------------
6863 Verify and canonicalize news groups names.
6864 Called from the message composer
6866 Args: given_group -- List of groups typed by user
6867 expanded_group -- pointer to point to expanded list, which will be
6868 allocated here and freed in caller. If this is
6869 NULL, don't attempt to validate.
6870 error -- pointer to store error message
6871 fcc -- pointer to point to fcc, which will be
6872 allocated here and freed in caller
6874 Returns: 0 if all is OK
6875 -1 if addresses weren't valid
6877 Test the given list of newstroups against those recognized by our nntp
6878 servers. Testing by actually trying to open the list is much cheaper, both
6879 in bandwidth and memory, than yanking the whole list across the wire.
6882 news_build(char *given_group
, char **expanded_group
, char **error
, BUILDER_ARG
*fcc
, int *mangled
)
6885 char *fccptr
= NULL
;
6887 if(fcc
&& fcc
->tptr
)
6888 fccptr
= cpystr(fcc
->tptr
);
6892 rv
= news_grouper(given_group
, expanded_group
, error
, &fccptr
, news_build_busy
);
6894 /* assign any new fcc to the BUILDER_ARG */
6898 if(fcc
->tptr
&& strcmp(fcc
->tptr
, fccptr
)){
6899 fs_give((void **) &fcc
->tptr
);
6906 fs_give((void **) &fccptr
);
6909 /* deal with any busy indicator */
6913 mark_status_dirty();
6914 display_message('x');
6916 *mangled
|= BUILDER_MESSAGE_DISPLAYED
;
6925 news_build_busy(void)
6927 news_busy_cue
= busy_cue("Validating newsgroup(s)", NULL
, 0);
6931 #if defined(DOS) || defined(OS2)
6933 /*----------------------------------------------------------------------
6934 Verify that the necessary pieces are around to allow for
6935 message sending under DOS
6937 Args: strict -- tells us if a remote stream is required before
6938 sending is permitted.
6940 The idea is to make sure pine knows enough to put together a valid
6941 from line. The things we MUST know are a user-id, user-domain and
6942 smtp server to dump the message off on. Typically these are
6943 provided in pine's configuration file, but if not, the user is
6949 char prompt
[100], answer
[80];
6954 * query for user name portion of address, use IMAP login
6957 if(!ps_global
->VAR_USER_ID
|| ps_global
->VAR_USER_ID
[0] == '\0'){
6959 int no_prompt_user_id
= 0;
6961 if(ps_global
->mail_stream
&& ps_global
->mail_stream
->mailbox
6962 && mail_valid_net_parse(ps_global
->mail_stream
->mailbox
, &mb
)
6964 strncpy(answer
, mb
.user
, sizeof(answer
)-1);
6965 answer
[sizeof(answer
)-1] = '\0';
6967 else if(F_ON(F_QUELL_USER_ID_PROMPT
, ps_global
)){
6968 /* no user-id prompting if set */
6969 no_prompt_user_id
= 1;
6971 if(!ps_global
->mail_stream
)
6972 do_broach_folder(ps_global
->inbox_name
,
6973 ps_global
->context_list
, NULL
, DB_INBOXWOCNTXT
);
6974 if(ps_global
->mail_stream
&& ps_global
->mail_stream
->mailbox
6975 && mail_valid_net_parse(ps_global
->mail_stream
->mailbox
, &mb
)
6977 strncpy(answer
, mb
.user
, sizeof(answer
)-1);
6978 answer
[sizeof(answer
)-1] = '\0';
6986 if(F_ON(F_QUELL_USER_ID_PROMPT
, ps_global
) && answer
[0]){
6987 /* No prompt, just assume mailbox login is user-id */
6988 no_prompt_user_id
= 1;
6992 snprintf(prompt
,sizeof(prompt
),_("User-id for From address : "));
6993 prompt
[sizeof(prompt
)-1] = '\0';
6996 while(!no_prompt_user_id
) {
6997 flags
= OE_APPEND_CURRENT
;
6998 rc
= optionally_enter(answer
,-FOOTER_ROWS(ps_global
),0,
6999 sizeof(answer
),prompt
,NULL
,help
,&flags
);
7004 help
= (help
== NO_HELP
) ? h_sticky_user_id
: NO_HELP
;
7012 if(rc
== 1 || (rc
== 0 && !answer
[0])) {
7013 q_status_message(SM_ORDER
, 3, 4,
7014 _("Send cancelled (User-id must be provided before sending)"));
7019 snprintf(prompt
, sizeof(prompt
), _("Preserve %.*s as \"user-id\" in PINERC"),
7020 sizeof(prompt
)-50, answer
);
7021 prompt
[sizeof(prompt
)-1] = '\0';
7022 if(ps_global
->blank_user_id
7023 && !no_prompt_user_id
7024 && want_to(prompt
, 'y', 'n', NO_HELP
, WT_NORM
) == 'y'){
7025 set_variable(V_USER_ID
, answer
, 1, 1, Main
);
7028 fs_give((void **)&(ps_global
->VAR_USER_ID
));
7029 ps_global
->VAR_USER_ID
= cpystr(answer
);
7033 /* query for personal name */
7034 if(!ps_global
->VAR_PERSONAL_NAME
|| ps_global
->VAR_PERSONAL_NAME
[0]=='\0'
7035 && F_OFF(F_QUELL_PERSONAL_NAME_PROMPT
, ps_global
)){
7037 snprintf(prompt
, sizeof(prompt
), _("Personal name for From address : "));
7038 prompt
[sizeof(prompt
)-1] = '\0';
7042 flags
= OE_APPEND_CURRENT
;
7043 rc
= optionally_enter(answer
,-FOOTER_ROWS(ps_global
),0,
7044 sizeof(answer
),prompt
,NULL
,help
,&flags
);
7049 help
= (help
== NO_HELP
) ? h_sticky_personal_name
: NO_HELP
;
7057 if(rc
== 0 && answer
){ /* save the name */
7058 snprintf(prompt
, sizeof(prompt
), _("Preserve %.*s as \"personal-name\" in PINERC"),
7059 sizeof(prompt
)-50, answer
);
7060 prompt
[sizeof(prompt
)-1] = '\0';
7061 if(ps_global
->blank_personal_name
7062 && want_to(prompt
, 'y', 'n', NO_HELP
, WT_NORM
) == 'y'){
7063 set_variable(V_PERSONAL_NAME
, answer
, 1, 1, Main
);
7066 fs_give((void **)&(ps_global
->VAR_PERSONAL_NAME
));
7067 ps_global
->VAR_PERSONAL_NAME
= cpystr(answer
);
7073 * query for host/domain portion of address, using IMAP
7076 if(ps_global
->blank_user_domain
7077 || ps_global
->maildomain
== ps_global
->localdomain
7078 || ps_global
->maildomain
== ps_global
->hostname
){
7079 if(ps_global
->inbox_name
[0] == '{'){
7081 i
< sizeof(answer
)-1 && ps_global
->inbox_name
[i
+1] != '}'; i
++)
7082 answer
[i
] = ps_global
->inbox_name
[i
+1];
7089 snprintf(prompt
,sizeof(prompt
),_("Host/domain for From address : "));
7090 prompt
[sizeof(prompt
)-1] = '\0';
7094 flags
= OE_APPEND_CURRENT
;
7095 rc
= optionally_enter(answer
,-FOOTER_ROWS(ps_global
),0,
7096 sizeof(answer
),prompt
,NULL
,help
,&flags
);
7101 help
= (help
== NO_HELP
) ? h_sticky_domain
: NO_HELP
;
7109 if(rc
== 1 || (rc
== 0 && !answer
[0])) {
7110 q_status_message(SM_ORDER
, 3, 4,
7111 _("Send cancelled (Host/domain name must be provided before sending)"));
7116 snprintf(prompt
, sizeof(prompt
), _("Preserve %.*s as \"user-domain\" in PINERC"),
7117 sizeof(prompt
)-50, answer
);
7118 prompt
[sizeof(prompt
)-1] = '\0';
7119 if(!ps_global
->userdomain
&& !ps_global
->blank_user_domain
7120 && want_to(prompt
, 'y', 'n', NO_HELP
, WT_NORM
) == 'y'){
7121 set_variable(V_USER_DOMAIN
, answer
, 1, 1, Main
);
7122 fs_give((void **)&(ps_global
->maildomain
)); /* blast old val */
7123 ps_global
->userdomain
= cpystr(answer
);
7124 ps_global
->maildomain
= ps_global
->userdomain
;
7127 fs_give((void **)&(ps_global
->maildomain
));
7128 ps_global
->userdomain
= cpystr(answer
);
7129 ps_global
->maildomain
= ps_global
->userdomain
;
7133 /* check for smtp server */
7134 if(!ps_global
->VAR_SMTP_SERVER
||
7135 !ps_global
->VAR_SMTP_SERVER
[0] ||
7136 !ps_global
->VAR_SMTP_SERVER
[0][0]){
7139 if(ps_global
->inbox_name
[0] == '{'){
7141 i
< sizeof(answer
)-1 && ps_global
->inbox_name
[i
+1] != '}'; i
++)
7142 answer
[i
] = ps_global
->inbox_name
[i
+1];
7149 snprintf(prompt
,sizeof(prompt
),_("SMTP server to forward message : "));
7150 prompt
[sizeof(prompt
)-1] = '\0';
7154 flags
= OE_APPEND_CURRENT
;
7155 rc
= optionally_enter(answer
,-FOOTER_ROWS(ps_global
),0,
7156 sizeof(answer
),prompt
,NULL
,help
,&flags
);
7161 help
= (help
== NO_HELP
) ? h_sticky_smtp
: NO_HELP
;
7169 if(rc
== 1 || (rc
== 0 && answer
[0] == '\0')) {
7170 q_status_message(SM_ORDER
, 3, 4,
7171 _("Send cancelled (SMTP server must be provided before sending)"));
7176 list
= (char **) fs_get(2 * sizeof(char *));
7177 list
[0] = cpystr(answer
);
7179 set_variable_list(V_SMTP_SERVER
, list
, TRUE
, Main
);
7180 fs_give((void *)&list
[0]);
7181 fs_give((void *)list
);
7187 #endif /* defined(DOS) || defined(OS2) */