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-2018 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
;
74 #define PHONE_HOME_VERSION ".count"
76 #define PHONE_HOME_HOST "vfemail.net"
79 * macro to bind pico's headerentry pointer to PINEFIELD "extdata" hook
81 #define HE(PF) ((struct headerentry *)((PF)->extdata))
87 int redraft(MAILSTREAM
**, ENVELOPE
**, BODY
**, char **, char **, REPLY_S
**,
88 REDRAFT_POS_S
**, PINEFIELD
**, ACTION_S
**, int);
89 int redraft_prompt(char *, char *, int);
90 int check_for_subject(METAENV
*);
91 int check_for_fcc(char *);
92 void free_prompts(PINEFIELD
*);
93 int postpone_prompt(void);
94 METAENV
*pine_simple_send_header(ENVELOPE
*, char **, char ***);
95 void call_mailer_file_result(char *, int);
96 void mark_address_failure_for_pico(METAENV
*);
98 *save_body_particulars(BODY
*);
99 void reset_body_particulars(BODY_PARTICULARS_S
*, BODY
*);
100 void free_body_particulars(BODY_PARTICULARS_S
*);
101 long message_format_for_pico(long, int (*)(int));
102 int send_exit_for_pico(struct headerentry
*, void (*)(void), int, char **);
103 void new_thread_on_blank_subject(void);
104 char *choose_a_priority(char *);
105 int dont_flow_this_time(void);
106 int mime_type_for_pico(char *);
107 char *cancel_for_pico(void (*)(void));
108 int filter_message_text(char *, ENVELOPE
*, BODY
*, STORE_S
**, METAENV
*);
109 void pine_send_newsgroup_name(char *, char*, size_t);
110 void outgoing2strings(METAENV
*, BODY
*, void **, PATMT
**, int);
111 void strings2outgoing(METAENV
*, BODY
**, PATMT
*, int);
112 void create_message_body_text(BODY
*, int);
113 void set_body_size(BODY
*);
114 int view_as_rich(char *, int);
115 int background_posting(int);
116 int valid_subject(char *, char **, char **,BUILDER_ARG
*,int *);
117 int build_addr_lcc(char *, char **, char **, BUILDER_ARG
*, int *);
118 int news_build(char *, char **, char **, BUILDER_ARG
*, int *);
119 void news_build_busy(void);
120 #if defined(DOS) || defined(OS2)
121 int dos_valid_from(void);
122 #endif /* defined(DOS) || defined(OS2) */
126 * Pointer to buffer to hold pointers into pine data that's needed by pico.
131 static char *g_rolenick
= NULL
;
134 static char *sending_filter_requested
;
135 static char background_requested
, flowing_requested
;
136 static unsigned call_mailer_flags
;
137 static char *priority_requested
;
139 /* local global to save busy_cue state */
140 static int news_busy_cue
= 0;
144 * Various useful strings
147 _("Continue INTERRUPTED composition (answering \"n\" won't erase it)")
149 _("Continue postponed composition (answering \"No\" won't erase it)")
151 _("Start composition from Form Letter Folder")
152 #define PSTPN_FORM_PMT \
153 _("Save to Postponed or Form letter folder? ")
155 _("Posted message may go to thousands of readers. Really post")
156 #define INTR_DEL_PMT \
157 _("Deleted messages will be removed from folder after use. Proceed")
161 * Macros to help sort out posting results
163 #define P_MAIL_WIN 0x01
164 #define P_MAIL_LOSE 0x02
165 #define P_MAIL_BITS 0x03
166 #define P_NEWS_WIN 0x04
167 #define P_NEWS_LOSE 0x08
168 #define P_NEWS_BITS 0x0C
169 #define P_FCC_WIN 0x10
170 #define P_FCC_LOSE 0x20
171 #define P_FCC_BITS 0x30
174 #define COMPOSE_MAIL_TITLE "COMPOSE MESSAGE"
178 * For check_for_subject and check_for_fcc
181 #define CF_MISSING 0x2
184 /*----------------------------------------------------------------------
185 Compose screen (not forward or reply). Set up envelope, call composer
187 Args: pine_state -- The usual pine structure
189 Little front end for the compose screen
192 compose_screen(struct pine
*pine_state
)
194 void (*prev_screen
)(struct pine
*) = pine_state
->prev_screen
,
195 (*redraw
)(void) = pine_state
->redrawer
;
197 pine_state
->redrawer
= NULL
;
198 ps_global
->next_screen
= SCREEN_FUN_NULL
;
199 mailcap_free(); /* free resources we won't be using for a while */
200 compose_mail(NULL
, NULL
, NULL
, NULL
, NULL
);
201 pine_state
->next_screen
= prev_screen
;
202 pine_state
->redrawer
= redraw
;
206 /*----------------------------------------------------------------------
207 Alternate compose screen. Set up role and call regular compose.
209 Args: pine_state -- The usual pine structure
212 alt_compose_screen(struct pine
*pine_state
)
214 ACTION_S
*role
= NULL
;
215 void (*prev_screen
)(struct pine
*) = pine_state
->prev_screen
,
216 (*redraw
)(void) = pine_state
->redrawer
;
218 pine_state
->redrawer
= NULL
;
219 ps_global
->next_screen
= SCREEN_FUN_NULL
;
220 mailcap_free(); /* free resources we won't be using for a while */
223 if(role_select_screen(pine_state
, &role
, MC_COMPOSE
) < 0){
224 cmd_cancelled("Composition");
225 pine_state
->next_screen
= prev_screen
;
226 pine_state
->redrawer
= redraw
;
231 * If default role was selected (NULL) we need to make up a role which
232 * won't do anything, but will cause compose_mail to think there's
233 * already a role so that it won't try to confirm the default.
236 role
= combine_inherited_role(role
);
238 role
= (ACTION_S
*)fs_get(sizeof(*role
));
239 memset((void *)role
, 0, sizeof(*role
));
240 role
->nick
= cpystr("Default Role");
243 pine_state
->redrawer
= NULL
;
244 compose_mail(NULL
, NULL
, role
, NULL
, NULL
);
246 pine_state
->next_screen
= prev_screen
;
247 pine_state
->redrawer
= redraw
;
251 /*----------------------------------------------------------------------
252 Format envelope for outgoing message and call editor
254 Args: given_to -- An address to send mail to (usually from command line
256 fcc_arg -- The fcc that goes with this address.
258 If a "To" line is given format that into the envelope and get ready to call
260 If there's a message postponed, offer to continue it, and set it up,
261 otherwise just fill in the outgoing envelope as blank.
263 NOTE: we ignore postponed and interrupted messages in nr mode
266 compose_mail(char *given_to
, char *fcc_arg
, ACTION_S
*role_arg
,
267 PATMT
*attach
, gf_io_t inc_text_getc
)
270 ENVELOPE
*outgoing
= NULL
;
271 PINEFIELD
*custom
= NULL
;
272 REPLY_S
*reply
= NULL
;
273 REDRAFT_POS_S
*redraft_pos
= NULL
;
274 ACTION_S
*role
= NULL
;
280 int fcc_is_sticky
= 0,
287 "\n\n ---- COMPOSE SCREEN (not in pico yet) ----\n"));
289 /*-- Check for INTERRUPTED mail --*/
290 if(!role_arg
&& !(given_to
|| attach
)){
291 char file_path
[MAXPATH
+1];
293 /* build filename and see if it exists. build_path creates
294 * an explicit local path name, so all c-client access is thru
298 build_path(file_path
,
299 ps_global
->VAR_OPER_DIR
? ps_global
->VAR_OPER_DIR
300 : ps_global
->home_dir
,
301 INTERRUPTED_MAIL
, sizeof(file_path
));
303 /* check to see if the folder exists, the user wants to continue
304 * and that we can actually read something in...
306 if(folder_exists(NULL
, file_path
) & FEX_ISFILE
)
310 /*-- Check for postponed mail --*/
312 && !outgoing
/* not replying/forwarding */
313 && !(given_to
|| attach
) /* not command line send */
314 && ps_global
->VAR_POSTPONED_FOLDER
/* folder to look in */
315 && ps_global
->VAR_POSTPONED_FOLDER
[0])
318 /*-- Check for form letter folder --*/
320 && !outgoing
/* not replying/forwarding */
321 && !(given_to
|| attach
) /* not command line send */
322 && ps_global
->VAR_FORM_FOLDER
/* folder to look in */
323 && ps_global
->VAR_FORM_FOLDER
[0])
326 if(!outgoing
&& !(given_to
|| attach
)
327 && !role_arg
&& F_ON(F_ALT_COMPOSE_MENU
, ps_global
)){
332 char *intrpt
= "Interrupted";
333 char *postpnd
= "Postponed";
334 char *formltr
= "FormLetter";
335 char *roles
= "setRole";
336 HelpType help
= h_composer_browse
;
337 ESCKEY_S compose_style
[6];
342 compose_style
[ekey_num
].ch
= 'n';
343 compose_style
[ekey_num
].rval
= 'n';
344 compose_style
[ekey_num
].name
= "N";
345 compose_style
[ekey_num
++].label
= new;
348 compose_style
[ekey_num
].ch
= 'i';
349 compose_style
[ekey_num
].rval
= 'i';
350 compose_style
[ekey_num
].name
= "I";
351 compose_style
[ekey_num
++].label
= intrpt
;
355 compose_style
[ekey_num
].ch
= 'p';
356 compose_style
[ekey_num
].rval
= 'p';
357 compose_style
[ekey_num
].name
= "P";
358 compose_style
[ekey_num
++].label
= postpnd
;
362 compose_style
[ekey_num
].ch
= 'f';
363 compose_style
[ekey_num
].rval
= 'f';
364 compose_style
[ekey_num
].name
= "F";
365 compose_style
[ekey_num
++].label
= formltr
;
368 compose_style
[ekey_num
].ch
= 'r';
369 compose_style
[ekey_num
].rval
= 'r';
370 compose_style
[ekey_num
].name
= "R";
371 compose_style
[ekey_num
++].label
= roles
;
373 compose_style
[ekey_num
].ch
= -1;
375 if(F_ON(F_BLANK_KEYMENU
,ps_global
)){
380 for(ekey_num
= 0; compose_style
[ekey_num
].ch
!= -1; ekey_num
++){
381 if(p
- letters
< sizeof(letters
))
382 *p
++ = (char) compose_style
[ekey_num
].ch
;
384 if(compose_style
[ekey_num
+ 1].ch
!= -1 && p
- letters
< sizeof(letters
))
388 if(p
- letters
< sizeof(letters
))
392 which_help
= intrptd
+ 2 * postponed
+ 4 * form
;
395 help
= h_compose_intrptd
;
398 help
= h_compose_postponed
;
401 help
= h_compose_intrptd_postponed
;
404 help
= h_compose_form
;
407 help
= h_compose_intrptd_form
;
410 help
= h_compose_postponed_form
;
413 help
= h_compose_intrptd_postponed_form
;
416 help
= h_compose_default
;
420 snprintf(prompt
, sizeof(prompt
),
421 "Choose a compose method from %s : ",
422 F_ON(F_BLANK_KEYMENU
,ps_global
) ? letters
: "the menu below");
423 prompt
[sizeof(prompt
)-1] = '\0';
425 chosen_task
= radio_buttons(prompt
, -FOOTER_ROWS(ps_global
),
426 compose_style
, 'n', 'x', help
, RB_NORM
);
427 intrptd
= postponed
= form
= 0;
438 void (*prev_screen
)(struct pine
*) = ps_global
->prev_screen
,
439 (*redraw
)(void) = ps_global
->redrawer
;
441 ps_global
->redrawer
= NULL
;
442 ps_global
->next_screen
= SCREEN_FUN_NULL
;
443 if(role_select_screen(ps_global
, &role
, MC_COMPOSE
) < 0){
444 cmd_cancelled("Composition");
445 ps_global
->next_screen
= prev_screen
;
446 ps_global
->redrawer
= redraw
;
450 ps_global
->next_screen
= prev_screen
;
451 ps_global
->redrawer
= redraw
;
453 role
= combine_inherited_role(role
);
462 q_status_message(SM_ORDER
, 0, 3,
463 "Composition cancelled");
472 if(intrptd
&& !outgoing
){
473 char file_path
[MAXPATH
+1];
477 build_path(file_path
,
478 ps_global
->VAR_OPER_DIR
? ps_global
->VAR_OPER_DIR
479 : ps_global
->home_dir
,
480 INTERRUPTED_MAIL
, sizeof(file_path
));
481 if(folder_exists(NULL
, file_path
) & FEX_ISFILE
){
482 if((stream
= pine_mail_open(NULL
, file_path
,
483 SP_USEPOOL
|SP_TEMPUSE
, NULL
))
484 && !stream
->halfopen
){
486 if(F_ON(F_ALT_COMPOSE_MENU
, ps_global
) ||
487 (ret
= redraft_prompt("Interrupted",INTRPT_PMT
,'n')) =='y'){
488 if(!redraft(&stream
, &outgoing
, &body
, &fcc
, &lcc
, &reply
,
489 &redraft_pos
, &custom
, &role
, REDRAFT_DEL
)){
491 pine_mail_close(stream
);
498 /* redraft() may or may not have closed stream */
500 pine_mail_close(stream
);
502 postponed
= form
= 0;
505 pine_mail_close(stream
);
507 q_status_message(SM_ORDER
, 0, 3,
508 _("Composition cancelled"));
514 q_status_message1(SM_ORDER
| SM_DING
, 3, 3,
515 _("Can't open Interrupted mailbox: %s"),
518 pine_mail_close(stream
);
523 if(postponed
&& !outgoing
){
524 int ret
= 'n', done
= 0;
527 if((exists
=postponed_stream(&stream
,
528 ps_global
->VAR_POSTPONED_FOLDER
,
529 "Postponed", 0)) & FEX_ISFILE
){
530 if(F_ON(F_ALT_COMPOSE_MENU
, ps_global
) ||
531 (ret
= redraft_prompt("Postponed",PSTPND_PMT
,'n')) == 'y'){
532 if(!redraft(&stream
, &outgoing
, &body
, &fcc
, &lcc
, &reply
,
533 &redraft_pos
, &custom
, &role
,
534 REDRAFT_DEL
| REDRAFT_PPND
))
537 /* stream may or may not be closed in redraft() */
538 if(stream
&& (stream
!= ps_global
->mail_stream
))
539 pine_mail_close(stream
);
545 if(stream
!= ps_global
->mail_stream
)
546 pine_mail_close(stream
);
549 q_status_message(SM_ORDER
, 0, 3,
550 _("Composition cancelled"));
555 else if(F_ON(F_ALT_COMPOSE_MENU
, ps_global
))
562 if(form
&& !outgoing
){
563 int ret
= 'n', done
= 0;
566 if((exists
=postponed_stream(&stream
,
567 ps_global
->VAR_FORM_FOLDER
,
568 "Form letter", 1)) & FEX_ISFILE
){
569 if(F_ON(F_ALT_COMPOSE_MENU
, ps_global
) ||
570 (ret
= want_to(FORM_PMT
,'y','x',NO_HELP
,WT_NORM
))=='y'){
571 if(!redraft(&stream
, &outgoing
, &body
, &fcc
, &lcc
, &reply
,
572 &redraft_pos
, &custom
, &role
, REDRAFT_NONE
))
575 /* stream may or may not be closed in redraft() */
576 if(stream
&& (stream
!= ps_global
->mail_stream
))
577 pine_mail_close(stream
);
580 intrptd
= postponed
= 0;
583 if(stream
!= ps_global
->mail_stream
)
584 pine_mail_close(stream
);
587 q_status_message(SM_ORDER
, 0, 3,
588 _("Composition cancelled"));
594 if(F_ON(F_ALT_COMPOSE_MENU
, ps_global
)){
595 q_status_message(SM_ORDER
| SM_DING
, 3, 3,
596 _("Form letter folder doesn't exist!"));
605 /*-- normal composition --*/
607 int impl
, template_len
= 0;
608 long rflags
= ROLE_COMPOSE
;
611 /*================= Compose new message ===============*/
612 body
= mail_newbody();
613 outgoing
= mail_newenvelope();
616 rfc822_parse_adrlist(&outgoing
->to
, given_to
, ps_global
->maildomain
);
618 outgoing
->message_id
= generate_message_id();
621 * Setup possible role
624 role
= copy_action(role_arg
);
627 /* Setup possible compose role */
628 if(nonempty_patterns(rflags
, &dummy
)){
631 * Msgno = -1 means there is no msg.
632 * This will match roles which have the Compose Use turned
633 * on, and have no patterns set, and match the Current
636 role
= set_role_from_msg(ps_global
, rflags
, -1L, NULL
);
638 if(confirm_role(rflags
, &role
))
639 role
= combine_inherited_role(role
);
640 else{ /* cancel reply */
642 cmd_cancelled("Composition");
649 q_status_message1(SM_ORDER
, 3, 4, _("Composing using role \"%s\""),
653 * The type of storage object allocated below is vitally
654 * important. See SIMPLIFYING ASSUMPTION #37
656 if((body
->contents
.text
.data
= (void *) so_get(PicoText
,
657 NULL
, EDIT_ACCESS
)) != NULL
){
661 while((*inc_text_getc
)(&ch
))
662 if(!so_writec(ch
, (STORE_S
*)body
->contents
.text
.data
)){
668 q_status_message(SM_ORDER
| SM_DING
, 3, 4,
669 _("Problem creating space for message text."));
673 if(role
&& role
->template){
676 impl
= 1; /* leave cursor in header if not explicit */
677 filtered
= detoken(role
, NULL
, 0, 0, 0, &redraft_pos
, &impl
);
680 so_puts((STORE_S
*)body
->contents
.text
.data
, filtered
);
682 template_len
= strlen(filtered
);
685 fs_give((void **)&filtered
);
691 if((sig
= detoken(role
, NULL
, 2, 0, 1, &redraft_pos
, &impl
)) != NULL
){
693 redraft_pos
->offset
+= template_len
;
696 so_puts((STORE_S
*)body
->contents
.text
.data
, sig
);
698 fs_give((void **)&sig
);
701 body
->type
= TYPETEXT
;
704 create_message_body(&body
, attach
, 0);
707 ps_global
->prev_screen
= compose_screen
;
708 if(!(fcc_to_free
= fcc
) && !(role
&& role
->fcc
))
709 fcc
= fcc_arg
; /* Didn't pick up fcc, use given */
712 * check whether a build_address-produced fcc is different from
713 * fcc. If same, do nothing, if different, set sticky bit in pine_send.
716 char *tmp_fcc
= NULL
;
719 tmp_fcc
= get_fcc_based_on_to(outgoing
->to
);
720 if(strcmp(fcc
, tmp_fcc
? tmp_fcc
: ""))
721 fcc_is_sticky
++; /* cause sticky bit to get set */
724 else if((tmp_fcc
= get_fcc(NULL
)) != NULL
&&
725 !strcmp(fcc
, tmp_fcc
)){
732 fs_give((void **)&tmp_fcc
);
735 pine_send(outgoing
, &body
, COMPOSE_MAIL_TITLE
, role
, fcc
,
736 reply
, redraft_pos
, lcc
, custom
,
737 (fcc_is_sticky
? PS_STICKY_FCC
: 0) | (to_is_sticky
? PS_STICKY_TO
: 0));
741 fs_give((void **) &reply
->mailbox
);
743 fs_give((void **) &reply
->origmbox
);
745 fs_give((void **) &reply
->prefix
);
746 if(reply
->data
.uid
.msgs
)
747 fs_give((void **) &reply
->data
.uid
.msgs
);
748 fs_give((void **) &reply
);
752 fs_give((void **)&fcc_to_free
);
755 fs_give((void **)&lcc
);
757 mail_free_envelope(&outgoing
);
758 pine_free_body(&body
);
759 free_redraft_pos(&redraft_pos
);
764 /*----------------------------------------------------------------------
765 Args: stream -- This is where we get the postponed messages from
766 We'll expunge and close it here unless it is mail_stream.
768 These are all return values:
784 redraft(MAILSTREAM
**streamp
, ENVELOPE
**outgoing
, struct mail_bodystruct
**body
,
785 char **fcc
, char **lcc
, REPLY_S
**reply
, REDRAFT_POS_S
**redraft_pos
,
786 PINEFIELD
**custom
, ACTION_S
**role
, int flags
)
792 if(!(streamp
&& *streamp
))
798 * If we're manipulating the current folder, don't bother
802 if(REDRAFT_PPND
&flags
)
803 q_status_message(SM_ORDER
| SM_DING
, 3, 5, _("Empty folder! No messages really postponed!"));
805 q_status_message(SM_ORDER
| SM_DING
, 3, 5, _("Empty folder! No messages really interrupted!"));
807 return(redraft_cleanup(streamp
, FALSE
, flags
));
809 else if(stream
== ps_global
->mail_stream
810 && ps_global
->prev_screen
== mail_index_screen
){
812 * Since the user's got this folder already opened and they're
813 * on a selected message, pick that one rather than rebuild
814 * another index screen...
816 cont_msg
= mn_m2raw(ps_global
->msgmap
, mn_get_cur(ps_global
->msgmap
));
818 else if(stream
->nmsgs
> 1L){ /* offer browser ? */
821 if(REDRAFT_PPND
&flags
){ /* set to last message postponed */
822 mn_set_cur(sp_msgmap(stream
),
823 mn_get_revsort(sp_msgmap(stream
))
824 ? 1L : mn_get_total(sp_msgmap(stream
)));
826 else{ /* set to top form letter */
827 mn_set_cur(sp_msgmap(stream
), 1L);
830 clear_index_cache(stream
, 0);
834 ti
= stop_threading_temporarily();
835 rv
= index_lister(ps_global
, NULL
, stream
->mailbox
,
836 stream
, sp_msgmap(stream
));
837 restore_threading(&ti
);
839 cont_msg
= mn_m2raw(sp_msgmap(stream
), mn_get_cur(sp_msgmap(stream
)));
840 if(count_flagged(stream
, F_DEL
)
841 && want_to(INTR_DEL_PMT
, 'n', 0, NO_HELP
, WT_NORM
) == 'n'){
842 if(REDRAFT_PPND
&flags
)
843 q_status_message(SM_ORDER
, 3, 3, _("Undelete messages to remain postponed, and then continue message"));
845 q_status_message(SM_ORDER
, 3, 3, _("Undelete form letters you want to keep, and then continue message"));
853 clear_index_cache(stream
, 0);
856 q_status_message(SM_ORDER
, 0, 3, _("Composition cancelled"));
857 (void) redraft_cleanup(streamp
, FALSE
, flags
);
859 if(!*streamp
&& !ps_global
->mail_stream
){
860 q_status_message2(SM_ORDER
, 3, 7,
861 "No more %.200s, returning to \"%.200s\"",
862 (REDRAFT_PPND
&flags
) ? "postponed messages"
864 ps_global
->inbox_name
);
865 if(ps_global
&& ps_global
->ttyo
){
866 blank_keymenu(ps_global
->ttyo
->screen_rows
- 2, 0);
867 ps_global
->mangled_footer
= 1;
870 do_broach_folder(ps_global
->inbox_name
,
871 ps_global
->context_list
, NULL
, DB_INBOXWOCNTXT
);
873 ps_global
->next_screen
= mail_index_screen
;
876 return(0); /* special case */
880 if((so
= (void *) so_get(PicoText
, NULL
, EDIT_ACCESS
)) != NULL
)
881 return(redraft_work(streamp
, cont_msg
, outgoing
, body
,
882 fcc
, lcc
, reply
, redraft_pos
, custom
,
890 redraft_prompt(char *type
, char *prompt
, int failure
)
892 if(background_posting(FALSE
)){
893 q_status_message1(SM_ORDER
, 0, 3,
894 _("%s folder unavailable while background posting"),
899 return(want_to(prompt
, 'y', 'x', NO_HELP
, WT_NORM
));
903 /* this is for initializing the fixed header elements in pine_send() */
905 prompt::name::help::prwid::maxlen::realaddr::
906 builder::affected_entry::next_affected::selector::key_label::fileedit::
907 display_it::break_on_comma::is_attach::rich_header::only_file_chars::
908 single_space::sticky::dirty::start_here::blank::sticky_special::KS_ODATAVAR
910 static struct headerentry he_template
[]={
911 {"", "X-Auth-Received", NO_HELP
, 10, 0, NULL
,
912 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
913 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KS_NONE
},
914 {"From : ", "From", h_composer_from
, 10, 0, NULL
,
915 build_address
, NULL
, NULL
, addr_book_compose
, "To AddrBk", NULL
, abook_nickname_complete
,
916 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, KS_TOADDRBOOK
},
917 {"Reply-To: ", "Reply To", h_composer_reply_to
, 10, 0, NULL
,
918 build_address
, NULL
, NULL
, addr_book_compose
, "To AddrBk", NULL
, abook_nickname_complete
,
919 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, KS_TOADDRBOOK
},
920 {"To : ", "To", h_composer_to
, 10, 0, NULL
,
921 build_address
, NULL
, NULL
, addr_book_compose
, "To AddrBk", NULL
, abook_nickname_complete
,
922 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, KS_TOADDRBOOK
},
923 {"Cc : ", "Cc", h_composer_cc
, 10, 0, NULL
,
924 build_address
, NULL
, NULL
, addr_book_compose
, "To AddrBk", NULL
, abook_nickname_complete
,
925 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, KS_TOADDRBOOK
},
926 {"Bcc : ", "Bcc", h_composer_bcc
, 10, 0, NULL
,
927 build_address
, NULL
, NULL
, addr_book_compose
, "To AddrBk", NULL
, abook_nickname_complete
,
928 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, KS_TOADDRBOOK
},
929 {"Newsgrps: ", "Newsgroups", h_composer_news
, 10, 0, NULL
,
930 news_build
, NULL
, NULL
, news_group_selector
, "To NwsGrps", NULL
, NULL
,
931 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, KS_NONE
},
932 {"Fcc : ", "Fcc", h_composer_fcc
, 10, 0, NULL
,
933 NULL
, NULL
, NULL
, folders_for_fcc
, "To Fldrs", NULL
, fcc_tab_complete
,
934 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, KS_NONE
},
935 {"Lcc : ", "Lcc", h_composer_lcc
, 10, 0, NULL
,
936 build_addr_lcc
, NULL
, NULL
, addr_book_compose_lcc
,"To AddrBk", NULL
, abook_nickname_complete
,
937 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, KS_NONE
},
938 {"Attchmnt: ", "Attchmnt", h_composer_attachment
, 10, 0, NULL
,
939 NULL
, NULL
, NULL
, NULL
, "To Files", NULL
, NULL
,
940 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, KS_NONE
},
941 {"Subject : ", "Subject", h_composer_subject
, 10, 0, NULL
,
942 valid_subject
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
943 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KS_NONE
},
944 {"", "References", NO_HELP
, 10, 0, NULL
,
945 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
946 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KS_NONE
},
947 {"", "Date", NO_HELP
, 10, 0, NULL
,
948 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
949 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KS_NONE
},
950 {"", "In-Reply-To", NO_HELP
, 10, 0, NULL
,
951 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
952 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KS_NONE
},
953 {"", "Message-ID", NO_HELP
, 10, 0, NULL
,
954 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
955 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KS_NONE
},
956 {"", "X-Priority", NO_HELP
, 10, 0, NULL
,
957 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
958 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KS_NONE
},
959 {"", "User-Agent", NO_HELP
, 10, 0, NULL
,
960 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
961 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KS_NONE
},
962 {"", "To", NO_HELP
, 10, 0, NULL
,
963 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
964 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KS_NONE
},
965 {"", "X-Post-Error",NO_HELP
, 10, 0, NULL
,
966 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
967 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KS_NONE
},
968 {"", "X-Reply-UID", NO_HELP
, 10, 0, NULL
,
969 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
970 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KS_NONE
},
971 {"", "X-Reply-Mbox", NO_HELP
, 10, 0, NULL
,
972 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
973 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KS_NONE
},
974 {"", "X-SMTP-Server", NO_HELP
, 10, 0, NULL
,
975 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
976 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KS_NONE
},
977 {"", "X-Cursor-Pos", NO_HELP
, 10, 0, NULL
,
978 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
979 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KS_NONE
},
980 {"", "X-Our-ReplyTo", NO_HELP
, 10, 0, NULL
,
981 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
982 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KS_NONE
},
983 {"", OUR_HDRS_LIST
, NO_HELP
, 10, 0, NULL
,
984 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
985 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KS_NONE
},
986 {"", "X-Auth-Received", NO_HELP
, 10, 0, NULL
,
987 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
988 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KS_NONE
},
989 #if !(defined(DOS) || defined(OS2)) || defined(NOAUTH)
990 {"", "Sender", 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
}
997 static struct headerentry he_custom_addr_templ
={
998 NULL
, NULL
, h_composer_custom_addr
,10, 0, NULL
,
999 build_address
, NULL
, NULL
, addr_book_compose
, "To AddrBk", NULL
, abook_nickname_complete
,
1000 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, KS_TOADDRBOOK
};
1002 static struct headerentry he_custom_free_templ
={
1003 NULL
, NULL
, h_composer_custom_free
,10, 0, NULL
,
1004 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1005 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, KS_NONE
};
1008 /*----------------------------------------------------------------------
1009 Get addressee for message, then post message
1011 Args: outgoing -- Partially formatted outgoing ENVELOPE
1012 body -- Body of outgoing message
1013 prmpt_who -- Optional prompt for optionally_enter call
1014 prmpt_cnf -- Optional prompt for confirmation call
1015 used_tobufval -- The string that the to was eventually set equal to.
1016 This gets passed back if non-NULL on entry.
1017 flagsarg -- SS_PROMPTFORTO - Allow user to change recipient
1018 SS_NULLRP - Use null return-path so we'll send an
1021 Result: message "To: " field is provided and message is sent or cancelled.
1030 subject passed in, NOT edited but maybe canonized here
1031 to possibly passed in, edited and canonized here
1037 Can only deal with message bodies that are either TYPETEXT or TYPEMULTIPART
1038 with the first part TYPETEXT! All newlines in the text here also end with
1041 Returns 0 on success, -1 on failure.
1044 pine_simple_send(ENVELOPE
*outgoing
, /* envelope for outgoing message */
1045 struct mail_bodystruct
**body
,
1049 char **used_tobufval
,
1052 char **tobufp
, *p
, tmp
[MAILTMPLEN
];
1054 int done
= 0, retval
= 0, x
;
1055 int lastrc
, rc
= 0, ku
, i
, resize_len
, result
, fcc_result
;
1058 static HISTORY_S
*history
= NULL
;
1062 ACTION_S
*role
= rolep
? *rolep
: NULL
;
1065 dprint((1,"\n === simple send called === \n"));
1067 memset(&ba_fcc
, 0, sizeof(BUILDER_ARG
));
1069 init_hist(&history
, HISTSIZE
);
1071 header
= pine_simple_send_header(outgoing
, &ba_fcc
.tptr
, &tobufp
);
1073 /*----- Fill in a few general parts of the envelope ----*/
1074 if(!outgoing
->date
){
1075 if(F_ON(F_QUELL_TIMEZONE
, ps_global
))
1076 mail_parameters(NULL
, SET_DISABLE822TZTEXT
, (void *) TRUE
);
1078 rfc822_date(tmp_20k_buf
); /* format and copy new date */
1079 if(F_ON(F_QUELL_TIMEZONE
, ps_global
))
1080 mail_parameters(NULL
, SET_DISABLE822TZTEXT
, (void *) FALSE
);
1082 outgoing
->date
= (unsigned char *) cpystr(tmp_20k_buf
);
1085 if(!outgoing
->from
){
1086 if(role
&& role
->from
){
1087 if(ps_global
->never_allow_changing_from
)
1088 q_status_message(SM_ORDER
, 3, 3, _("Site policy doesn't allow changing From address so role's From has no effect"));
1090 outgoing
->from
= copyaddrlist(role
->from
);
1093 outgoing
->from
= generate_from();
1096 if(!(flagsarg
& SS_NULLRP
))
1097 outgoing
->return_path
= rfc822_cpy_adr(outgoing
->from
);
1099 ekey
[i
= 0].ch
= ctrl('T');
1101 ekey
[i
].name
= "^T";
1102 ekey
[i
++].label
= N_("To AddrBk");
1104 if(F_ON(F_ENABLE_TAB_COMPLETE
,ps_global
)){
1105 ekey
[i
].ch
= ctrl('I');
1107 ekey
[i
].name
= "TAB";
1108 ekey
[i
++].label
= N_("Complete");
1111 if(nonempty_patterns(ROLE_DO_ROLES
, &pstate
) && first_pattern(&pstate
)){
1112 ekey
[i
].ch
= ctrl('R');
1114 ekey
[i
].name
= "^R";
1115 ekey
[i
++].label
= "Set Role";
1118 ekey
[i
].ch
= KEY_UP
;
1122 ekey
[i
++].label
= "";
1124 ekey
[i
].ch
= KEY_DOWN
;
1127 ekey
[i
++].label
= "";
1131 if(outgoing
->remail
== NULL
)
1132 strcpy(tmp
, _("FORWARD (as e-mail) to : "));
1134 /*----------------------------------------------------------------------
1135 Loop editing the "To: " field until everything goes well
1142 if(outgoing
->remail
){
1144 snprintf(tmp
, sizeof(tmp
), _("BOUNCE (redirect) message using role \"%s\" to : "), role
->nick
);
1146 strncpy(tmp
, _("BOUNCE (redirect) message to : "), sizeof(tmp
));
1147 tmp
[sizeof(tmp
)-1] = '\0';
1152 outgoing2strings(header
, *body
, &messagebuf
, NULL
, 1);
1156 if(flagsarg
& SS_PROMPTFORTO
){
1158 *tobufp
= cpystr("");
1160 resize_len
= MAX(MAXPATH
, strlen(*tobufp
));
1161 fs_resize((void **) tobufp
, resize_len
+1);
1163 if(items_in_hist(history
) > 0){
1164 ekey
[ku
].name
= HISTORY_UP_KEYNAME
;
1165 ekey
[ku
].label
= HISTORY_KEYLABEL
;
1166 ekey
[ku
+1].name
= HISTORY_DOWN_KEYNAME
;
1167 ekey
[ku
+1].label
= HISTORY_KEYLABEL
;
1171 ekey
[ku
].label
= "";
1172 ekey
[ku
+1].name
= "";
1173 ekey
[ku
+1].label
= "";
1176 flags
= OE_APPEND_CURRENT
;
1178 rc
= optionally_enter(*tobufp
, -FOOTER_ROWS(ps_global
),
1183 ekey
, help
, &flags
);
1190 q_status_message(SM_ORDER
| SM_DING
, 3, 4,
1191 "Internal problem encountered");
1196 case 15 : /* set a role */
1197 {void (*prev_screen
)(struct pine
*) = NULL
, (*redraw
)(void) = NULL
;
1199 redraw
= ps_global
->redrawer
;
1200 ps_global
->redrawer
= NULL
;
1201 prev_screen
= ps_global
->prev_screen
;
1203 ps_global
->next_screen
= SCREEN_FUN_NULL
;
1205 if(role_select_screen(ps_global
, &role
,
1206 outgoing
->remail
? MC_BOUNCE
: MC_FORWARD
) < 0)
1207 cmd_cancelled(_("Set Role"));
1210 role
= combine_inherited_role(role
);
1212 role
= (ACTION_S
*) fs_get(sizeof(*role
));
1213 memset((void *) role
, 0, sizeof(*role
));
1214 role
->nick
= cpystr("Default Role");
1221 ps_global
->next_screen
= prev_screen
;
1222 ps_global
->redrawer
= redraw
;
1223 ps_global
->mangled_screen
= 1;
1225 if(role
&& role
->from
&& !ps_global
->never_allow_changing_from
){
1226 mail_free_address (&outgoing
->from
);
1227 outgoing
->from
= copyaddrlist(role
->from
);
1229 if(rolep
) *rolep
= role
;
1234 if((p
= get_prev_hist(history
, *tobufp
, 0, NULL
)) != NULL
){
1235 strncpy(*tobufp
, p
, resize_len
);
1236 (*tobufp
)[resize_len
-1] = '\0';
1244 if((p
= get_next_hist(history
, *tobufp
, 0, NULL
)) != NULL
){
1245 strncpy(*tobufp
, p
, resize_len
);
1246 (*tobufp
)[resize_len
-1] = '\0';
1255 {void (*redraw
) (void) = ps_global
->redrawer
;
1256 char *returned_addr
= NULL
;
1260 int got_something
= 0;
1262 push_titlebar_state();
1263 returned_addr
= addr_book_bounce();
1266 * Just make it look like user typed this list in.
1270 if((l
=resize_len
) < (len
= strlen(returned_addr
)) + 1){
1272 fs_resize((void **) tobufp
, (size_t) (l
+1));
1275 strncpy(*tobufp
, returned_addr
, l
);
1276 (*tobufp
)[l
] = '\0';
1277 fs_give((void **)&returned_addr
);
1281 pop_titlebar_state();
1283 if((ps_global
->redrawer
= redraw
) != NULL
) /* reset old value, and test */
1284 (*ps_global
->redrawer
)();
1290 if(*tobufp
&& **tobufp
!= '\0'){
1291 char *errbuf
, *addr
;
1294 save_hist(history
, *tobufp
, 0, NULL
);
1299 * If role has an fcc, use it instead of what build_address
1302 if(role
&& role
->fcc
){
1304 fs_give((void **) &ba_fcc
.tptr
);
1306 ba_fcc
.tptr
= cpystr(role
->fcc
);
1309 if(build_address(*tobufp
, &addr
, &errbuf
,
1310 (role
&& role
->fcc
) ? NULL
: &ba_fcc
, NULL
) >= 0){
1314 fs_give((void **)&errbuf
);
1316 if((l
=strlen(*tobufp
)) < (tolen
= strlen(addr
)) + 1){
1318 fs_resize((void **) tobufp
, (size_t) (l
+1));
1321 strncpy(*tobufp
, addr
, l
);
1322 (*tobufp
)[l
] = '\0';
1324 *used_tobufval
= cpystr(addr
);
1326 /* confirm address */
1327 if(flagsarg
& SS_PROMPTFORTO
){
1328 char dsn_string
[30];
1329 int dsn_label
= 0, dsn_show
, i
;
1330 int verbose_label
= 0;
1333 strings2outgoing(header
, body
, NULL
, 0);
1335 if((flagsarg
& SS_PROMPTFORTO
)
1336 && ((x
= check_addresses(header
)) == CA_BAD
1337 || (x
== CA_EMPTY
&& F_OFF(F_FCC_ON_BOUNCE
,
1339 /*--- Addresses didn't check out---*/
1346 opts
[i
++].label
= N_("Yes");
1351 opts
[i
++].label
= N_("No");
1353 call_mailer_flags
&= ~CM_VERBOSE
; /* clear verbose */
1354 if(F_ON(F_VERBOSE_POST
, ps_global
)){
1355 /* setup keymenu slot to toggle verbose mode */
1356 opts
[i
].ch
= ctrl('W');
1358 opts
[i
].name
= "^W";
1359 verbose_label
= i
++;
1360 if(F_ON(F_DSN
, ps_global
)){
1364 opts
[i
++].label
= "";
1368 /* clear DSN flags */
1369 call_mailer_flags
&= ~(CM_DSN_NEVER
| CM_DSN_DELAY
| CM_DSN_SUCCESS
| CM_DSN_FULL
);
1370 if(F_ON(F_DSN
, ps_global
)){
1371 /* setup keymenu slots to toggle dsn bits */
1375 opts
[i
].label
= "DSNOpts";
1380 opts
[i
++].label
= "";
1384 opts
[i
++].label
= "";
1388 opts
[i
++].label
= "";
1396 dsn_show
= (call_mailer_flags
& CM_DSN_SHOW
);
1397 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
,
1398 "%s%s%s%s%s%sto \"%s\" ? ",
1399 prmpt_cnf
? prmpt_cnf
: "Send message ",
1400 ((call_mailer_flags
& CM_VERBOSE
)
1403 (call_mailer_flags
& CM_VERBOSE
)
1404 ? "in verbose mode" : "",
1405 (dsn_show
&& (call_mailer_flags
& CM_VERBOSE
))
1407 (dsn_show
) ? dsn_string
: "",
1408 ((call_mailer_flags
& CM_VERBOSE
) || dsn_show
)
1412 : (F_ON(F_FCC_ON_BOUNCE
, ps_global
)
1413 && ba_fcc
.tptr
&& ba_fcc
.tptr
[0])
1416 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
1418 if((strlen(tmp_20k_buf
) >
1419 ps_global
->ttyo
->screen_cols
- 2) &&
1420 ps_global
->ttyo
->screen_cols
>= 7)
1421 strncpy(tmp_20k_buf
+ps_global
->ttyo
->screen_cols
-7,
1422 "...? ", SIZEOF_20KBUF
-ps_global
->ttyo
->screen_cols
-7);
1424 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
1427 opts
[verbose_label
].label
=
1428 /* TRANSLATORS: several possible key labels follow */
1429 (call_mailer_flags
& CM_VERBOSE
) ? N_("Normal") : N_("Verbose");
1431 if(F_ON(F_DSN
, ps_global
)){
1432 if(call_mailer_flags
& CM_DSN_SHOW
){
1433 opts
[dsn_label
].label
=
1434 (call_mailer_flags
& CM_DSN_DELAY
)
1435 ? N_("NoDelay") : N_("Delay");
1436 opts
[dsn_label
+1].ch
= 's';
1437 opts
[dsn_label
+1].label
=
1438 (call_mailer_flags
& CM_DSN_SUCCESS
)
1439 ? N_("NoSuccess") : N_("Success");
1440 opts
[dsn_label
+2].ch
= 'x';
1441 opts
[dsn_label
+2].label
=
1442 (call_mailer_flags
& CM_DSN_NEVER
)
1443 ? N_("ErrRets") : N_("NoErrRets");
1444 opts
[dsn_label
+3].ch
= 'h';
1445 opts
[dsn_label
+3].label
=
1446 (call_mailer_flags
& CM_DSN_FULL
)
1447 ? N_("RetHdrs") : N_("RetFull");
1451 rv
= radio_buttons(tmp_20k_buf
,
1452 -FOOTER_ROWS(ps_global
), opts
,
1453 'y', 'z', NO_HELP
, RB_NORM
);
1454 if(rv
== 'y'){ /* user ACCEPTS! */
1458 else if(rv
== 'n'){ /* Declined! */
1461 else if(rv
== 'z'){ /* Cancelled! */
1464 else if(rv
== 12){ /* flip verbose bit */
1465 if(call_mailer_flags
& CM_VERBOSE
)
1466 call_mailer_flags
&= ~CM_VERBOSE
;
1468 call_mailer_flags
|= CM_VERBOSE
;
1470 else if(call_mailer_flags
& CM_DSN_SHOW
){
1471 if(rv
== 's'){ /* flip success bit */
1472 call_mailer_flags
^= CM_DSN_SUCCESS
;
1473 /* turn off related bits */
1474 if(call_mailer_flags
& CM_DSN_SUCCESS
)
1475 call_mailer_flags
&= ~(CM_DSN_NEVER
);
1477 else if(rv
== 'd'){ /* flip delay bit */
1478 call_mailer_flags
^= CM_DSN_DELAY
;
1479 /* turn off related bits */
1480 if(call_mailer_flags
& CM_DSN_DELAY
)
1481 call_mailer_flags
&= ~(CM_DSN_NEVER
);
1483 else if(rv
== 'x'){ /* flip never bit */
1484 call_mailer_flags
^= CM_DSN_NEVER
;
1485 /* turn off related bits */
1486 if(call_mailer_flags
& CM_DSN_NEVER
)
1487 call_mailer_flags
&= ~(CM_DSN_SUCCESS
| CM_DSN_DELAY
);
1489 else if(rv
== 'h'){ /* flip full bit */
1490 call_mailer_flags
^= CM_DSN_FULL
;
1493 else if(rv
== 'd'){ /* show dsn options */
1494 call_mailer_flags
|= (CM_DSN_SHOW
| CM_DSN_SUCCESS
| CM_DSN_DELAY
| CM_DSN_FULL
);
1497 snprintf(dsn_string
, sizeof(dsn_string
), _("DSN requested[%s%s%s%s]"),
1498 (call_mailer_flags
& CM_DSN_NEVER
)
1500 (call_mailer_flags
& CM_DSN_DELAY
)
1502 (call_mailer_flags
& CM_DSN_SUCCESS
)
1504 (call_mailer_flags
& CM_DSN_NEVER
)
1506 : (call_mailer_flags
& CM_DSN_FULL
) ? "-Full"
1508 dsn_string
[sizeof(dsn_string
)-1] = '\0';
1513 fs_give((void **)&addr
);
1515 if(!(flagsarg
& SS_PROMPTFORTO
) || sendit
){
1517 CONTEXT_S
*fcc_cntxt
= NULL
;
1519 if(F_ON(F_FCC_ON_BOUNCE
, ps_global
)){
1521 fcc
= cpystr(ba_fcc
.tptr
);
1526 * If special name "inbox" then replace it with the
1529 if(ps_global
->VAR_INBOX_PATH
1530 && strucmp(fcc
, ps_global
->inbox_name
) == 0){
1533 replace_fcc
= cpystr(ps_global
->VAR_INBOX_PATH
);
1534 fs_give((void **) &fcc
);
1539 /*---- Check out fcc -----*/
1541 (void) commence_fcc(fcc
, &fcc_cntxt
, FALSE
);
1543 dprint((4,"can't open fcc, cont\n"));
1544 if(!(flagsarg
& SS_PROMPTFORTO
)){
1546 fs_give((void **)&fcc
);
1554 so_truncate(lmc
.so
, fcc_size_guess(*body
) + 2048);
1559 if(!(outgoing
->to
|| outgoing
->cc
|| outgoing
->bcc
1561 q_status_message(SM_ORDER
, 3, 5, _("No recipients specified!"));
1565 if(outgoing
->to
|| outgoing
->cc
|| outgoing
->bcc
){
1566 char **alt_smtp
= NULL
;
1568 if(role
&& role
->smtp
){
1569 if(ps_global
->FIX_SMTP_SERVER
1570 && ps_global
->FIX_SMTP_SERVER
[0])
1571 q_status_message(SM_ORDER
| SM_DING
, 5, 5, _("Use of a role-defined smtp-server is administratively prohibited"));
1573 alt_smtp
= role
->smtp
;
1576 result
= call_mailer(header
, *body
, alt_smtp
,
1578 call_mailer_file_result
,
1580 mark_address_failure_for_pico(header
);
1585 if(result
== 1 && !lmc
.so
)
1586 q_status_message(SM_ORDER
, 0, 3, _("Message sent"));
1588 /*----- Was there an fcc involved? -----*/
1592 && pine_rfc822_output(header
, *body
, NULL
, NULL
))){
1595 strncpy(label
, "Fcc", sizeof(label
));
1596 label
[sizeof(label
)-1] = '\0';
1597 if(strcmp(fcc
, ps_global
->VAR_DEFAULT_FCC
)){
1598 snprintf(label
+ 3, sizeof(label
)-3, " to %s", fcc
);
1599 label
[sizeof(label
)-1] = '\0';
1602 /* Now actually copy to fcc folder and close */
1604 write_fcc(fcc
, fcc_cntxt
, lmc
.so
, NULL
,
1606 F_ON(F_MARK_FCC_SEEN
, ps_global
)
1609 else if(result
== 0){
1610 q_status_message(SM_ORDER
,3,5,
1611 _("Fcc Failed!. No message saved."));
1613 dprint((1, "explicit fcc write failed!\n"));
1620 dprint((1, "Bounce failed\n"));
1621 if(!(flagsarg
& SS_PROMPTFORTO
))
1626 else if(result
== 1){
1628 q_status_message(SM_ORDER
, 0, 3,
1631 int avail
= ps_global
->ttyo
->screen_cols
-2;
1633 char *part1
= "Message sent and ";
1634 char *part2
= fcc_result
? "" : "NOT ";
1635 char *part3
= "copied to ";
1636 fcclen
= strlen(fcc
);
1638 need
= 2 + strlen(part1
) + strlen(part2
) +
1639 strlen(part3
) + fcclen
;
1641 if(need
> avail
&& fcclen
> 6)
1642 fcclen
-= MIN(fcclen
-6, need
-avail
);
1644 q_status_message4(SM_ORDER
, 0, 3,
1646 part1
, part2
, part3
,
1648 (char *)tmp_20k_buf
,
1650 fcclen
, FrontDots
));
1655 fs_give((void **)&fcc
);
1658 q_status_message(SM_ORDER
, 0, 3, _("Send cancelled"));
1663 q_status_message1(SM_ORDER
| SM_DING
, 3, 5,
1664 _("Error in address: %s"), errbuf
);
1666 fs_give((void **)&errbuf
);
1668 if(!(flagsarg
& SS_PROMPTFORTO
))
1676 q_status_message(SM_ORDER
| SM_DING
, 3, 5,
1677 _("No addressee! No e-mail sent."));
1686 q_status_message(SM_ORDER
, 0, 3, _("Send cancelled"));
1692 help
= (help
== NO_HELP
)
1693 ? (outgoing
->remail
== NULL
1701 char *new_nickname
= NULL
;
1705 ambiguity
= abook_nickname_complete(*tobufp
, &new_nickname
,
1706 (lastrc
==rc
&& !(flags
& OE_USER_MODIFIED
)), ANC_AFTERCOMMA
);
1709 if((l
=strlen(new_nickname
)) > resize_len
){
1711 fs_resize((void **) tobufp
, resize_len
+1);
1714 strncpy(*tobufp
, new_nickname
, l
);
1715 (*tobufp
)[l
] = '\0';
1718 fs_give((void **) &new_nickname
);
1727 case 4: /* can't suspend */
1735 fs_give((void **)&ba_fcc
.tptr
);
1737 pine_free_env(&header
);
1744 * pine_simple_send_header - generate header suitable for simple_sending
1747 pine_simple_send_header(ENVELOPE
*outgoing
, char **fccp
, char ***tobufpp
)
1751 static struct headerentry he_dummy
;
1753 header
= pine_new_env(outgoing
, fccp
, tobufpp
, NULL
);
1755 /* assign he_dummy to "To:" field "he" for strings2outgoing */
1756 for(pf
= header
->local
; pf
&& pf
->name
; pf
= pf
->next
)
1757 if(pf
->type
== Address
&& !strucmp(pf
->name
, "to")){
1758 memset((void *) &he_dummy
, 0, sizeof(he_dummy
));
1759 pf
->extdata
= (void *) &he_dummy
;
1769 /*----------------------------------------------------------------------
1770 Prepare data structures for pico, call pico, then post message
1772 Args: outgoing -- Partially formatted outgoing ENVELOPE
1773 body -- Body of outgoing message
1774 editor_title -- Title for anchor line in composer
1775 fcc_arg -- The file carbon copy field
1776 reply -- Struct describing set of msgs being replied-to
1778 custom -- custom header list.
1781 Result: message is edited, then postponed, cancelled or sent.
1790 subject passed in, edited and cannonized here
1791 to possibly passed in, edited and cannonized here
1792 cc possibly passed in, edited and cannonized here
1793 bcc edited and cannonized here
1794 in_reply_to generated in reply() and passed in
1797 Storage for these fields comes from anywhere outside. It is remalloced
1798 here so the composer can realloc them if needed. The copies here are also
1801 Can only deal with message bodies that are either TYPETEXT or TYPEMULTIPART
1802 with the first part TYPETEXT! All newlines in the text here also end with
1805 There's a further assumption that the text in the TYPETEXT part is
1806 stored in a storage object (see filter.c).
1809 pine_send(ENVELOPE
*outgoing
, struct mail_bodystruct
**body
,
1810 char *editor_title
, ACTION_S
*role
, char *fcc_arg
,
1811 REPLY_S
*reply
, REDRAFT_POS_S
*redraft_pos
, char *lcc_arg
,
1812 PINEFIELD
*custom
, int flags
)
1814 int i
, fixed_cnt
, total_cnt
, index
,
1815 editor_result
= 0, body_start
= 0, use_news_order
= 0;
1816 char *p
, *addr
, *fcc
, *fcc_to_free
= NULL
;
1817 char *start_here_name
= NULL
;
1818 char *suggested_nntp_server
= NULL
;
1820 struct headerentry
*he
, *headents
, *he_to
, *he_fcc
, *he_news
= NULL
, *he_lcc
= NULL
,
1822 PINEFIELD
*pfields
, *pf
, *pf_nobody
= NULL
, *pf_to
= NULL
,
1823 *pf_smtp_server
, *pf_nntp_server
,
1824 *pf_fcc
= NULL
, *pf_err
, *pf_uid
, *pf_mbox
, *pf_curpos
,
1825 *pf_ourrep
, *pf_ourhdrs
, **sending_order
;
1827 ADDRESS
*lcc_addr
= NULL
;
1828 ADDRESS
*nobody_addr
= NULL
;
1829 BODY_PARTICULARS_S
*bp
;
1830 STORE_S
*orig_so
= NULL
;
1831 PICO pbuf1
, *save_previous_pbuf
;
1833 REDRAFT_POS_S
*local_redraft_pos
= NULL
;
1835 dprint((1,"\n=== send called ===\n"));
1837 save_previous_pbuf
= pbf
;
1839 standard_picobuf_setup(pbf
);
1842 * Cancel any pending initial commands since pico uses a different
1843 * input routine. If we didn't cancel them, they would happen after
1844 * we returned from the editor, which would be confusing.
1846 if(ps_global
->in_init_seq
){
1847 ps_global
->in_init_seq
= 0;
1848 ps_global
->save_in_init_seq
= 0;
1850 if(ps_global
->initial_cmds
){
1851 if(ps_global
->free_initial_cmds
)
1852 fs_give((void **)&(ps_global
->free_initial_cmds
));
1854 ps_global
->initial_cmds
= 0;
1857 F_SET(F_USE_FK
,ps_global
,ps_global
->orig_use_fkeys
);
1860 #if defined(DOS) || defined(OS2)
1861 if(!dos_valid_from()){
1862 pbf
= save_previous_pbuf
;
1868 pbf
->upload
= (ps_global
->VAR_UPLOAD_CMD
1869 && ps_global
->VAR_UPLOAD_CMD
[0])
1870 ? upload_msg_to_pico
: NULL
;
1873 pbf
->msgntext
= message_format_for_pico
;
1874 pbf
->mimetype
= mime_type_for_pico
;
1875 pbf
->exittest
= send_exit_for_pico
;
1876 pbf
->user_says_noflow
= dont_flow_this_time
;
1877 pbf
->newthread
= new_thread_on_blank_subject
;
1878 ps_global
->newthread
= 0; /* reset this value */
1879 if(F_OFF(F_CANCEL_CONFIRM
, ps_global
))
1880 pbf
->canceltest
= cancel_for_pico
;
1882 pbf
->dict
= (ps_global
->VAR_DICTIONARY
1883 && ps_global
->VAR_DICTIONARY
[0]
1884 && ps_global
->VAR_DICTIONARY
[0][0])
1885 ? ps_global
->VAR_DICTIONARY
: NULL
;
1886 pbf
->chosen_dict
= -1; /* not chosen yet */
1887 #endif /* _WINDOWS */
1888 pbf
->alt_ed
= (ps_global
->VAR_EDITOR
&& ps_global
->VAR_EDITOR
[0] &&
1889 ps_global
->VAR_EDITOR
[0][0])
1890 ? ps_global
->VAR_EDITOR
: NULL
;
1891 pbf
->alt_spell
= (ps_global
->VAR_SPELLER
&& ps_global
->VAR_SPELLER
[0])
1892 ? ps_global
->VAR_SPELLER
: NULL
;
1893 pbf
->always_spell_check
= F_ON(F_ALWAYS_SPELL_CHECK
, ps_global
);
1894 pbf
->quote_str
= reply
&& reply
->prefix
? reply
->prefix
: "> ";
1895 /* We actually want to set this only if message we're sending is flowed */
1896 pbf
->strip_ws_before_send
= F_ON(F_STRIP_WS_BEFORE_SEND
, ps_global
);
1897 pbf
->allow_flowed_text
= (F_OFF(F_QUELL_FLOWED_TEXT
, ps_global
)
1898 && F_OFF(F_STRIP_WS_BEFORE_SEND
, ps_global
)
1899 && (strcmp(pbf
->quote_str
, "> ") == 0
1900 || strcmp(pbf
->quote_str
, ">") == 0));
1901 pbf
->edit_offset
= 0;
1902 title
= cpystr(set_titlebar(editor_title
,
1903 ps_global
->mail_stream
,
1904 ps_global
->context_current
,
1905 ps_global
->cur_folder
,ps_global
->msgmap
,
1906 0, FolderName
, 0, 0, NULL
));
1907 pbf
->pine_anchor
= title
;
1909 #if defined(DOS) || defined(OS2)
1910 if(!pbf
->oper_dir
&& ps_global
->VAR_FILE_DIR
){
1911 pbf
->oper_dir
= ps_global
->VAR_FILE_DIR
;
1915 if(redraft_pos
&& editor_title
&& !strcmp(editor_title
, COMPOSE_MAIL_TITLE
))
1916 pbf
->pine_flags
|= P_CHKPTNOW
;
1918 /* NOTE: initial cursor position set below */
1920 dprint((9, "flags: %x\n", pbf
->pine_flags
));
1923 * When user runs compose and the current folder is a newsgroup,
1924 * offer to post to the current newsgroup.
1926 if(!(outgoing
->to
|| (outgoing
->newsgroups
&& *outgoing
->newsgroups
))
1927 && IS_NEWS(ps_global
->mail_stream
)){
1928 char prompt
[200], news_group
[MAILTMPLEN
];
1930 pine_send_newsgroup_name(ps_global
->mail_stream
->mailbox
, news_group
,
1931 sizeof(news_group
));
1934 * Replies don't get this far because To or Newsgroups will already
1935 * be filled in. So must be either ordinary compose or forward.
1936 * Forward sets subject, so use that to tell the difference.
1938 if(news_group
[0] && !outgoing
->subject
){
1941 char *errmsg
= NULL
;
1942 BUILDER_ARG
*fcc_build
= NULL
;
1944 if(F_OFF(F_COMPOSE_TO_NEWSGRP
,ps_global
)){
1945 snprintf(prompt
, sizeof(prompt
),
1946 _("Post to current newsgroup (%s)"), news_group
);
1947 prompt
[sizeof(prompt
)-1] = '\0';
1948 ch
= want_to(prompt
, 'y', 'x', NO_HELP
, WT_NORM
);
1953 if(outgoing
->newsgroups
)
1954 fs_give((void **)&outgoing
->newsgroups
);
1956 if(!fcc_arg
&& !(role
&& role
->fcc
)){
1957 fcc_build
= (BUILDER_ARG
*)fs_get(sizeof(BUILDER_ARG
));
1958 memset((void *)fcc_build
, 0, sizeof(BUILDER_ARG
));
1959 fcc_build
->tptr
= fcc_to_free
;
1962 ret_val
= news_build(news_group
, &outgoing
->newsgroups
,
1963 &errmsg
, fcc_build
, NULL
);
1966 if(outgoing
->newsgroups
)
1967 fs_give((void **)&outgoing
->newsgroups
);
1969 outgoing
->newsgroups
= cpystr(news_group
);
1972 if(!fcc_arg
&& !(role
&& role
->fcc
)){
1973 fcc_arg
= fcc_to_free
= fcc_build
->tptr
;
1974 fs_give((void **)&fcc_build
);
1979 q_status_message(SM_ORDER
, 3, 3, errmsg
);
1980 display_message(NO_OP_COMMAND
);
1983 fs_give((void **)&errmsg
);
1989 q_status_message(SM_ORDER
, 0, 3, _("Message cancelled"));
1990 dprint((4, "=== send: cancelled\n"));
1991 pbf
= save_previous_pbuf
;
2002 if(F_ON(F_PREDICT_NNTP_SERVER
, ps_global
)
2003 && outgoing
->newsgroups
&& *outgoing
->newsgroups
2004 && IS_NEWS(ps_global
->mail_stream
)){
2007 if(mail_valid_net_parse(ps_global
->mail_stream
->original_mailbox
,
2009 if(!strucmp(news_mb
.service
, "nntp")){
2010 if(*ps_global
->mail_stream
->original_mailbox
== '{'){
2011 char *svcp
= NULL
, *psvcp
;
2013 suggested_nntp_server
=
2014 cpystr(ps_global
->mail_stream
->original_mailbox
+ 1);
2015 if((p
= strindex(suggested_nntp_server
, '}')) != NULL
)
2017 for(p
= strindex(suggested_nntp_server
, '/'); p
&& *p
;
2018 p
= strindex(p
, '/')){
2019 /* take out /nntp, which gets added in nntp_open */
2020 if(!struncmp(p
, "/nntp", 5))
2022 else if(!struncmp(p
, "/service=nntp", 13))
2024 else if(!struncmp(p
, "/service=\"nntp\"", 15))
2031 else if(*svcp
== '/' || *svcp
== ':'){
2032 for(psvcp
= p
; *svcp
; svcp
++, psvcp
++)
2041 suggested_nntp_server
= cpystr(news_mb
.orighost
);
2046 * If we don't already have custom headers set and the role has custom
2047 * headers, then incorporate those custom headers into "custom".
2050 PINEFIELD
*dflthdrs
= NULL
, *rolehdrs
= NULL
;
2052 dflthdrs
= parse_custom_hdrs(ps_global
->VAR_CUSTOM_HDRS
, UseAsDef
);
2054 * If we allow the Combine argument here, we're saying that we want to
2055 * combine the values from the envelope and the role for the fields To,
2056 * Cc, Bcc, and Newsgroups. For example, if we are replying to a message
2057 * we'll have a To in the envelope because we're replying. If our role also
2058 * has a To action, then Combine would combine those two and offer both
2059 * to the user. We've decided against doing this. Instead, we always use
2060 * Replace, and the role's header value replaces the value from the
2061 * envelope. It might also make sense in some cases to do the opposite,
2062 * which would be treating the role headers as defaults, just like
2065 #ifdef WANT_TO_COMBINE_ADDRESSES
2066 if(role
&& role
->cstm
)
2067 rolehdrs
= parse_custom_hdrs(role
->cstm
, Combine
);
2069 if(role
&& role
->cstm
)
2070 rolehdrs
= parse_custom_hdrs(role
->cstm
, Replace
);
2074 custom
= combine_custom_headers(dflthdrs
, rolehdrs
);
2076 free_prompts(dflthdrs
);
2077 free_customs(dflthdrs
);
2081 free_prompts(rolehdrs
);
2082 free_customs(rolehdrs
);
2089 g_rolenick
= role
? role
->nick
: NULL
;
2091 /* how many fixed fields are there? */
2092 for(fixed_cnt
= 0; pf_template
&& pf_template
[fixed_cnt
].name
; fixed_cnt
++)
2095 total_cnt
= fixed_cnt
+ count_custom_hdrs_pf(custom
,1);
2097 /* the fixed part of the PINEFIELDs */
2098 i
= fixed_cnt
* sizeof(PINEFIELD
);
2099 pfields
= (PINEFIELD
*)fs_get((size_t) i
);
2100 memset(pfields
, 0, (size_t) i
);
2102 /* temporary headerentry array for pico */
2103 i
= (total_cnt
+ 1) * sizeof(struct headerentry
);
2104 headents
= (struct headerentry
*)fs_get((size_t) i
);
2105 memset(headents
, 0, (size_t) i
);
2107 i
= total_cnt
* sizeof(PINEFIELD
*);
2108 sending_order
= (PINEFIELD
**)fs_get((size_t) i
);
2109 memset(sending_order
, 0, (size_t) i
);
2111 pbf
->headents
= headents
;
2112 header
.env
= outgoing
;
2113 header
.local
= pfields
;
2114 header
.sending_order
= sending_order
;
2116 /* custom part of PINEFIELDs */
2117 header
.custom
= custom
;
2123 * For Address types, pf->addr points to an ADDRESS *.
2124 * If that address is in the "outgoing" envelope, it will
2125 * be freed by the caller, otherwise, it should be freed here.
2126 * Pf->textbuf for an Address is used a little to set up a default,
2127 * but then is freed right away below. Pf->scratch is used for a
2128 * pointer to some alloced space for pico to edit in. Addresses in
2129 * the custom area are freed by free_customs().
2131 * For FreeText types, pf->addr is not used. Pf->text points to a
2132 * pointer that points to the text. Pf->textbuf points to a copy of
2133 * the text that must be freed before we leave, otherwise, it is
2134 * probably a pointer into the envelope and that gets freed by the
2137 * He->realaddr is the pointer to the text that pico actually edits.
2140 #if !(defined(DOS) || defined(OS2)) || defined(NOAUTH)
2146 if(outgoing
->newsgroups
&& *outgoing
->newsgroups
)
2149 /* initialize the fixed header elements of the two temp arrays */
2150 for(i
=0; i
< fixed_cnt
; i
++, pf
++){
2151 static int news_order
[] = {
2152 N_AUTHRCVD
,N_FROM
, N_REPLYTO
, N_NEWS
, N_TO
, N_CC
, N_BCC
,
2153 N_FCC
, N_LCC
, N_ATTCH
, N_SUBJ
, N_REF
, N_DATE
, N_INREPLY
,
2154 N_MSGID
, N_PRIORITY
, N_USERAGENT
, N_NOBODY
, N_POSTERR
, N_RPLUID
, N_RPLMBOX
,
2155 N_SMTP
, N_NNTP
, N_CURPOS
, N_OURREPLYTO
, N_OURHDRS
2156 #if !(defined(DOS) || defined(OS2)) || defined(NOAUTH)
2162 /* slightly different editing order if sending to news */
2163 if(use_news_order
&&
2164 index
>= 0 && index
< sizeof(news_order
)/sizeof(news_order
[0]))
2165 index
= news_order
[i
];
2167 /* copy the templates */
2168 *he
= he_template
[index
];
2170 pf
->name
= cpystr(pf_template
[index
].name
);
2171 if(index
== N_SENDER
&& F_ON(F_USE_SENDER_NOT_X
, ps_global
)){
2172 /* slide string over so it is Sender instead of X-X-Sender */
2173 for(p
= pf
->name
+4; *p
!= '\0'; p
++)
2177 pf
->type
= pf_template
[index
].type
;
2178 pf
->canedit
= pf_template
[index
].canedit
;
2179 pf
->rcptto
= pf_template
[index
].rcptto
;
2180 pf
->writehdr
= pf_template
[index
].writehdr
;
2181 pf
->localcopy
= pf_template
[index
].localcopy
;
2185 he
->rich_header
= view_as_rich(pf
->name
, he
->rich_header
);
2186 if(F_OFF(F_ENABLE_TAB_COMPLETE
,ps_global
))
2187 he
->nickcmpl
= NULL
;
2190 case FreeText
: /* realaddr points to c-client env */
2191 if(index
== N_NEWS
){
2192 sending_order
[1] = pf
;
2193 he
->realaddr
= &outgoing
->newsgroups
;
2196 switch(set_default_hdrval(pf
, custom
)){
2199 fs_give((void **)he
->realaddr
);
2201 *he
->realaddr
= pf
->textbuf
;
2207 if(*he
->realaddr
){ /* combine values */
2208 if(pf
->textbuf
&& *pf
->textbuf
){
2212 l
= strlen(*he
->realaddr
) + strlen(pf
->textbuf
) + 1;
2213 combined_hdr
= (char *) fs_get((l
+1) * sizeof(char));
2214 strncpy(combined_hdr
, *he
->realaddr
, l
);
2215 combined_hdr
[l
] = '\0';
2216 strncat(combined_hdr
, ",", l
+1-1-strlen(combined_hdr
));
2217 combined_hdr
[l
] = '\0';
2218 strncat(combined_hdr
, pf
->textbuf
, l
+1-1-strlen(combined_hdr
));
2219 combined_hdr
[l
] = '\0';
2221 fs_give((void **)he
->realaddr
);
2222 *he
->realaddr
= combined_hdr
;
2223 q_status_message(SM_ORDER
, 3, 3,
2224 "Adding newsgroup from role");
2229 *he
->realaddr
= pf
->textbuf
;
2236 /* if no value, use default */
2238 *he
->realaddr
= pf
->textbuf
;
2248 /* If there is a newsgroup, we'd better show it */
2249 if(outgoing
->newsgroups
&& *outgoing
->newsgroups
)
2250 he
->rich_header
= 0; /* force on by default */
2253 fs_give((void **)&pf
->textbuf
);
2255 pf
->text
= he
->realaddr
;
2257 else if(index
== N_DATE
){
2258 sending_order
[2] = pf
;
2259 pf
->text
= (char **) &outgoing
->date
;
2262 else if(index
== N_INREPLY
){
2263 sending_order
[NN
+9] = pf
;
2264 pf
->text
= &outgoing
->in_reply_to
;
2267 else if(index
== N_MSGID
){
2268 sending_order
[NN
+10] = pf
;
2269 pf
->text
= &outgoing
->message_id
;
2272 else if(index
== N_REF
){
2273 sending_order
[NN
+11] = pf
;
2274 pf
->text
= &outgoing
->references
;
2277 else if(index
== N_PRIORITY
){
2278 sending_order
[NN
+12] = pf
;
2279 pf
->text
= &pf
->textbuf
;
2282 else if(index
== N_USERAGENT
){
2283 sending_order
[NN
+13] = pf
;
2284 pf
->text
= &pf
->textbuf
;
2285 pf
->textbuf
= generate_user_agent();
2288 else if(index
== N_POSTERR
){
2289 sending_order
[NN
+14] = pf
;
2291 pf
->text
= &pf
->textbuf
;
2294 else if(index
== N_RPLUID
){
2295 sending_order
[NN
+15] = pf
;
2297 pf
->text
= &pf
->textbuf
;
2300 else if(index
== N_RPLMBOX
){
2301 sending_order
[NN
+16] = pf
;
2303 pf
->text
= &pf
->textbuf
;
2306 else if(index
== N_SMTP
){
2307 sending_order
[NN
+17] = pf
;
2308 pf_smtp_server
= pf
;
2309 pf
->text
= &pf
->textbuf
;
2312 else if(index
== N_NNTP
){
2313 sending_order
[NN
+18] = pf
;
2314 pf_nntp_server
= pf
;
2315 pf
->text
= &pf
->textbuf
;
2318 else if(index
== N_CURPOS
){
2319 sending_order
[NN
+19] = pf
;
2321 pf
->text
= &pf
->textbuf
;
2324 else if(index
== N_OURREPLYTO
){
2325 sending_order
[NN
+20] = pf
;
2327 pf
->text
= &pf
->textbuf
;
2330 else if(index
== N_OURHDRS
){
2331 sending_order
[NN
+21] = pf
;
2333 pf
->text
= &pf
->textbuf
;
2336 else if(index
== N_AUTHRCVD
){
2337 sending_order
[0] = pf
;
2339 pf
->text
= &pf
->textbuf
;
2343 q_status_message(SM_ORDER
| SM_DING
, 3, 7,
2344 "Botched: Unmatched FreeText header in pine_send");
2349 /* can't do a default for this one */
2351 /* If there is an attachment already, we'd better show them */
2352 if(body
&& *body
&& (*body
)->type
!= TYPETEXT
)
2353 he
->rich_header
= 0; /* force on by default */
2360 sending_order
[3] = pf
;
2361 pf
->addr
= &outgoing
->from
;
2362 if(role
&& role
->from
){
2363 if(ps_global
->never_allow_changing_from
)
2364 q_status_message(SM_ORDER
, 3, 3, _("Site policy doesn't allow changing From address so role's From has no effect"));
2366 outgoing
->from
= copyaddrlist(role
->from
);
2367 he
->display_it
= 1; /* show it */
2368 he
->rich_header
= 0;
2376 sending_order
[NN
+2] = pf
;
2377 pf
->addr
= &outgoing
->to
;
2378 /* If already set, make it act like we typed it in */
2380 && outgoing
->to
->mailbox
2381 && outgoing
->to
->mailbox
[0]
2382 && flags
& PS_STICKY_TO
)
2390 sending_order
[NN
+5] = pf
;
2392 if(ps_global
->VAR_EMPTY_HDR_MSG
2393 && !ps_global
->VAR_EMPTY_HDR_MSG
[0]){
2397 nobody_addr
= mail_newaddr();
2398 nobody_addr
->next
= mail_newaddr();
2399 nobody_addr
->mailbox
= cpystr(rfc1522_encode(tmp_20k_buf
,
2401 (unsigned char *)(ps_global
->VAR_EMPTY_HDR_MSG
2402 ? ps_global
->VAR_EMPTY_HDR_MSG
2403 : "undisclosed-recipients"),
2404 ps_global
->posting_charmap
));
2405 pf
->addr
= &nobody_addr
;
2411 sending_order
[NN
+3] = pf
;
2412 pf
->addr
= &outgoing
->cc
;
2416 sending_order
[NN
+4] = pf
;
2417 pf
->addr
= &outgoing
->bcc
;
2418 /* if bcc exists, make sure it's exposed so nothing's
2419 * sent by mistake...
2427 sending_order
[NN
+1] = pf
;
2428 pf
->addr
= &outgoing
->reply_to
;
2429 if(role
&& role
->replyto
){
2430 if(outgoing
->reply_to
)
2431 mail_free_address(&outgoing
->reply_to
);
2433 outgoing
->reply_to
= copyaddrlist(role
->replyto
);
2434 he
->display_it
= 1; /* show it */
2435 he
->rich_header
= 0;
2441 sending_order
[NN
+7] = pf
;
2442 pf
->addr
= &lcc_addr
;
2445 build_address(lcc_arg
, &addr
, NULL
, NULL
, NULL
);
2446 rfc822_parse_adrlist(&lcc_addr
, addr
,
2447 ps_global
->maildomain
);
2448 fs_give((void **)&addr
);
2454 #if !(defined(DOS) || defined(OS2)) || defined(NOAUTH)
2456 sending_order
[4] = pf
;
2457 pf
->addr
= &outgoing
->sender
;
2462 q_status_message1(SM_ORDER
,3,7,
2463 "Internal error: Address header %s", comatose(index
));
2468 * If this is a reply to news, don't show the regular email
2469 * recipient headers (unless they are non-empty).
2471 if((outgoing
->newsgroups
&& *outgoing
->newsgroups
)
2472 && (index
== N_TO
|| index
== N_CC
2473 || index
== N_BCC
|| index
== N_LCC
)
2474 && (pf
->addr
&& !*pf
->addr
)){
2475 if((ct
=set_default_hdrval(pf
, custom
)) >= UseAsDef
&&
2476 pf
->textbuf
&& *pf
->textbuf
){
2477 removing_trailing_white_space(pf
->textbuf
);
2478 (void)removing_double_quotes(pf
->textbuf
);
2479 build_address(pf
->textbuf
, &addr
, NULL
, NULL
, NULL
);
2480 rfc822_parse_adrlist(pf
->addr
, addr
,
2481 ps_global
->maildomain
);
2482 fs_give((void **)&addr
);
2487 he
->rich_header
= 1; /* hide */
2491 * If this address doesn't already have a value, then we check
2492 * for a default value assigned by the user.
2494 else if(pf
->addr
&& !*pf
->addr
){
2495 if((ct
=set_default_hdrval(pf
, custom
)) >= UseAsDef
&&
2497 (!ps_global
->never_allow_changing_from
&&
2498 F_ON(F_ALLOW_CHANGING_FROM
, ps_global
))) &&
2499 pf
->textbuf
&& *pf
->textbuf
){
2501 removing_trailing_white_space(pf
->textbuf
);
2502 (void)removing_double_quotes(pf
->textbuf
);
2505 * Try to set To based on Lcc. Don't attempt Fcc.
2507 if(index
== N_LCC
&& !he_to
->sticky
&& pf_to
&& pf_to
->addr
){
2508 BUILDER_ARG
*barg
= NULL
;
2512 ppp
= addr_list_string(*pf_to
->addr
, NULL
, 1);
2517 barg
= (BUILDER_ARG
*) fs_get(sizeof(*barg
));
2518 memset(barg
, 0, sizeof(*barg
));
2519 barg
->me
= &(he
->bldr_private
);
2520 barg
->aff
= &(he_to
->bldr_private
);
2521 barg
->tptr
= cpystr(ppp
);
2523 build_addr_lcc(pf
->textbuf
, &addr
, NULL
, barg
, NULL
);
2526 rfc822_parse_adrlist(pf
->addr
, addr
,
2527 ps_global
->maildomain
);
2529 fs_give((void **) &addr
);
2534 if(barg
&& barg
->tptr
&& strcmp(ppp
, barg
->tptr
)){
2537 rfc822_parse_adrlist(&a
, barg
->tptr
,
2538 ps_global
->maildomain
);
2541 mail_free_address(pf_to
->addr
);
2549 fs_give((void **) &barg
->tptr
);
2551 fs_give((void **) &barg
);
2555 fs_give((void **) &ppp
);
2558 build_address(pf
->textbuf
, &addr
, NULL
, NULL
, NULL
);
2559 rfc822_parse_adrlist(pf
->addr
, addr
,
2560 ps_global
->maildomain
);
2562 fs_give((void **) &addr
);
2569 /* if we still don't have a from */
2570 if(index
== N_FROM
&& !*pf
->addr
)
2571 *pf
->addr
= generate_from();
2575 * Addr is already set in the rest of the cases.
2577 else if((index
== N_FROM
|| index
== N_REPLYTO
) && pf
->addr
){
2578 ADDRESS
*adr
= NULL
;
2581 * We get to this case of the ifelse if the from or reply-to
2582 * addr was set by a role above.
2585 /* figure out the default value */
2586 (void)set_default_hdrval(pf
, custom
);
2587 if(pf
->textbuf
&& *pf
->textbuf
){
2588 removing_trailing_white_space(pf
->textbuf
);
2589 (void)removing_double_quotes(pf
->textbuf
);
2590 build_address(pf
->textbuf
, &addr
, NULL
, NULL
, NULL
);
2591 rfc822_parse_adrlist(&adr
, addr
,
2592 ps_global
->maildomain
);
2593 fs_give((void **)&addr
);
2596 /* if value set by role is different from default, show it */
2597 if(adr
&& !address_is_same(*pf
->addr
, adr
))
2598 he
->display_it
= 1; /* start this off showing */
2601 if(!(*pf
->addr
)->mailbox
){
2602 fs_give((void **)pf
->addr
);
2607 mail_free_address(&adr
);
2609 else if((index
== N_TO
|| index
== N_CC
|| index
== N_BCC
)
2611 ADDRESS
*a
= NULL
, **tail
;
2614 * These three are different from the others because we
2615 * might add the addresses to what is already there instead
2619 switch(set_default_hdrval(pf
, custom
)){
2622 mail_free_address(pf
->addr
);
2624 removing_trailing_white_space(pf
->textbuf
);
2625 (void)removing_double_quotes(pf
->textbuf
);
2626 build_address(pf
->textbuf
, &addr
, NULL
, NULL
, NULL
);
2627 rfc822_parse_adrlist(pf
->addr
, addr
, ps_global
->maildomain
);
2628 fs_give((void **)&addr
);
2633 removing_trailing_white_space(pf
->textbuf
);
2634 (void)removing_double_quotes(pf
->textbuf
);
2635 build_address(pf
->textbuf
, &addr
, NULL
, NULL
, NULL
);
2636 rfc822_parse_adrlist(&a
, addr
, ps_global
->maildomain
);
2637 fs_give((void **)&addr
);
2640 for(tail
= pf
->addr
; *tail
; tail
= &(*tail
)->next
)
2642 *tail
= reply_cp_addr(ps_global
, 0, NULL
, NULL
,
2643 *pf
->addr
, NULL
, a
, RCA_ALL
);
2644 q_status_message(SM_ORDER
, 3, 3,
2645 "Adding addresses from role");
2646 mail_free_address(&a
);
2656 he
->display_it
= 1; /* start this off showing */
2659 switch(set_default_hdrval(pf
, custom
)){
2663 mail_free_address(pf
->addr
);
2665 removing_trailing_white_space(pf
->textbuf
);
2666 (void)removing_double_quotes(pf
->textbuf
);
2667 build_address(pf
->textbuf
, &addr
, NULL
, NULL
, NULL
);
2668 rfc822_parse_adrlist(pf
->addr
, addr
, ps_global
->maildomain
);
2669 fs_give((void **)&addr
);
2681 if(pf
->addr
&& *pf
->addr
&& !(*pf
->addr
)->mailbox
){
2682 mail_free_address(pf
->addr
);
2683 he
->display_it
= 1; /* start this off showing */
2686 if(pf
->textbuf
) /* free default value in any case */
2687 fs_give((void **)&pf
->textbuf
);
2689 /* outgoing2strings will alloc the string pf->scratch below */
2690 he
->realaddr
= &pf
->scratch
;
2694 sending_order
[NN
+8] = pf
;
2696 if(role
&& role
->fcc
)
2699 fcc
= get_fcc(fcc_arg
);
2702 fs_give((void **)&fcc_to_free
);
2706 if(((flags
& PS_STICKY_FCC
) && fcc
[0]) || (role
&& role
->fcc
))
2712 if(strcmp(fcc
, ps_global
->VAR_DEFAULT_FCC
) != 0)
2713 he
->display_it
= 1; /* start this off showing */
2715 he
->realaddr
= &fcc
;
2721 sending_order
[NN
+6] = pf
;
2723 switch(set_default_hdrval(pf
, custom
)){
2726 pf
->scratch
= pf
->textbuf
;
2729 if(outgoing
->subject
)
2730 fs_give((void **)&outgoing
->subject
);
2736 /* if no value, use default */
2737 if(outgoing
->subject
){
2738 pf
->scratch
= cpystr(outgoing
->subject
);
2741 pf
->scratch
= pf
->textbuf
;
2748 he
->realaddr
= &pf
->scratch
;
2749 pf
->text
= &outgoing
->subject
;
2753 q_status_message1(SM_ORDER
,3,7,
2754 "Unknown header type %d in pine_send",
2760 * We may or may not want to give the user the chance to edit
2761 * the From and Reply-To lines. If they are listed in either
2762 * Default-composer-hdrs or Customized-hdrs, then they can edit
2764 * If canedit is not set, that means that this header is not in
2765 * the user's customized-hdrs. If rich_header is set, that
2766 * means that this header is not in the user's
2767 * default-composer-hdrs (since From and Reply-To are rich
2768 * by default). So, don't give it an he to edit with in that case.
2770 * For other types, just not setting canedit will cause it to be
2771 * uneditable, regardless of what the user does.
2775 /* to allow it, we let this fall through to the reply-to case below */
2776 if(ps_global
->never_allow_changing_from
||
2777 (F_OFF(F_ALLOW_CHANGING_FROM
, ps_global
) &&
2778 !(role
&& role
->from
))){
2779 if(pf
->canedit
|| !he
->rich_header
)
2780 q_status_message(SM_ORDER
, 3, 3,
2781 _("Not allowed to change header \"From\""));
2783 memset(he
, 0, (size_t)sizeof(*he
));
2789 if(!pf
->canedit
&& he
->rich_header
){
2790 memset(he
, 0, (size_t)sizeof(*he
));
2802 memset(he
, 0, (size_t)sizeof(*he
));
2813 * This is so the builder can tell the composer to fill the affected
2814 * field based on the value in the field on the left.
2816 * Note that this mechanism isn't completely general. Each entry has
2817 * only a single next_affected, so if some other entry points an
2818 * affected entry at an entry with a next_affected, they all inherit
2819 * that next_affected. Since this isn't used much a careful ordering
2820 * of the affected fields should make it a sufficient mechanism.
2822 he_to
->affected_entry
= he_fcc
;
2823 he_news
->affected_entry
= he_fcc
;
2824 he_lcc
->affected_entry
= he_to
;
2825 he_to
->next_affected
= he_fcc
;
2827 (--pf
)->next
= (total_cnt
!= fixed_cnt
) ? header
.custom
: NULL
;
2829 i
--; /* subtract one because N_ATTCH doesn't get a sending_order slot */
2831 * Set up headerentries for custom fields.
2832 * NOTE: "i" is assumed to now index first custom field in sending
2835 for(pf
= pf
->next
; pf
&& pf
->name
; pf
= pf
->next
){
2849 if(pf
->addr
){ /* better be set */
2850 sending_order
[i
++] = pf
;
2851 *he
= he_custom_addr_templ
;
2852 /* change default text into an ADDRESS */
2853 /* strip quotes around whole default */
2854 removing_trailing_white_space(pf
->textbuf
);
2855 (void)removing_double_quotes(pf
->textbuf
);
2856 build_address(pf
->textbuf
, &addr
, NULL
, NULL
, NULL
);
2857 rfc822_parse_adrlist(pf
->addr
, addr
, ps_global
->maildomain
);
2858 fs_give((void **)&addr
);
2860 fs_give((void **)&pf
->textbuf
);
2862 he
->realaddr
= &pf
->scratch
;
2863 if(F_OFF(F_ENABLE_TAB_COMPLETE
,ps_global
))
2864 he
->nickcmpl
= NULL
;
2870 sending_order
[i
++] = pf
;
2871 *he
= he_custom_free_templ
;
2872 he
->realaddr
= &pf
->textbuf
;
2873 pf
->text
= &pf
->textbuf
;
2874 if(((!pf
->val
|| !pf
->val
[0]) && pf
->textbuf
&& pf
->textbuf
[0]) ||
2875 (pf
->val
&& (!pf
->textbuf
|| strcmp(pf
->textbuf
, pf
->val
))))
2876 he
->display_it
= 1; /* show it */
2881 q_status_message1(SM_ORDER
,0,7,"Unknown custom header type %d",
2886 he
->name
= pf
->name
;
2888 /* use first 8 characters for prompt */
2889 he
->prompt
= cpystr(" : ");
2890 strncpy(he
->prompt
, he
->name
, MIN(strlen(he
->name
), he
->prwid
- 2));
2892 he
->rich_header
= view_as_rich(he
->name
, he
->rich_header
);
2897 * Make sure at least *one* field is displayable...
2899 for(index
= -1, i
=0, pf
=header
.local
; pf
&& pf
->name
; pf
=pf
->next
, i
++)
2900 if(HE(pf
) && !HE(pf
)->rich_header
){
2906 * None displayable!!! Warn and display defaults.
2909 q_status_message(SM_ORDER
,0,5,
2910 "No default-composer-hdrs matched, displaying defaults");
2911 for(i
= 0, pf
= header
.local
; pf
; pf
= pf
->next
, i
++)
2912 if((i
== N_TO
|| i
== N_CC
|| i
== N_SUBJ
|| i
== N_ATTCH
)
2914 HE(pf
)->rich_header
= 0;
2918 * Save information about body which set_mime_type_by_grope might change.
2919 * Then, if we get an error sending, we reset these things so that
2920 * grope can do it's thing again after we edit some more.
2922 if ((*body
)->type
== TYPEMULTIPART
)
2923 bp
= save_body_particulars(&(*body
)->nested
.part
->body
);
2925 bp
= save_body_particulars(*body
);
2928 local_redraft_pos
= redraft_pos
;
2930 /*----------------------------------------------------------------------
2931 Loop calling the editor until everything goes well
2934 int saved_user_timeout
;
2936 /* Reset body to what it was when we started. */
2937 if ((*body
)->type
== TYPEMULTIPART
)
2938 reset_body_particulars(bp
, &(*body
)->nested
.part
->body
);
2940 reset_body_particulars(bp
,*body
);
2942 * set initial cursor position based on how many times we've been
2945 if(reply
&& reply
->pseudo
){
2946 pbf
->pine_flags
|= reply
->data
.pico_flags
;
2948 else if(body_start
){
2949 pbf
->pine_flags
|= P_BODY
;
2950 body_start
= 0; /* maybe not next time */
2952 else if(local_redraft_pos
){
2953 pbf
->edit_offset
= local_redraft_pos
->offset
;
2954 /* set the start_here bit in correct header */
2955 for(pf
= header
.local
; pf
&& pf
->name
; pf
= pf
->next
)
2956 if(strcmp(pf
->name
, local_redraft_pos
->hdrname
) == 0
2958 HE(pf
)->start_here
= 1;
2962 /* If didn't find it, we start in body. */
2963 if(!pf
|| !pf
->name
)
2964 pbf
->pine_flags
|= P_BODY
;
2966 else if(reply
&& (!reply
->forw
&& !reply
->forwarded
)){
2967 pbf
->pine_flags
|= P_BODY
;
2970 /* in case these were turned on in previous pass through loop */
2972 pf_nobody
->writehdr
= 0;
2973 pf_nobody
->localcopy
= 0;
2977 pf_fcc
->localcopy
= 0;
2980 * If a sending attempt failed after we passed the message text
2981 * thru a user-defined filter, "orig_so" points to the original
2982 * text. Replace the body's encoded data with the original...
2985 STORE_S
**so
= (STORE_S
**)(((*body
)->type
== TYPEMULTIPART
)
2986 ? &(*body
)->nested
.part
->body
.contents
.text
.data
2987 : &(*body
)->contents
.text
.data
);
2994 * Convert the envelope and body to the string format that
2997 outgoing2strings(&header
, *body
, &pbf
->msgtext
, &pbf
->attachments
, 0);
2999 for(pf
= header
.local
; pf
&& pf
->name
; pf
= pf
->next
){
3001 * If this isn't the first time through this loop, we may have
3002 * freed some of the FreeText headers below so that they wouldn't
3003 * show up as empty headers in the finished message. Need to
3004 * alloc them again here so they can be edited.
3006 if(pf
->type
== FreeText
&& HE(pf
) && !*HE(pf
)->realaddr
)
3007 *HE(pf
)->realaddr
= cpystr("");
3009 if(pf
->type
!= Attachment
&& HE(pf
) && *HE(pf
)->realaddr
)
3010 HE(pf
)->maxlen
= strlen(*HE(pf
)->realaddr
);
3014 * If From is exposed, probably by a role, then start the cursor
3015 * on the first line which isn't filled in. If it isn't, then we
3016 * don't move the cursor, mostly for back-compat.
3018 if((!reply
|| reply
->forw
|| reply
->forwarded
) &&
3019 !local_redraft_pos
&& !(pbf
->pine_flags
& P_BODY
) && he_from
&&
3020 (he_from
->display_it
|| !he_from
->rich_header
)){
3021 for(pf
= header
.local
; pf
&& pf
->name
; pf
= pf
->next
)
3023 (HE(pf
)->display_it
|| !HE(pf
)->rich_header
) &&
3025 (!*HE(pf
)->realaddr
|| !**HE(pf
)->realaddr
)){
3026 HE(pf
)->start_here
= 1;
3032 mswin_setwindowmenu (MENU_COMPOSER
);
3035 cancel_busy_cue(-1);
3036 flush_status_messages(1);
3038 /* turn off user input timeout when in composer */
3039 saved_user_timeout
= ps_global
->hours_to_timeout
;
3040 ps_global
->hours_to_timeout
= 0;
3041 dprint((1, "\n ---- COMPOSER ----\n"));
3042 editor_result
= pico(pbf
);
3043 dprint((4, "... composer returns (0x%x)\n", editor_result
));
3044 ps_global
->hours_to_timeout
= saved_user_timeout
;
3047 mswin_setwindowmenu (MENU_DEFAULT
);
3049 fix_windsize(ps_global
);
3052 * Only reinitialize signals if we didn't receive an interesting
3053 * one while in pico, since pico's return is part of processing that
3054 * signal and it should continue to be ignored.
3056 if(!(editor_result
& COMP_GOTHUP
))
3057 init_signals(); /* Pico has it's own signal stuff */
3060 * We're going to save in DEADLETTER. Dump attachments first.
3062 if(editor_result
& COMP_CANCEL
)
3063 free_attachment_list(&pbf
->attachments
);
3065 /* Turn strings back into structures */
3066 strings2outgoing(&header
, body
, pbf
->attachments
, flowing_requested
);
3068 /* Make newsgroups NULL if it is "" (so won't show up in headers) */
3069 if(outgoing
->newsgroups
){
3070 sqzspaces(outgoing
->newsgroups
);
3071 if(!outgoing
->newsgroups
[0])
3072 fs_give((void **)&(outgoing
->newsgroups
));
3075 /* Make subject NULL if it is "" (so won't show up in headers) */
3076 if(outgoing
->subject
&& !outgoing
->subject
[0])
3077 fs_give((void **)&(outgoing
->subject
));
3079 /* remove custom fields that are empty */
3080 for(pf
= header
.local
; pf
&& pf
->name
; pf
= pf
->next
){
3081 if(pf
->type
== FreeText
&& pf
->textbuf
){
3082 if(pf
->textbuf
[0] == '\0'){
3083 fs_give((void **)&pf
->textbuf
);
3089 removing_trailing_white_space(fcc
);
3091 /*-------- Stamp it with a current date -------*/
3092 if(outgoing
->date
) /* update old date */
3093 fs_give((void **)&(outgoing
->date
));
3095 if(F_ON(F_QUELL_TIMEZONE
, ps_global
))
3096 mail_parameters(NULL
, SET_DISABLE822TZTEXT
, (void *) TRUE
);
3098 rfc822_date(tmp_20k_buf
); /* format and copy new date */
3099 if(F_ON(F_QUELL_TIMEZONE
, ps_global
))
3100 mail_parameters(NULL
, SET_DISABLE822TZTEXT
, (void *) FALSE
);
3102 outgoing
->date
= (unsigned char *) cpystr(tmp_20k_buf
);
3104 /* Set return_path based on From which is going to be used */
3105 if(outgoing
->return_path
)
3106 mail_free_address(&outgoing
->return_path
);
3108 outgoing
->return_path
= rfc822_cpy_adr(outgoing
->from
);
3111 * Don't ever believe the sender that is there.
3112 * If From doesn't look quite right, generate our own sender.
3114 if(outgoing
->sender
)
3115 mail_free_address(&outgoing
->sender
);
3118 * If the LHS of the address doesn't match, or the RHS
3119 * doesn't match one of localdomain or hostname,
3120 * then add a sender line (really X-X-Sender).
3122 * Don't add a personal_name since the user can change that.
3124 if(F_OFF(F_DISABLE_SENDER
, ps_global
)
3127 || !outgoing
->from
->mailbox
3128 || strucmp(outgoing
->from
->mailbox
, ps_global
->VAR_USER_ID
) != 0
3129 || !outgoing
->from
->host
3130 || !(strucmp(outgoing
->from
->host
, ps_global
->localdomain
) == 0
3131 || strucmp(outgoing
->from
->host
, ps_global
->hostname
) == 0))){
3133 outgoing
->sender
= mail_newaddr();
3134 outgoing
->sender
->mailbox
= cpystr(ps_global
->VAR_USER_ID
);
3135 outgoing
->sender
->host
= cpystr(ps_global
->hostname
);
3138 if(ps_global
->newthread
){
3139 if(outgoing
->in_reply_to
) fs_give((void **)&outgoing
->in_reply_to
);
3140 if(outgoing
->references
) fs_give((void **)&outgoing
->references
);
3143 /*----- Message is edited, now decide what to do with it ----*/
3144 if(editor_result
& (COMP_SUSPEND
| COMP_GOTHUP
| COMP_CANCEL
)){
3145 /*=========== Postpone or Interrupted message ============*/
3146 CONTEXT_S
*fcc_cntxt
= NULL
;
3147 char folder
[MAXPATH
+1];
3151 dprint((4, "pine_send:%s handling\n",
3152 (editor_result
& COMP_SUSPEND
)
3154 : (editor_result
& COMP_GOTHUP
)
3156 : (editor_result
& COMP_CANCEL
)
3157 ? "CANCEL" : "HUH?"));
3158 if((editor_result
& COMP_CANCEL
)
3159 && (F_ON(F_QUELL_DEAD_LETTER
, ps_global
)
3160 || ps_global
->deadlets
== 0)){
3161 q_status_message(SM_ORDER
, 0, 3, "Message cancelled");
3166 * The idea here is to use the Fcc: writing facility
3167 * to append to the special postponed message folder...
3169 * NOTE: the strategy now is to write the message and
3170 * all attachments as they exist at composition time.
3171 * In other words, attachments are postponed by value
3172 * and not reference. This may change later, but we'll
3173 * need a local "message/external-body" type that
3174 * outgoing2strings knows how to properly set up for
3175 * the composer. Maybe later...
3180 if(F_ON(F_COMPOSE_REJECTS_UNQUAL
, ps_global
)
3181 && (editor_result
& COMP_SUSPEND
)
3182 && (check_addresses(&header
) == CA_BAD
)){
3183 /*--- Addresses didn't check out---*/
3184 q_status_message(SM_ORDER
, 7, 7,
3185 _("Not allowed to postpone message until addresses are qualified"));
3190 * Build the local message copy so.
3192 * In the HUP case, we'll write the bezerk delimiter by
3193 * hand and output the message directly into the folder.
3194 * It's not only faster, we don't have to worry about
3195 * c-client reentrance and less hands paw over the data so
3196 * there's less chance of a problem.
3198 * In the Postpone case, just create it if the user wants to
3199 * and create a temporary storage object to write into. */
3201 lmc
.all_written
= lmc
.text_only
= lmc
.text_written
= 0;
3202 if(editor_result
& (COMP_GOTHUP
| COMP_CANCEL
)){
3204 time_t now
= time((time_t *)0);
3206 #if defined(DOS) || defined(OS2)
3208 * we can't assume anything about root or home dirs, so
3209 * just plunk it down in the same place as the pinerc
3211 if(!getenv("HOME")){
3212 char *lc
= last_cmpnt(ps_global
->pinerc
);
3215 strncpy(folder
,ps_global
->pinerc
,
3216 MIN(lc
-ps_global
->pinerc
,sizeof(folder
)-1));
3217 folder
[MIN(lc
-ps_global
->pinerc
,sizeof(folder
)-1)]='\0';
3220 strncat(folder
, (editor_result
& COMP_GOTHUP
)
3221 ? INTERRUPTED_MAIL
: DEADLETTER
,
3222 sizeof(folder
)-strlen(folder
)-1);
3227 ps_global
->VAR_OPER_DIR
3228 ? ps_global
->VAR_OPER_DIR
: ps_global
->home_dir
,
3229 (editor_result
& COMP_GOTHUP
)
3230 ? INTERRUPTED_MAIL
: DEADLETTER
,
3233 if(editor_result
& COMP_CANCEL
){
3234 char filename
[MAXPATH
+1], newfname
[MAXPATH
+1], nbuf
[5];
3236 if(strlen(folder
) + 1 < sizeof(filename
))
3237 for(i
= ps_global
->deadlets
- 1; i
> 0 && i
< 9; i
--){
3238 strncpy(filename
, folder
, sizeof(filename
));
3239 filename
[sizeof(filename
)-1] = '\0';
3240 strncpy(newfname
, filename
, sizeof(newfname
));
3241 newfname
[sizeof(newfname
)-1] = '\0';
3244 snprintf(nbuf
, sizeof(nbuf
), "%d", i
);
3245 nbuf
[sizeof(nbuf
)-1] = '\0';
3246 strncat(filename
, nbuf
,
3247 sizeof(filename
)-strlen(filename
)-1);
3248 filename
[sizeof(filename
)-1] = '\0';
3251 snprintf(nbuf
, sizeof(nbuf
), "%d", i
+1);
3252 nbuf
[sizeof(nbuf
)-1] = '\0';
3253 strncat(newfname
, nbuf
,
3254 sizeof(newfname
)-strlen(newfname
)-1);
3255 newfname
[sizeof(newfname
)-1] = '\0';
3256 (void) rename_file(filename
, newfname
);
3262 newfile
= can_access(folder
, ACCESS_EXISTS
);
3264 if((lmc
.so
= so_get(FCC_SOURCE
, NULL
, WRITE_ACCESS
)) != NULL
){
3265 if (outgoing
->from
){
3266 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, "%sFrom %s@%s %.24s\015\012",
3267 newfile
? "" : "\015\012",
3268 outgoing
->from
->mailbox
,
3269 outgoing
->from
->host
, ctime(&now
));
3270 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
3271 if(!so_puts(lmc
.so
, tmp_20k_buf
)){
3272 if(editor_result
& COMP_CANCEL
)
3273 q_status_message2(SM_ORDER
| SM_DING
, 3, 3,
3274 "Can't write \"%s\": %s",
3275 folder
, error_description(errno
));
3277 dprint((1, "* * * CAN'T WRITE %s: %s\n",
3278 folder
? folder
: "?",
3279 error_description(errno
)));
3284 else{ /* Must be COMP_SUSPEND */
3285 if(!ps_global
->VAR_POSTPONED_FOLDER
3286 || !ps_global
->VAR_POSTPONED_FOLDER
[0]){
3287 q_status_message(SM_ORDER
| SM_DING
, 3, 3,
3288 _("No postponed file defined"));
3293 * Store the cursor position
3295 * First find the header entry with the start_here
3296 * bit set, if any. This means the editor is telling
3297 * us to start on this header field next time.
3299 start_here_name
= NULL
;
3300 for(pf
= header
.local
; pf
&& pf
->name
; pf
= pf
->next
)
3301 if(HE(pf
) && HE(pf
)->start_here
){
3302 start_here_name
= pf
->name
;
3306 /* If there wasn't one, ":" means we start in the body. */
3307 if(!start_here_name
|| !*start_here_name
)
3308 start_here_name
= ":";
3310 if(ps_global
->VAR_FORM_FOLDER
3311 && ps_global
->VAR_FORM_FOLDER
[0]
3312 && postpone_prompt() == 'f'){
3313 strncpy(folder
, ps_global
->VAR_FORM_FOLDER
,
3315 folder
[sizeof(folder
)-1] = '\0';
3316 strncpy(label
, "form letter", sizeof(label
));
3317 label
[sizeof(label
)-1] = '\0';
3320 strncpy(folder
, ps_global
->VAR_POSTPONED_FOLDER
,
3322 folder
[sizeof(folder
)-1] = '\0';
3323 strncpy(label
, "postponed message", sizeof(label
));
3324 label
[sizeof(label
)-1] = '\0';
3327 lmc
.so
= open_fcc(folder
,&fcc_cntxt
, 1, NULL
, NULL
);
3334 /* copy fcc line to postponed or interrupted folder */
3336 pf_fcc
->localcopy
= 1;
3338 /* plug error into header for later display to user */
3339 if((editor_result
& ~0xff) && (lmq
= last_message_queued()) != NULL
){
3340 pf_err
->writehdr
= 1;
3341 pf_err
->localcopy
= 1;
3342 pf_err
->textbuf
= lmq
;
3346 * if reply, write (UID)folder header field so we can
3347 * later flag the replied-to message \\ANSWERED
3348 * DON'T save MSGNO's.
3350 if(reply
&& reply
->uid
){
3351 char uidbuf
[MAILTMPLEN
], *p
;
3354 for(i
= 0L, p
= tmp_20k_buf
; reply
->data
.uid
.msgs
[i
]; i
++){
3356 sstrncpy(&p
, ",", SIZEOF_20KBUF
-(p
-tmp_20k_buf
));
3358 sstrncpy(&p
,ulong2string(reply
->data
.uid
.msgs
[i
]),SIZEOF_20KBUF
-(p
-tmp_20k_buf
));
3361 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
3363 pf_uid
->writehdr
= 1;
3364 pf_uid
->localcopy
= 1;
3365 snprintf(uidbuf
, sizeof(uidbuf
), "(%s%s%s)(%ld %lu %s)%s",
3366 reply
->prefix
? int2string(strlen(reply
->prefix
))
3367 : (reply
->forwarded
) ? "": "0 ",
3368 reply
->prefix
? " " : "",
3369 reply
->prefix
? reply
->prefix
: "",
3370 i
, reply
->data
.uid
.validity
,
3371 tmp_20k_buf
, reply
->mailbox
);
3372 uidbuf
[sizeof(uidbuf
)-1] = '\0';
3373 pf_uid
->textbuf
= cpystr(uidbuf
);
3376 * Logically, this ought to be part of pf_uid, but this
3377 * was added later and so had to be in a separate header
3378 * for backwards compatibility.
3380 pf_mbox
->writehdr
= 1;
3381 pf_mbox
->localcopy
= 1;
3382 pf_mbox
->textbuf
= cpystr(reply
->origmbox
3387 /* Save cursor position */
3388 if(start_here_name
&& *start_here_name
){
3389 char curposbuf
[MAILTMPLEN
];
3391 pf_curpos
->writehdr
= 1;
3392 pf_curpos
->localcopy
= 1;
3393 snprintf(curposbuf
, sizeof(curposbuf
), "%s %ld", start_here_name
,
3395 curposbuf
[sizeof(curposbuf
)-1] = '\0';
3396 pf_curpos
->textbuf
= cpystr(curposbuf
);
3400 * Work around c-client reply-to bug. C-client will
3401 * return a reply_to in an envelope even if there is
3402 * no reply-to header field. We want to note here whether
3403 * the reply-to is real or not.
3405 if(outgoing
->reply_to
|| hdr_is_in_list("reply-to", custom
)){
3406 pf_ourrep
->writehdr
= 1;
3407 pf_ourrep
->localcopy
= 1;
3408 if(outgoing
->reply_to
)
3409 pf_ourrep
->textbuf
= cpystr("Full");
3411 pf_ourrep
->textbuf
= cpystr("Empty");
3414 /* Save the role-specific smtp server */
3415 if(role
&& role
->smtp
&& role
->smtp
[0]){
3416 char *q
, *smtp
= NULL
;
3421 * Turn the list of smtp servers into a space-
3422 * delimited list in a single string.
3424 for(lp
= role
->smtp
; (q
= *lp
) != NULL
; lp
++)
3425 len
+= (strlen(q
) + 1);
3428 smtp
= (char *) fs_get(len
* sizeof(char));
3430 for(lp
= role
->smtp
; (q
= *lp
) != NULL
; lp
++){
3431 if(lp
!= role
->smtp
)
3432 strncat(smtp
, " ", len
-strlen(smtp
)-1);
3434 strncat(smtp
, q
, len
-strlen(smtp
)-1);
3440 pf_smtp_server
->writehdr
= 1;
3441 pf_smtp_server
->localcopy
= 1;
3443 pf_smtp_server
->textbuf
= smtp
;
3445 pf_smtp_server
->textbuf
= cpystr("");
3448 /* Save the role-specific nntp server */
3449 if(suggested_nntp_server
||
3450 (role
&& role
->nntp
&& role
->nntp
[0])){
3451 char *q
, *nntp
= NULL
;
3455 if(role
&& role
->nntp
&& role
->nntp
[0]){
3457 * Turn the list of nntp servers into a space-
3458 * delimited list in a single string.
3460 for(lp
= role
->nntp
; (q
= *lp
) != NULL
; lp
++)
3461 len
+= (strlen(q
) + 1);
3464 nntp
= (char *) fs_get(len
* sizeof(char));
3466 for(lp
= role
->nntp
; (q
= *lp
) != NULL
; lp
++){
3467 if(lp
!= role
->nntp
)
3468 strncat(nntp
, " ", len
-strlen(nntp
)-1);
3470 strncat(nntp
, q
, len
-strlen(nntp
)-1);
3477 nntp
= cpystr(suggested_nntp_server
);
3479 pf_nntp_server
->writehdr
= 1;
3480 pf_nntp_server
->localcopy
= 1;
3482 pf_nntp_server
->textbuf
= nntp
;
3484 pf_nntp_server
->textbuf
= cpystr("");
3488 * Write the list of custom headers to the
3489 * X-Our-Headers header so that we can recover the
3493 for(pf
= header
.custom
; pf
&& pf
->name
; pf
= pf
->next
)
3494 sz
+= strlen(pf
->name
) + 1;
3499 pf_ourhdrs
->writehdr
= 1;
3500 pf_ourhdrs
->localcopy
= 1;
3501 pf_ourhdrs
->textbuf
= (char *)fs_get(sz
);
3502 memset(pf_ourhdrs
->textbuf
, 0, sz
);
3503 q
= pf_ourhdrs
->textbuf
;
3504 for(pf
= header
.custom
; pf
&& pf
->name
; pf
= pf
->next
){
3505 if(pf
!= header
.custom
)
3506 sstrncpy(&q
, ",", sz
-(q
-pf_ourhdrs
->textbuf
));
3508 sstrncpy(&q
, pf
->name
, sz
-(q
-pf_ourhdrs
->textbuf
));
3511 pf_ourhdrs
->textbuf
[sz
-1] = '\0';;
3515 * We need to make sure any header values that got cleared
3516 * get written to the postponed message (they won't if
3517 * pf->text is NULL). Otherwise, we can't tell previously
3518 * non-existent custom headers or default values from
3519 * custom (or other) headers that got blanked in the
3522 for(pf
= header
.local
; pf
&& pf
->name
; pf
= pf
->next
)
3523 if(pf
->type
== FreeText
&& HE(pf
) && !*(HE(pf
)->realaddr
))
3524 *(HE(pf
)->realaddr
) = cpystr("");
3527 * We're saving the message for use later. It may be that the
3528 * characters in the message are not all convertible to the
3529 * user's posting_charmap. We'll save it as UTF-8 instead
3530 * and worry about that the next time they try to send it.
3531 * Use a different save pointer just to be sure we don't
3532 * mess up the other stuff. We should probably make the
3533 * charset an argument.
3535 * We also need to fix the charset of the body part
3536 * the user is editing so that we can read it back
3537 * successfully when we resume the composition.
3539 ps_global
->post_utf8
= 1;
3544 if((*body
)->type
== TYPEMULTIPART
)
3545 bp
= &(*body
)->nested
.part
->body
;
3549 for(pm
= bp
->parameter
;
3550 pm
&& strucmp(pm
->attribute
, "charset") != 0;
3556 fs_give((void **) &pm
->value
);
3558 pm
->value
= cpystr("UTF-8");
3562 if(pine_rfc822_output(&header
,*body
,NULL
,NULL
) >= 0L){
3563 if(editor_result
& (COMP_GOTHUP
| COMP_CANCEL
)){
3569 if(editor_result
& COMP_CANCEL
){
3570 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
,
3571 "Saving to \"%s\"", folder
);
3572 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
3573 we_cancel
= busy_cue((char *)tmp_20k_buf
, NULL
, 1);
3577 so_get(FileStar
, folder
, WRITE_ACCESS
|OWNER_ONLY
)) != NULL
){
3578 gf_set_so_readc(&gc
, lmc
.so
);
3579 gf_set_so_writec(&pc
, hup_so
);
3580 so_seek(lmc
.so
, 0L, 0); /* read msg copy and */
3581 so_seek(hup_so
, 0L, 2); /* append to folder */
3583 gf_link_filter(gf_nvtnl_local
, NULL
);
3584 if(!(fcc_result
= !(err
= gf_pipe(gc
, pc
))))
3585 dprint((1, "*** PIPE FAILED: %s\n",
3588 gf_clear_so_readc(lmc
.so
);
3589 gf_clear_so_writec(hup_so
);
3593 dprint((1, "*** CAN'T CREATE %s: %s\n",
3594 folder
? folder
: "?",
3595 error_description(errno
)));
3598 cancel_busy_cue(-1);
3601 fcc_result
= write_fcc(folder
, fcc_cntxt
,
3602 lmc
.so
, NULL
, label
, NULL
);
3605 /* discontinue coerced UTF-8 posting */
3606 ps_global
->post_utf8
= 0;
3611 dprint((1, "***CAN'T ALLOCATE temp store: %s ",
3612 error_description(errno
)));
3614 if(editor_result
& COMP_GOTHUP
){
3616 * Special Hack #291: if any hi-byte bits are set in
3617 * editor's result, we put them there.
3619 if(editor_result
& 0xff00)
3620 exit(editor_result
>> 8);
3622 dprint((1, "Save composition on HUP %sED\n",
3623 fcc_result
? "SUCCEED" : "FAIL"));
3624 hup_signal(); /* Do what we normally do on SIGHUP */
3626 else if((editor_result
& COMP_SUSPEND
) && fcc_result
){
3627 if(ps_global
->VAR_FORM_FOLDER
3628 && ps_global
->VAR_FORM_FOLDER
[0]
3629 && !strcmp(folder
, ps_global
->VAR_FORM_FOLDER
))
3630 q_status_message(SM_ORDER
, 0, 3,
3631 _("Composition saved to Form Letter Folder. Select Compose to send."));
3633 q_status_message(SM_ORDER
, 0, 3,
3634 _("Composition postponed. Select Compose to resume."));
3636 break; /* postpone went OK, get out of here */
3638 else if(editor_result
& COMP_CANCEL
){
3641 if(fcc_result
&& folder
)
3642 lc
= last_cmpnt(folder
);
3644 q_status_message3(SM_ORDER
, 0, 3,
3645 _("Message cancelled%s%s%s"),
3646 (lc
&& *lc
) ? " and copied to \"" : "",
3647 (lc
&& *lc
) ? lc
: "",
3648 (lc
&& *lc
) ? "\" file" : "");
3652 q_status_message(SM_ORDER
, 0, 4,
3653 _("Continuing composition. Message not postponed or sent"));
3655 continue; /* postpone failed, jump back in to composer */
3659 /*------ Must be sending mail or posting ! -----*/
3660 int result
, valid_addr
, continue_with_only_fcc
= 0;
3661 CONTEXT_S
*fcc_cntxt
= NULL
;
3664 dprint((4, "=== sending: "));
3666 /* --- If posting, confirm with user ----*/
3667 if(outgoing
->newsgroups
&& *outgoing
->newsgroups
3668 && F_OFF(F_QUELL_EXTRA_POST_PROMPT
, ps_global
)
3669 && want_to(POST_PMT
, 'n', 'n', NO_HELP
, WT_NORM
) == 'n'){
3670 q_status_message(SM_ORDER
, 0, 3, _("Message not posted"));
3671 dprint((4, "no post, continuing\n"));
3675 if(!(outgoing
->to
|| outgoing
->cc
|| outgoing
->bcc
|| lcc_addr
3676 || outgoing
->newsgroups
)){
3678 if(F_OFF(F_AUTO_FCC_ONLY
, ps_global
) &&
3679 want_to(_("No recipients, really copy only to Fcc "),
3680 'n', 'n', h_send_fcc_only
, WT_NORM
) != 'y')
3683 continue_with_only_fcc
++;
3686 q_status_message(SM_ORDER
, 3, 4,
3687 _("No recipients specified!"));
3688 dprint((4, "no recip, continuing\n"));
3693 if((valid_addr
= check_addresses(&header
)) == CA_BAD
){
3694 /*--- Addresses didn't check out---*/
3695 dprint((4, "addrs failed, continuing\n"));
3699 if(F_ON(F_WARN_ABOUT_NO_TO_OR_CC
, ps_global
)
3700 && !continue_with_only_fcc
3701 && !(outgoing
->to
|| outgoing
->cc
|| lcc_addr
3702 || outgoing
->newsgroups
)
3703 && (want_to(_("No To, Cc, or Newsgroup specified, send anyway "),
3704 'n', 'n', h_send_check_to_cc
, WT_NORM
) != 'y')){
3705 dprint((4, "No To or CC or Newsgroup, continuing\n"));
3706 if(local_redraft_pos
&& local_redraft_pos
!= redraft_pos
)
3707 free_redraft_pos(&local_redraft_pos
);
3710 = (REDRAFT_POS_S
*) fs_get(sizeof(*local_redraft_pos
));
3711 memset((void *) local_redraft_pos
,0,sizeof(*local_redraft_pos
));
3712 local_redraft_pos
->hdrname
= cpystr(TONAME
);
3716 if(F_ON(F_WARN_ABOUT_NO_SUBJECT
, ps_global
)
3717 && check_for_subject(&header
) == CF_MISSING
){
3718 dprint((4, "No subject, continuing\n"));
3719 if(local_redraft_pos
&& local_redraft_pos
!= redraft_pos
)
3720 free_redraft_pos(&local_redraft_pos
);
3723 = (REDRAFT_POS_S
*) fs_get(sizeof(*local_redraft_pos
));
3724 memset((void *) local_redraft_pos
,0,sizeof(*local_redraft_pos
));
3725 local_redraft_pos
->hdrname
= cpystr(SUBJNAME
);
3729 if(F_ON(F_WARN_ABOUT_NO_FCC
, ps_global
)
3730 && check_for_fcc(fcc
) == CF_MISSING
){
3731 dprint((4, "No fcc, continuing\n"));
3732 if(local_redraft_pos
&& local_redraft_pos
!= redraft_pos
)
3733 free_redraft_pos(&local_redraft_pos
);
3736 = (REDRAFT_POS_S
*) fs_get(sizeof(*local_redraft_pos
));
3737 memset((void *) local_redraft_pos
,0,sizeof(*local_redraft_pos
));
3738 local_redraft_pos
->hdrname
= cpystr("Fcc");
3744 /*---- Check out fcc -----*/
3747 * If special name "inbox" then replace it with the
3750 if(ps_global
->VAR_INBOX_PATH
3751 && strucmp(fcc
, ps_global
->inbox_name
) == 0){
3754 replace_fcc
= cpystr(ps_global
->VAR_INBOX_PATH
);
3755 fs_give((void **)&fcc
);
3759 lmc
.all_written
= lmc
.text_written
= 0;
3760 /* lmc.text_only set on command line */
3761 if(!(lmc
.so
= open_fcc(fcc
, &fcc_cntxt
, 0, NULL
, NULL
))){
3762 /* ---- Open or allocation of fcc failed ----- */
3763 dprint((4,"can't open/allocate fcc, cont'g\n"));
3766 * Find field entry associated with fcc, and start
3769 for(pf
= header
.local
; pf
&& pf
->name
; pf
= pf
->next
)
3770 if(pf
->type
== Fcc
&& HE(pf
))
3771 HE(pf
)->start_here
= 1;
3776 so_truncate(lmc
.so
, fcc_size_guess(*body
) + 2048);
3781 /*---- Take care of any requested prefiltering ----*/
3782 if(sending_filter_requested
3783 && !filter_message_text(sending_filter_requested
, outgoing
,
3784 *body
, &orig_so
, &header
)){
3785 q_status_message1(SM_ORDER
, 3, 3,
3786 _("Problem filtering! Nothing sent%s."),
3787 fcc
? " or saved to fcc" : "");
3791 /*------ Actually post -------*/
3792 if(outgoing
->newsgroups
){
3793 char **alt_nntp
= NULL
, *alt_nntp_p
[2];
3794 if(((role
&& role
->nntp
)
3795 || suggested_nntp_server
)){
3796 if(ps_global
->FIX_NNTP_SERVER
3797 && ps_global
->FIX_NNTP_SERVER
[0])
3798 q_status_message(SM_ORDER
| SM_DING
, 5, 5,
3799 "Using nntp-server that is administratively fixed");
3800 else if(role
&& role
->nntp
)
3801 alt_nntp
= role
->nntp
;
3803 alt_nntp_p
[0] = suggested_nntp_server
;
3804 alt_nntp_p
[1] = NULL
;
3805 alt_nntp
= alt_nntp_p
;
3808 if(news_poster(&header
, *body
, alt_nntp
, pipe_callback
) < 0){
3809 dprint((1, "Post failed, continuing\n"));
3810 if(outgoing
->message_id
)
3811 fs_give((void **) &outgoing
->message_id
);
3813 outgoing
->message_id
= generate_message_id();
3818 result
|= P_NEWS_WIN
;
3822 * BUG: IF we've posted the message *and* an fcc was specified
3823 * then we've already got a neatly formatted message in the
3824 * lmc.so. It'd be nice not to have to re-encode everything
3825 * to insert it into the smtp slot...
3829 * Turn on "undisclosed recipients" header if no To or cc.
3831 if(!(outgoing
->to
|| outgoing
->cc
)
3832 && (outgoing
->bcc
|| lcc_addr
) && pf_nobody
&& pf_nobody
->addr
){
3833 pf_nobody
->writehdr
= 1;
3834 pf_nobody
->localcopy
= 1;
3837 if(priority_requested
){
3838 (void) set_priority_header(&header
, priority_requested
);
3839 fs_give((void **) &priority_requested
);
3842 #if defined(BACKGROUND_POST) && defined(SIGCHLD)
3844 * If requested, launch backgroud posting...
3846 if(background_requested
&& !(call_mailer_flags
& CM_VERBOSE
)){
3847 ps_global
->post
= (POST_S
*)fs_get(sizeof(POST_S
));
3848 memset(ps_global
->post
, 0, sizeof(POST_S
));
3850 ps_global
->post
->fcc
= cpystr(fcc
);
3852 if((ps_global
->post
->pid
= fork()) == 0){
3854 * Put us in new process group...
3856 setpgrp(0, ps_global
->post
->pid
);
3858 /* BUG: should fix argv[0] to indicate what we're up to */
3861 * If there are any live streams, pretend we never
3862 * knew them. Problem is two processes writing
3863 * same server process.
3864 * This is not clean but we're just going to exit
3865 * right away anyway. We just want to be sure to leave
3866 * the stuff that the parent is going to use alone.
3867 * The next three lines will disable the re-use of the
3868 * existing streams and cause us to open a new one if
3871 ps_global
->mail_stream
= NULL
;
3872 ps_global
->s_pool
.streams
= NULL
;
3873 ps_global
->s_pool
.nstream
= 0;
3875 /* quell any display output */
3876 ps_global
->in_init_seq
= 1;
3878 /*------- Actually mail the message ------*/
3879 if(valid_addr
== CA_OK
3880 && (outgoing
->to
|| outgoing
->cc
3881 || outgoing
->bcc
|| lcc_addr
)){
3882 char **alt_smtp
= NULL
;
3884 if(role
&& role
->smtp
){
3885 if(ps_global
->FIX_SMTP_SERVER
3886 && ps_global
->FIX_SMTP_SERVER
[0])
3887 q_status_message(SM_ORDER
| SM_DING
, 5, 5, "Use of a role-defined smtp-server is administratively prohibited");
3889 alt_smtp
= role
->smtp
;
3892 result
|= (call_mailer(&header
, *body
, alt_smtp
,
3894 call_mailer_file_result
,
3896 ? P_MAIL_WIN
: P_MAIL_LOSE
;
3898 if(result
& P_MAIL_LOSE
)
3899 mark_address_failure_for_pico(&header
);
3902 /*----- Was there an fcc involved? -----*/
3904 /*------ Write it if at least something worked ------*/
3905 if((result
& (P_MAIL_WIN
| P_NEWS_WIN
))
3906 || (!(result
& (P_MAIL_BITS
| P_NEWS_BITS
))
3907 && pine_rfc822_output(&header
, *body
,
3911 strncpy(label
, "Fcc", sizeof(label
));
3912 label
[sizeof(label
)-1] = '\0';
3913 if(strcmp(fcc
, ps_global
->VAR_DEFAULT_FCC
)){
3914 snprintf(label
+ 3, sizeof(label
)-3, " to %s", fcc
);
3915 label
[sizeof(label
)-1] = '\0';
3918 /*-- Now actually copy to fcc folder and close --*/
3919 result
|= (write_fcc(fcc
, fcc_cntxt
, lmc
.so
,
3921 F_ON(F_MARK_FCC_SEEN
, ps_global
)
3923 ? P_FCC_WIN
: P_FCC_LOSE
;
3925 else if(!(result
& (P_MAIL_BITS
| P_NEWS_BITS
))){
3926 q_status_message(SM_ORDER
, 3, 5,
3927 _("Fcc Failed!. No message saved."));
3929 "explicit fcc write failed!\n"));
3930 result
|= P_FCC_LOSE
;
3936 if(result
& (P_MAIL_LOSE
| P_NEWS_LOSE
| P_FCC_LOSE
)){
3938 * Encode child's result in hi-byte of
3941 editor_result
= ((result
<< 8) | COMP_GOTHUP
);
3948 if(ps_global
->post
->pid
> 0){
3949 q_status_message(SM_ORDER
, 3, 3,
3950 _("Message handed off for posting"));
3951 break; /* up to our child now */
3954 q_status_message1(SM_ORDER
| SM_DING
, 3, 3,
3955 "Can't fork for send: %s",
3956 error_description(errno
));
3957 if(ps_global
->post
->fcc
)
3958 fs_give((void **) &ps_global
->post
->fcc
);
3960 fs_give((void **) &ps_global
->post
);
3963 if(lmc
.so
) /* throw away unused store obj */
3966 if(outgoing
->message_id
)
3967 fs_give((void **) &outgoing
->message_id
);
3969 outgoing
->message_id
= generate_message_id();
3971 continue; /* if we got here, there was a prob */
3973 #endif /* BACKGROUND_POST */
3975 /*------- Actually mail the message ------*/
3976 if(valid_addr
== CA_OK
3977 && (outgoing
->to
|| outgoing
->cc
|| outgoing
->bcc
|| lcc_addr
)){
3978 char **alt_smtp
= NULL
;
3980 if(role
&& role
->smtp
){
3981 if(ps_global
->FIX_SMTP_SERVER
3982 && ps_global
->FIX_SMTP_SERVER
[0])
3983 q_status_message(SM_ORDER
| SM_DING
, 5, 5, "Use of a role-defined smtp-server is administratively prohibited");
3985 alt_smtp
= role
->smtp
;
3988 result
|= (call_mailer(&header
, *body
, alt_smtp
,
3990 call_mailer_file_result
,
3992 ? P_MAIL_WIN
: P_MAIL_LOSE
;
3994 if(result
& P_MAIL_LOSE
)
3995 mark_address_failure_for_pico(&header
);
3998 /*----- Was there an fcc involved? -----*/
4000 /*------ Write it if at least something worked ------*/
4001 if((result
& (P_MAIL_WIN
| P_NEWS_WIN
))
4002 || (!(result
& (P_MAIL_BITS
| P_NEWS_BITS
))
4003 && pine_rfc822_output(&header
, *body
, NULL
, NULL
))){
4006 strncpy(label
, "Fcc", sizeof(label
));
4007 label
[sizeof(label
)-1] = '\0';
4008 if(strcmp(fcc
, ps_global
->VAR_DEFAULT_FCC
)){
4009 snprintf(label
+ 3, sizeof(label
)-3, " to %s", fcc
);
4010 label
[sizeof(label
)-1] = '\0';
4013 /*-- Now actually copy to fcc folder and close --*/
4014 result
|= (write_fcc(fcc
, fcc_cntxt
, lmc
.so
, NULL
, label
,
4015 F_ON(F_MARK_FCC_SEEN
, ps_global
)
4017 ? P_FCC_WIN
: P_FCC_LOSE
;
4019 else if(!(result
& (P_MAIL_BITS
| P_NEWS_BITS
))){
4020 q_status_message(SM_ORDER
,3,5,
4021 _("Fcc Failed!. No message saved."));
4022 dprint((1, "explicit fcc write failed!\n"));
4023 result
|= P_FCC_LOSE
;
4029 /*----- Mail Post FAILED, back to composer -----*/
4030 if(result
& (P_MAIL_LOSE
| P_FCC_LOSE
)){
4031 dprint((1, "Send failed, continuing\n"));
4033 if(result
& P_FCC_LOSE
){
4035 * Find field entry associated with fcc, and start
4038 for(pf
= header
.local
; pf
&& pf
->name
; pf
= pf
->next
)
4039 if(pf
->type
== Fcc
&& HE(pf
))
4040 HE(pf
)->start_here
= 1;
4042 q_status_message(SM_ORDER
| SM_DING
, 3, 3,
4043 pine_send_status(result
, fcc
,
4044 tmp_20k_buf
, SIZEOF_20KBUF
, NULL
));
4047 if(outgoing
->message_id
)
4048 fs_give((void **) &outgoing
->message_id
);
4050 outgoing
->message_id
= generate_message_id();
4056 * If message sent *completely* successfully, there's a
4057 * reply struct AND we're allowed to write back state, do it.
4058 * But also protect against shifted message numbers due
4059 * to new mail arrival. Since the number passed is based
4060 * on the real imap msg no, AND we're sure no expunge has
4061 * been done, just fix up the sorted number...
4063 update_answered_flags(reply
);
4065 /*----- Signed, sealed, delivered! ------*/
4066 q_status_message(SM_ORDER
, 0, 3,
4067 pine_send_status(result
, fcc
, tmp_20k_buf
, SIZEOF_20KBUF
, NULL
));
4069 break; /* All's well, pop out of here */
4077 fs_give((void **)&fcc
);
4079 free_body_particulars(bp
);
4081 free_attachment_list(&pbf
->attachments
);
4083 standard_picobuf_teardown(pbf
);
4085 for(i
=0; i
< fixed_cnt
; i
++){
4086 if(pfields
[i
].textbuf
)
4087 fs_give((void **)&pfields
[i
].textbuf
);
4089 fs_give((void **)&pfields
[i
].name
);
4093 mail_free_address(&lcc_addr
);
4096 mail_free_address(&nobody_addr
);
4098 free_prompts(header
.custom
);
4099 free_customs(header
.custom
);
4100 fs_give((void **)&pfields
);
4101 free_headents(&headents
);
4102 fs_give((void **)&sending_order
);
4103 if(suggested_nntp_server
)
4104 fs_give((void **)&suggested_nntp_server
);
4106 fs_give((void **)&title
);
4108 if(local_redraft_pos
&& local_redraft_pos
!= redraft_pos
)
4109 free_redraft_pos(&local_redraft_pos
);
4111 pbf
= save_previous_pbuf
;
4114 dprint((4, "=== send returning ===\n"));
4119 * Check for subject in outgoing message.
4121 * Asks user whether to proceed with no subject.
4124 check_for_subject(METAENV
*header
)
4129 for(pf
= header
->local
; pf
&& pf
->name
; pf
= pf
->next
)
4130 if(pf
->type
== Subject
){
4131 if(pf
->text
&& *pf
->text
&& **pf
->text
)
4134 if(want_to("No Subject, send anyway ",
4135 'n', 'n', h_send_check_subj
, WT_NORM
) == 'y')
4150 * Check for fcc in outgoing message.
4152 * Asks user whether to proceed with no fcc.
4155 check_for_fcc(char *fcc
)
4162 if(want_to("No Fcc, send anyway ", 'n', 'n', h_send_check_fcc
, WT_NORM
) == 'y')
4173 * Confirm that the user wants to send to MAILER-DAEMON
4176 confirm_daemon_send(void)
4178 return(want_to("Really send this message to the MAILER-DAEMON",
4179 'n', 'n', NO_HELP
, WT_NORM
) == 'y');
4184 free_prompts(PINEFIELD
*head
)
4188 for(pf
= head
; pf
&& pf
->name
; pf
= pf
->next
){
4189 if(HE(pf
) && HE(pf
)->prompt
)
4190 fs_give((void **)& HE(pf
)->prompt
);
4196 postpone_prompt(void)
4198 static ESCKEY_S pstpn_form_opt
[] = { {'p', 'p', "P", N_("Postponed Folder")},
4199 {'f', 'f', "F", N_("Form Letter Folder")},
4200 {-1, 0, NULL
, NULL
} };
4202 return(radio_buttons(PSTPN_FORM_PMT
, -FOOTER_ROWS(ps_global
),
4203 pstpn_form_opt
, 'p', 0, NO_HELP
, RB_FLUSH_IN
));
4208 * call__mailer_file_result - some results from call_mailer might be in a file.
4209 * dislplay that file.
4212 call_mailer_file_result(char *filename
, int style
)
4215 if(style
& CM_BR_VERBOSE
){
4216 display_output_file(filename
, "Verbose SMTP Interaction", NULL
, DOF_BRIEF
);
4219 display_output_file(filename
, "POSTING ERRORS", "Posting Error", DOF_EMPTY
);
4225 mark_address_failure_for_pico(METAENV
*header
)
4229 int error_count
= 0;
4230 struct headerentry
*last_he
= NULL
;
4232 for(pf
= header
->local
; pf
&& pf
->name
; pf
= pf
->next
)
4233 if(pf
->type
== Address
&& pf
->rcptto
&& pf
->addr
&& *pf
->addr
)
4234 for(a
= *pf
->addr
; a
!= NULL
; a
= a
->next
)
4236 && error_count
++ < MAX_ADDR_ERROR
4238 if(last_he
) /* start last reported err */
4239 last_he
->start_here
= 0;
4241 (last_he
= HE(pf
))->start_here
= 1;
4248 * This is specialized routine. It assumes that the only things that we
4249 * care about restoring are the body type, subtype, encoding and the
4250 * state of the charset parameter. It also assumes that if the charset
4251 * parameter exists when we save it, it won't be removed later.
4253 BODY_PARTICULARS_S
*
4254 save_body_particulars(struct mail_bodystruct
*body
)
4256 BODY_PARTICULARS_S
*bp
;
4259 bp
= (BODY_PARTICULARS_S
*)fs_get(sizeof(BODY_PARTICULARS_S
));
4261 bp
->type
= body
->type
;
4262 bp
->encoding
= body
->encoding
;
4263 bp
->subtype
= body
->subtype
? cpystr(body
->subtype
) : NULL
;
4264 bp
->parameter
= body
->parameter
;
4265 for(pm
= bp
->parameter
;
4266 pm
&& strucmp(pm
->attribute
, "charset") != 0;
4268 ;/* searching for possible charset parameter */
4270 if(pm
){ /* found one */
4271 bp
->had_csp
= 1; /* saved body had charset parameter */
4272 bp
->charset
= pm
->value
? cpystr(pm
->value
) : NULL
;
4284 reset_body_particulars(BODY_PARTICULARS_S
*bp
, struct mail_bodystruct
*body
)
4286 body
->type
= bp
->type
;
4287 body
->encoding
= bp
->encoding
;
4289 fs_give((void **)&body
->subtype
);
4291 body
->subtype
= bp
->subtype
? cpystr(bp
->subtype
) : NULL
;
4294 PARAMETER
*pm
, *pm_prev
= NULL
;
4296 for(pm
= body
->parameter
;
4297 pm
&& strucmp(pm
->attribute
, "charset") != 0;
4301 if(pm
){ /* body has charset parameter */
4302 if(bp
->had_csp
){ /* reset to what it used to be */
4304 fs_give((void **)&pm
->value
);
4306 pm
->value
= bp
->charset
? cpystr(bp
->charset
) : NULL
;
4308 else{ /* remove charset parameter */
4310 pm_prev
->next
= pm
->next
;
4312 body
->parameter
= pm
->next
;
4314 mail_free_body_parameter(&pm
);
4320 * This can't happen because grope never removes
4321 * the charset parameter.
4323 q_status_message(SM_ORDER
| SM_DING
, 5, 5,
4324 "Programmer error: saved charset but no current charset param in pine_send");
4328 ok, still no parameter
4335 mail_free_body_parameter(&body
->parameter
);
4337 body
->parameter
= NULL
;
4343 free_body_particulars(BODY_PARTICULARS_S
*bp
)
4347 fs_give((void **)&bp
->subtype
);
4350 fs_give((void **)&bp
->charset
);
4352 fs_give((void **)&bp
);
4357 /*----------------------------------------------------------------------
4358 Build a status message suitable for framing
4360 Returns: pointer to resulting buffer
4363 pine_send_status(int result
, char *fcc_name
, char *buf
, size_t buflen
, int *goodorbad
)
4365 int avail
= ps_global
->ttyo
->screen_cols
- 2;
4366 int fixedneed
, need
, lenfcc
;
4367 char *part1
, *part2
, *part3
, *part4
, *part5
;
4368 char fbuf
[MAILTMPLEN
+1];
4370 part1
= (result
& P_NEWS_WIN
)
4372 : (result
& P_NEWS_LOSE
)
4375 part2
= ((result
& P_NEWS_BITS
) && (result
& P_MAIL_BITS
)
4376 && (result
& P_FCC_BITS
))
4378 : ((result
& P_NEWS_BITS
) && (result
& (P_MAIL_BITS
| P_FCC_BITS
)))
4381 part3
= (result
& P_MAIL_WIN
)
4383 : (result
& P_MAIL_LOSE
)
4386 part4
= ((result
& P_MAIL_BITS
) && (result
& P_FCC_BITS
))
4389 part5
= ((result
& P_FCC_WIN
) && !(result
& (P_MAIL_WIN
| P_NEWS_WIN
)))
4391 : (result
& P_FCC_WIN
)
4393 : (result
& P_FCC_LOSE
)
4396 lenfcc
= MIN(sizeof(fbuf
)-1, (result
& P_FCC_BITS
) ? strlen(fcc_name
) : 0);
4398 fixedneed
= 9 + strlen(part1
) + strlen(part2
) + strlen(part3
) +
4399 strlen(part4
) + strlen(part5
);
4400 need
= fixedneed
+ ((result
& P_FCC_BITS
) ? 2 : 0) + lenfcc
;
4402 if(need
> avail
&& fixedneed
+ 3 >= avail
){
4403 /* dots on end of fixed, no fcc */
4404 snprintf(fbuf
, sizeof(fbuf
), "Message %s%s%s%s%s ",
4405 part1
, part2
, part3
, part4
, part5
);
4406 short_str(fbuf
, buf
, buflen
, avail
, EndDots
);
4408 else if(need
> avail
){
4409 /* include whole fixed part, quotes and dots at end of fcc name */
4411 lenfcc
= MAX(1, lenfcc
-(need
-avail
));
4413 snprintf(buf
, buflen
, "Message %s%s%s%s%s%s%s%s.",
4414 part1
, part2
, part3
, part4
, part5
,
4415 (result
& P_FCC_BITS
) ? "\"" : "",
4416 short_str((result
& P_FCC_BITS
) ? fcc_name
: "",
4417 fbuf
, sizeof(fbuf
), lenfcc
, FrontDots
),
4418 (result
& P_FCC_BITS
) ? "\"" : "");
4422 snprintf(buf
, buflen
, "Message %s%s%s%s%s%s%s%s.",
4423 part1
, part2
, part3
, part4
, part5
,
4424 (result
& P_FCC_BITS
) ? "\"" : "",
4425 (result
& P_FCC_BITS
) ? fcc_name
: "",
4426 (result
& P_FCC_BITS
) ? "\"" : "");
4430 *goodorbad
= (result
& (P_MAIL_LOSE
| P_NEWS_LOSE
| P_FCC_LOSE
)) == 0;
4435 /* Callback from Pico to set the conditions for Alpine to start a new thread
4439 new_thread_on_blank_subject(void)
4441 ps_global
->newthread
= F_ON(F_NEW_THREAD_ON_BLANK_SUBJECT
, ps_global
);
4446 /*----------------------------------------------------------------------
4447 Call back for pico to insert the specified message's text
4449 Args: n -- message number to format
4450 f -- function to use to output the formatted message
4453 Returns: returns msg number formatted on success, zero on error.
4456 message_format_for_pico(long int n
, int (*f
) (int))
4460 char *old_quote
= NULL
;
4463 if(!(n
> 0L && n
<= mn_get_total(ps_global
->msgmap
)
4464 && (e
= pine_mail_fetchstructure(ps_global
->mail_stream
,
4465 mn_m2raw(ps_global
->msgmap
, n
), &b
)))){
4466 q_status_message(SM_ORDER
|SM_DING
,3,3,"Error inserting Message");
4467 flush_status_messages(0);
4471 /* temporarily assign a new quote string */
4472 old_quote
= pbf
->quote_str
;
4473 pbf
->quote_str
= reply_quote_str(e
);
4475 /* build separator line */
4476 reply_delimiter(e
, NULL
, f
);
4478 /* actually write message text */
4479 if(!format_message(mn_m2raw(ps_global
->msgmap
, n
), e
, b
, NULL
,
4480 FM_NEW_MESS
| FM_DISPLAY
| FM_NOCOLOR
| FM_NOINDENT
, f
)){
4481 q_status_message(SM_ORDER
|SM_DING
,3,3,"Error inserting Message");
4482 flush_status_messages(0);
4486 fs_give((void **)&pbf
->quote_str
);
4487 pbf
->quote_str
= old_quote
;
4492 /*----------------------------------------------------------------------
4493 Call back for pico to prompt the user for exit confirmation
4495 Args: dflt -- default answer for confirmation prompt
4497 Returns: either NULL if the user accepts exit, or string containing
4498 reason why the user declined.
4501 send_exit_for_pico(struct headerentry
*he
, void (*redraw_pico
)(void), int allow_flowed
,
4504 int i
, rv
, c
, verbose_label
= 0, bg_label
= 0, old_suspend
;
4505 int dsn_label
= 0, fcc_label
= 0, lparen
;
4506 int flowing_label
= 0, double_rad
;
4507 char *rstr
= NULL
, *p
, *lc
, *optp
;
4508 char dsn_string
[30];
4509 void (*redraw
)(void) = ps_global
->redrawer
;
4514 struct filters
*prev
, *next
;
4515 } *filters
= NULL
, *fp
;
4517 sending_filter_requested
= NULL
;
4518 call_mailer_flags
= 0;
4519 background_requested
= 0;
4520 flowing_requested
= allow_flowed
? 1 : 0;
4521 lmc
.text_only
= F_ON(F_NO_FCC_ATTACH
, ps_global
) != 0;
4522 if(priority_requested
)
4523 fs_give((void **) &priority_requested
);
4525 if(background_posting(FALSE
)){
4527 *result
= "Can't send while background posting. Use postpone.";
4532 if(F_ON(F_SEND_WO_CONFIRM
, ps_global
)){
4539 ps_global
->redrawer
= redraw_pico
;
4541 if((old_suspend
= F_ON(F_CAN_SUSPEND
, ps_global
)) != 0)
4542 (void) F_SET(F_CAN_SUSPEND
, ps_global
, 0);
4545 * Build list of available filters...
4547 for(i
=0; ps_global
->VAR_SEND_FILTER
&& ps_global
->VAR_SEND_FILTER
[i
]; i
++){
4548 for(p
= ps_global
->VAR_SEND_FILTER
[i
];
4549 *p
&& !isspace((unsigned char)*p
); p
++)
4554 if(!(is_absolute_path(ps_global
->VAR_SEND_FILTER
[i
])
4555 && can_access(ps_global
->VAR_SEND_FILTER
[i
],EXECUTE_ACCESS
) ==0)){
4560 fp
= (struct filters
*)fs_get(sizeof(struct filters
));
4562 if((lc
= last_cmpnt(ps_global
->VAR_SEND_FILTER
[i
])) != NULL
){
4563 fp
->filter
= cpystr(lc
);
4565 else if((p
- ps_global
->VAR_SEND_FILTER
[i
]) > 20){
4566 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, "...%s", p
- 17);
4567 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
4568 fp
->filter
= cpystr(tmp_20k_buf
);
4571 fp
->filter
= cpystr(ps_global
->VAR_SEND_FILTER
[i
]);
4577 fp
->prev
= filters
->prev
;
4578 fp
->prev
->next
= filters
->prev
= fp
;
4581 filters
= (struct filters
*)fs_get(sizeof(struct filters
));
4582 filters
->index
= -1;
4583 filters
->filter
= NULL
;
4584 filters
->next
= filters
->prev
= fp
;
4585 fp
->next
= fp
->prev
= filters
;
4593 opts
[i
++].label
= N_("Yes");
4598 opts
[i
++].label
= N_("No");
4601 /* set global_filter_pointer to desired filter or NULL if none */
4602 /* prepare two keymenu slots for selecting filter */
4603 opts
[i
].ch
= ctrl('P');
4605 opts
[i
].name
= "^P";
4606 opts
[i
++].label
= N_("Prev Filter");
4608 opts
[i
].ch
= ctrl('N');
4610 opts
[i
].name
= "^N";
4611 opts
[i
++].label
= N_("Next Filter");
4613 if(F_ON(F_FIRST_SEND_FILTER_DFLT
, ps_global
))
4614 filters
= filters
->next
;
4617 if(F_ON(F_VERBOSE_POST
, ps_global
)){
4618 /* setup keymenu slot to toggle verbose mode */
4619 opts
[i
].ch
= ctrl('W');
4621 opts
[i
].name
= "^W";
4622 verbose_label
= i
++;
4626 /* setup keymenu slot to toggle flowed mode */
4627 opts
[i
].ch
= ctrl('V');
4629 opts
[i
].name
= "^V";
4630 flowing_label
= i
++;
4631 flowing_requested
= 1;
4634 if(F_ON(F_NO_FCC_ATTACH
, ps_global
)){
4635 /* setup keymenu slot to toggle attacment on fcc */
4636 opts
[i
].ch
= ctrl('F');
4638 opts
[i
].name
= "^F";
4642 #if defined(BACKGROUND_POST) && defined(SIGCHLD)
4643 if(F_ON(F_BACKGROUND_POST
, ps_global
)){
4644 opts
[i
].ch
= ctrl('R');
4646 opts
[i
].name
= "^R";
4654 opts
[i
++].label
= N_("Priority");
4657 if(F_OFF(F_DONT_DO_SMIME
, ps_global
)){
4661 opts
[i
++].label
= "Encrypt";
4666 opts
[i
++].label
= "Sign";
4668 if(ps_global
->smime
){
4669 ps_global
->smime
->do_encrypt
= F_ON(F_ENCRYPT_DEFAULT_ON
, ps_global
);
4670 ps_global
->smime
->do_sign
= F_ON(F_SIGN_DEFAULT_ON
, ps_global
);
4677 if(F_ON(F_DSN
, ps_global
)){
4678 /* setup keymenu slots to toggle dsn bits */
4682 opts
[i
].label
= N_("DSNOpts");
4687 opts
[i
++].label
= "";
4691 opts
[i
++].label
= "";
4695 opts
[i
++].label
= "";
4699 opts
[i
].ch
= KEY_UP
;
4702 opts
[i
++].label
= "";
4704 opts
[i
].ch
= KEY_DOWN
;
4707 opts
[i
++].label
= "";
4712 fix_windsize(ps_global
);
4715 if(filters
&& filters
->filter
&& (p
= strindex(filters
->filter
, ' ')))
4721 strncpy(tmp_20k_buf
, "Send message", SIZEOF_20KBUF
);
4722 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
4723 optp
= tmp_20k_buf
+ strlen(tmp_20k_buf
);
4725 if(F_ON(F_NO_FCC_ATTACH
, ps_global
) && !lmc
.text_only
)
4726 sstrncpy(&optp
, " and Fcc Atmts", SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4728 if(allow_flowed
&& !flowing_requested
){
4729 if((optp
-tmp_20k_buf
)+2 < SIZEOF_20KBUF
){
4739 sstrncpy(&optp
, "not flowed", SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4743 if((optp
-tmp_20k_buf
)+2 < SIZEOF_20KBUF
){
4755 if(filters
->filter
){
4756 sstrncpy(&optp
, "filtered thru \"", SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4757 sstrncpy(&optp
, filters
->filter
, SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4758 if((optp
-tmp_20k_buf
) < SIZEOF_20KBUF
)
4762 sstrncpy(&optp
, "unfiltered", SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4765 if((call_mailer_flags
& CM_VERBOSE
) || background_requested
){
4766 if((optp
-tmp_20k_buf
)+2 < SIZEOF_20KBUF
){
4776 sstrncpy(&optp
, "in ", SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4777 if(call_mailer_flags
& CM_VERBOSE
)
4778 sstrncpy(&optp
, "verbose ", SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4780 if(background_requested
)
4781 sstrncpy(&optp
, "background ", SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4783 sstrncpy(&optp
, "mode", SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4786 if(g_rolenick
&& !(he
&& he
[N_FROM
].dirty
)){
4787 if((optp
-tmp_20k_buf
)+2 < SIZEOF_20KBUF
){
4797 sstrncpy(&optp
, "as \"", SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4798 sstrncpy(&optp
, g_rolenick
, SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4799 sstrncpy(&optp
, "\"", SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4802 if(call_mailer_flags
& CM_DSN_SHOW
){
4803 if((optp
-tmp_20k_buf
)+2 < SIZEOF_20KBUF
){
4815 sstrncpy(&optp
, dsn_string
, SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4819 if(ps_global
->smime
&& ps_global
->smime
->do_encrypt
){
4820 if((optp
-tmp_20k_buf
)+2 < SIZEOF_20KBUF
){
4832 sstrncpy(&optp
, "Encrypted", SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4835 if(ps_global
->smime
&& ps_global
->smime
->do_sign
){
4836 if((optp
-tmp_20k_buf
)+2 < SIZEOF_20KBUF
){
4848 sstrncpy(&optp
, "Signed", SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4852 if(lparen
&& (optp
-tmp_20k_buf
) < SIZEOF_20KBUF
)
4855 sstrncpy(&optp
, "? ", SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4856 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
4862 opts
[flowing_label
].label
= flowing_requested
? N_("NoFlow") : N_("Flow");
4865 opts
[verbose_label
].label
= (call_mailer_flags
& CM_VERBOSE
) ? N_("Normal") : N_("Verbose");
4868 opts
[bg_label
].label
= background_requested
4869 ? N_("Foreground") : N_("Background");
4872 opts
[fcc_label
].label
= lmc
.text_only
? N_("Fcc Attchmnts")
4873 : N_("No Fcc Atmts ");
4875 if(F_ON(F_DSN
, ps_global
)){
4876 if(call_mailer_flags
& CM_DSN_SHOW
){
4877 opts
[dsn_label
].label
= (call_mailer_flags
& CM_DSN_DELAY
)
4878 ? N_("NoDelay") : N_("Delay");
4879 opts
[dsn_label
+1].ch
= 's';
4880 opts
[dsn_label
+1].label
= (call_mailer_flags
& CM_DSN_SUCCESS
)
4881 ? N_("NoSuccess") : N_("Success");
4882 opts
[dsn_label
+2].ch
= 'x';
4883 opts
[dsn_label
+2].label
= (call_mailer_flags
& CM_DSN_NEVER
)
4884 ? N_("ErrRets") : N_("NoErrRets");
4885 opts
[dsn_label
+3].ch
= 'h';
4886 opts
[dsn_label
+3].label
= (call_mailer_flags
& CM_DSN_FULL
)
4887 ? N_("RetHdrs") : N_("RetFull");
4892 ((call_mailer_flags
& CM_DSN_SHOW
)
4893 ? 4 : F_ON(F_DSN
, ps_global
) ? 1 : 0) > 11)
4894 rv
= double_radio_buttons(tmp_20k_buf
, -FOOTER_ROWS(ps_global
), opts
,
4896 (F_ON(F_DSN
, ps_global
) && allow_flowed
)
4897 ? h_send_prompt_dsn_flowed
:
4898 F_ON(F_DSN
, ps_global
) ? h_send_prompt_dsn
:
4899 allow_flowed
? h_send_prompt_flowed
:
4903 rv
= radio_buttons(tmp_20k_buf
, -FOOTER_ROWS(ps_global
), opts
,
4906 ((call_mailer_flags
& CM_DSN_SHOW
)
4907 ? 4 : F_ON(F_DSN
, ps_global
) ? 1 : 0) == 11)
4909 (F_ON(F_DSN
, ps_global
) && allow_flowed
)
4910 ? h_send_prompt_dsn_flowed
:
4911 F_ON(F_DSN
, ps_global
) ? h_send_prompt_dsn
:
4912 allow_flowed
? h_send_prompt_flowed
:
4916 if(rv
== 'y'){ /* user ACCEPTS! */
4919 else if(rv
== 'n'){ /* Declined! */
4920 rstr
= _("No Message Sent");
4923 else if(rv
== 'z'){ /* Cancelled! */
4924 rstr
= _("Send Cancelled");
4927 else if(rv
== 10){ /* PREVIOUS filter */
4928 filters
= filters
->prev
;
4930 else if(rv
== 11){ /* NEXT filter */
4931 filters
= filters
->next
;
4934 lmc
.text_only
= !lmc
.text_only
;
4936 else if(rv
== 12){ /* flip verbose bit */
4937 if(call_mailer_flags
& CM_VERBOSE
)
4938 call_mailer_flags
&= ~CM_VERBOSE
;
4940 call_mailer_flags
|= CM_VERBOSE
;
4942 if((call_mailer_flags
& CM_VERBOSE
) && background_requested
)
4943 background_requested
= 0;
4945 else if(rv
== 22){ /* flip flowing bit */
4946 flowing_requested
= !flowing_requested
;
4949 if((background_requested
= !background_requested
)
4950 && (call_mailer_flags
& CM_VERBOSE
))
4951 call_mailer_flags
&= ~CM_VERBOSE
; /* clear verbose */
4953 else if(call_mailer_flags
& CM_DSN_SHOW
){
4954 if(rv
== 's'){ /* flip success bit */
4955 call_mailer_flags
^= CM_DSN_SUCCESS
;
4956 /* turn off related bits */
4957 if(call_mailer_flags
& CM_DSN_SUCCESS
)
4958 call_mailer_flags
&= ~(CM_DSN_NEVER
);
4960 else if(rv
== 'd'){ /* flip delay bit */
4961 call_mailer_flags
^= CM_DSN_DELAY
;
4962 /* turn off related bits */
4963 if(call_mailer_flags
& CM_DSN_DELAY
)
4964 call_mailer_flags
&= ~(CM_DSN_NEVER
);
4966 else if(rv
== 'x'){ /* flip never bit */
4967 call_mailer_flags
^= CM_DSN_NEVER
;
4968 /* turn off related bits */
4969 if(call_mailer_flags
& CM_DSN_NEVER
)
4970 call_mailer_flags
&= ~(CM_DSN_SUCCESS
| CM_DSN_DELAY
);
4972 else if(rv
== 'h'){ /* flip full bit */
4973 call_mailer_flags
^= CM_DSN_FULL
;
4976 else if(rv
== 'd'){ /* show dsn options */
4978 * When you turn on DSN, the default is to notify on
4979 * failure, success, or delay; and to return the whole
4982 call_mailer_flags
|= (CM_DSN_SHOW
| CM_DSN_SUCCESS
| CM_DSN_DELAY
| CM_DSN_FULL
);
4984 else if(rv
== 'p'){ /* choose X-Priority */
4987 prio
= choose_a_priority(priority_requested
);
4988 if((ps_global
->redrawer
= redraw_pico
) != NULL
){
4989 (*ps_global
->redrawer
)();
4990 fix_windsize(ps_global
);
4994 if(priority_requested
)
4995 fs_give((void **) &priority_requested
);
4998 priority_requested
= prio
;
5000 fs_give((void **) &prio
);
5005 if(ps_global
->smime
)
5006 ps_global
->smime
->do_encrypt
= !ps_global
->smime
->do_encrypt
;
5009 if(ps_global
->smime
)
5010 ps_global
->smime
->do_sign
= !ps_global
->smime
->do_sign
;
5014 snprintf(dsn_string
, sizeof(dsn_string
), "DSN requested[%s%s%s%s]",
5015 (call_mailer_flags
& CM_DSN_NEVER
)
5017 (call_mailer_flags
& CM_DSN_DELAY
)
5019 (call_mailer_flags
& CM_DSN_SUCCESS
)
5021 (call_mailer_flags
& CM_DSN_NEVER
)
5023 : (call_mailer_flags
& CM_DSN_FULL
) ? "-Full"
5025 dsn_string
[sizeof(dsn_string
)-1] = '\0';
5028 /* remember selection */
5029 if(filters
&& filters
->index
> -1)
5030 sending_filter_requested
= ps_global
->VAR_SEND_FILTER
[filters
->index
];
5033 filters
->prev
->next
= NULL
; /* tie off list */
5034 while(filters
){ /* then free it */
5037 fs_give((void **)&filters
->filter
);
5039 fs_give((void **)&filters
);
5045 (void) F_SET(F_CAN_SUSPEND
, ps_global
, 1);
5050 ps_global
->redrawer
= redraw
;
5052 return((rstr
== NULL
) ? 0 : 1);
5057 * Allow user to choose a priority for sending.
5059 * Returns an allocated priority on success, NULL otherwise.
5062 choose_a_priority(char *default_val
)
5064 char *choice
= NULL
;
5065 char **priority_list
, **lp
;
5066 char *starting_val
= NULL
;
5071 for(cnt
= 0, p
= priorities
; p
&& p
->desc
; p
++)
5074 cnt
++; /* for NONE entry */
5075 lp
= priority_list
= (char **) fs_get((cnt
+ 1) * sizeof(*priority_list
));
5076 memset(priority_list
, 0, (cnt
+1) * sizeof(*priority_list
));
5078 for(i
= 0, p
= priorities
; p
&& p
->desc
; p
++){
5079 *lp
= cpystr(p
->desc
);
5080 if(default_val
&& !strcmp(default_val
, p
->desc
))
5081 starting_val
= (*lp
);
5086 none
= _("NONE - No X-Priority header included");
5089 starting_val
= (*lp
);
5091 /* TRANSLATORS: SELECT A PRIORITY is a screen title
5092 TRANSLATORS: Print something1 using something2.
5093 "priorities" is something1 */
5094 choice
= choose_item_from_list(priority_list
, NULL
, _("SELECT A PRIORITY"),
5095 _("priorities"), h_select_priority_screen
,
5096 _("HELP FOR SELECTING A PRIORITY"),
5100 q_status_message(SM_ORDER
, 1, 4, _("No change"));
5101 else if(!strcmp(choice
, none
))
5104 free_list_array(&priority_list
);
5111 dont_flow_this_time(void)
5113 return(flowing_requested
? 0 : 1);
5117 /*----------------------------------------------------------------------
5118 Call back for pico to display mime type of attachment
5120 Args: file -- filename being attached
5122 Returns: returns 1 on success (message queued), zero otherwise (don't know
5123 type so nothing queued).
5126 mime_type_for_pico(char *file
)
5130 void *file_contents
;
5132 body
= mail_newbody();
5133 body
->type
= TYPEOTHER
;
5134 body
->encoding
= ENCOTHER
;
5136 /* don't know where the cursor's been, reset it */
5138 if(!set_mime_type_by_extension(body
, file
)){
5139 if((file_contents
=(void *)so_get(FileStar
,file
,READ_ACCESS
|READ_FROM_LOCALE
)) != NULL
){
5140 body
->contents
.text
.data
= file_contents
;
5141 set_mime_type_by_grope(body
);
5145 if(body
->type
!= TYPEOTHER
){
5147 q_status_message3(SM_ORDER
, 0, 3,
5148 _("File %s attached as type %s/%s"), file
,
5149 body_types
[body
->type
],
5150 body
->subtype
? body
->subtype
: rfc822_default_subtype(body
->type
));
5155 pine_free_body(&body
);
5160 /*----------------------------------------------------------------------
5161 Call back for pico to receive an uploaded message
5163 Args: fname -- name for uploaded file (empty if they want us to assign it)
5164 size -- pointer to long to hold the attachment's size
5166 Notes: the attachment is uploaded to a temp file, and
5168 Returns: TRUE on success, FALSE otherwise
5171 upload_msg_to_pico(char *fname
, size_t fnlen
, long int *size
)
5173 char cmd
[MAXPATH
+1], *fnp
= NULL
;
5174 char *locale_name
= NULL
;
5178 dprint((1, "Upload cmd called to xfer \"%s\"\n",
5179 fname
? fname
: "<NO FILE>"));
5181 if(!fname
) /* no place for file name */
5184 if(!*fname
){ /* caller wants temp file */
5185 if((fnp
= temp_nam(NULL
, "pu")) != NULL
){
5186 strncpy(fname
, fnp
, fnlen
);
5187 fname
[fnlen
-1] = '\0';
5189 fs_give((void **)&fnp
);
5193 locale_name
= convert_to_locale(fname
);
5195 build_updown_cmd(cmd
, sizeof(cmd
), ps_global
->VAR_UPLOAD_CMD_PREFIX
,
5196 ps_global
->VAR_UPLOAD_CMD
, locale_name
? locale_name
: fname
);
5197 if((syspipe
= open_system_pipe(cmd
, NULL
, NULL
, PIPE_USER
| PIPE_RESET
,
5198 0, pipe_callback
, pipe_report_error
)) != NULL
){
5199 (void) close_system_pipe(&syspipe
, NULL
, pipe_callback
);
5200 if((l
= name_file_size(locale_name
? locale_name
: fname
)) < 0L){
5201 q_status_message2(SM_ORDER
| SM_DING
, 3, 4,
5202 "Error determining size of %s: %s", fname
,
5203 fnp
= error_description(errno
));
5205 "!!! Upload cmd \"%s\" failed for \"%s\": %s\n",
5207 fname
? fname
: "?",
5214 fs_give((void **) &locale_name
);
5219 q_status_message(SM_ORDER
| SM_DING
, 3, 4, _("Error opening pipe"));
5222 fs_give((void **) &locale_name
);
5229 cancel_for_pico(void (*redraw_pico
)(void))
5234 _("Cancel message (answering \"Confirm\" will abandon your mail message) ? ");
5235 void (*redraw
)(void) = ps_global
->redrawer
;
5236 static ESCKEY_S opts
[] = {
5237 {'c', 'c', "C", N_("Confirm")},
5238 {'n', 'n', "N", N_("No")},
5243 ps_global
->redrawer
= redraw_pico
;
5244 fix_windsize(ps_global
);
5247 rv
= radio_buttons(prompt
, -FOOTER_ROWS(ps_global
), opts
,
5248 'n', 'x', h_confirm_cancel
, RB_NORM
);
5249 if(rv
== 'c'){ /* user ACCEPTS! */
5254 q_status_message(SM_INFO
, 1, 3, _(" Type \"C\" to cancel message "));
5255 display_message('x');
5261 ps_global
->redrawer
= redraw
;
5266 /*----------------------------------------------------------------------
5267 Pass the first text segment of the message thru the "send filter"
5269 Args: body pointer and address for storage object of old data
5271 Returns: returns 1 on success, zero on error.
5274 filter_message_text(char *fcmd
, ENVELOPE
*outgoing
, struct mail_bodystruct
*body
,
5275 STORE_S
**old
, METAENV
*header
)
5277 char *cmd
, *tmpf
= NULL
, *resultf
= NULL
, *errstr
= NULL
, *mtf
= NULL
;
5278 int key
= 0, include_hdrs
= 0;
5280 STORE_S
**so
= (STORE_S
**)((body
->type
== TYPEMULTIPART
)
5281 ? &body
->nested
.part
->body
.contents
.text
.data
5282 : &body
->contents
.text
.data
),
5283 *tmp_so
= NULL
, *tmpf_so
,
5284 *save_local_so
, *readthis_so
, *our_tmpf_so
= NULL
;
5285 #define DO_HEADERS 1
5288 && (cmd
=expand_filter_tokens(fcmd
, outgoing
, &tmpf
, &resultf
, &mtf
,
5289 &key
, &include_hdrs
, NULL
))){
5292 * We need WRITE_TO_LOCALE here because the user is going to
5293 * be operating on tmpf. We need to change it back after they
5296 if((tmpf_so
= so_get(FileStar
, tmpf
, EDIT_ACCESS
|OWNER_ONLY
|WRITE_TO_LOCALE
)) != NULL
){
5298 so_puts(tmpf_so
, filter_session_key());
5299 so_puts(tmpf_so
, NEWLINE
);
5303 * If the headers are wanted for filtering, we can just
5304 * stick them in the tmpf file that is already there before
5305 * putting the body in.
5308 save_local_so
= lmc
.so
;
5309 lmc
.so
= tmpf_so
; /* write it to tmpf_so */
5310 lmc
.all_written
= lmc
.text_written
= lmc
.text_only
= 0;
5311 pine_rfc822_header(header
, body
, NULL
, NULL
);
5312 lmc
.so
= save_local_so
;
5315 so_seek(*so
, 0L, 0);
5316 gf_set_so_readc(&gc
, *so
);
5317 gf_set_so_writec(&pc
, tmpf_so
);
5319 errstr
= gf_pipe(gc
, pc
);
5320 gf_clear_so_readc(*so
);
5321 gf_clear_so_writec(tmpf_so
);
5325 errstr
= "Can't create space for filter temporary file.";
5327 else if(include_hdrs
){
5329 * Gf_filter wants a single storage object to read from.
5330 * If headers are wanted for filtering we'll have to put them
5331 * and the body into a temp file first and then use that
5332 * as the storage object for gf_filter.
5333 * We don't use WRITE_TO_LOCALE in this case because gf_filter
5334 * takes care of that.
5336 if((our_tmpf_so
= so_get(TmpFileStar
, NULL
, EDIT_ACCESS
|OWNER_ONLY
)) != NULL
){
5337 /* put headers in our_tmpf_so */
5338 save_local_so
= lmc
.so
;
5339 lmc
.so
= our_tmpf_so
; /* write it to our_tmpf_so */
5340 lmc
.all_written
= lmc
.text_written
= lmc
.text_only
= 0;
5341 pine_rfc822_header(header
, body
, NULL
, NULL
);
5342 lmc
.so
= save_local_so
;
5344 /* put body in our_tmpf_so */
5345 so_seek(*so
, 0L, 0);
5346 gf_set_so_readc(&gc
, *so
);
5347 gf_set_so_writec(&pc
, our_tmpf_so
);
5349 errstr
= gf_pipe(gc
, pc
);
5350 gf_clear_so_readc(*so
);
5351 gf_clear_so_writec(our_tmpf_so
);
5353 /* tell gf_filter to read from our_tmpf_so instead of *so */
5354 readthis_so
= our_tmpf_so
;
5357 errstr
= "Can't create space for temporary file.";
5363 if((tmp_so
= so_get(PicoText
, NULL
, EDIT_ACCESS
)) != NULL
){
5364 gf_set_so_writec(&pc
, tmp_so
);
5365 ps_global
->mangled_screen
= 1;
5372 if((fpipe
= open_system_pipe(cmd
, NULL
, NULL
,
5373 PIPE_NOSHELL
| PIPE_RESET
,
5374 0, pipe_callback
, pipe_report_error
)) != NULL
){
5375 if(close_system_pipe(&fpipe
, NULL
, pipe_callback
) == 0){
5377 /* now we undo the WRITE_FROM_LOCALE change in tmpf */
5378 if((tmpf_so
= so_get(FileStar
, tmpf
, READ_ACCESS
|READ_FROM_LOCALE
)) != NULL
){
5379 gf_set_so_readc(&gc
, tmpf_so
);
5381 errstr
= gf_pipe(gc
, pc
);
5382 gf_clear_so_readc(tmpf_so
);
5386 errstr
= "Can't open temp file filter wrote.";
5389 errstr
= "Filter command returned error.";
5392 errstr
= "Can't exec filter text.";
5395 errstr
= gf_filter(cmd
, key
? filter_session_key() : NULL
,
5396 readthis_so
, pc
, NULL
, 0, 0,
5400 so_give(&our_tmpf_so
);
5402 gf_clear_so_writec(tmp_so
);
5407 * Can't really be using stdout, so don't print message that
5408 * gets printed in the else. Ideally the program being called
5409 * will wait after showing the message, we might want to look
5410 * into doing the waiting in console based apps... or not.
5416 fprintf(stdout
, "\r\n%s Hit return to continue.", errstr
);
5418 while((ch
= read_char(300)) != ctrl('M')
5419 && ch
!= NO_OP_IDLE
)
5423 #endif /* _WINDOWS */
5424 BODY
*b
= (body
->type
== TYPEMULTIPART
)
5425 ? &body
->nested
.part
->body
: body
;
5427 *old
= *so
; /* save old so */
5428 *so
= tmp_so
; /* return new one */
5429 (*so
)->attr
= copy_parameters((*old
)->attr
);
5432 * If the command said it would return new MIME
5433 * mime type data, check it out...
5436 char buf
[MAILTMPLEN
], *s
;
5439 if((fp
= our_fopen(mtf
, "rb")) != NULL
){
5440 if(fgets(buf
, sizeof(buf
), fp
)
5441 && !struncmp(buf
, "content-", 8)
5442 && (s
= strchr(buf
+8, ':'))){
5443 BODY
*nb
= mail_newbody();
5445 for(*s
++ = '\0'; *s
== ' '; s
++)
5448 rfc822_parse_content_header(nb
,
5449 (char *) ucase((unsigned char *) buf
+8),s
);
5450 if(nb
->type
== TYPETEXT
5453 || strucmp(b
->subtype
, nb
->subtype
))){
5455 fs_give((void **) &b
->subtype
);
5457 b
->subtype
= nb
->subtype
;
5460 mail_free_body_parameter(&b
->parameter
);
5461 b
->parameter
= nb
->parameter
;
5462 nb
->parameter
= NULL
;
5463 mail_free_body_parameter(&nb
->parameter
);
5466 mail_free_body(&nb
);
5474 * Reevaluate the encoding in case form's changed...
5476 b
->encoding
= ENCOTHER
;
5477 set_mime_type_by_grope(b
);
5484 errstr
= "Can't create space for filtered text.";
5487 fs_give((void **)&cmd
);
5494 fs_give((void **)&tmpf
);
5499 fs_give((void **) &mtf
);
5503 if(name_file_size(resultf
) > 0L)
5504 display_output_file(resultf
, "Filter", NULL
, DOF_BRIEF
);
5505 our_unlink(resultf
);
5506 fs_give((void **)&resultf
);
5512 q_status_message1(SM_ORDER
| SM_DING
, 3, 6, _("Problem filtering: %s"),
5514 dprint((1, "Filter FAILED: %s\n",
5515 errstr
? errstr
: "?"));
5518 return(errstr
== NULL
);
5522 /*----------------------------------------------------------------------
5523 Copy the newsgroup name of the given mailbox into the given buffer
5530 pine_send_newsgroup_name(char *mailbox
, char *group_name
, size_t len
)
5534 if(*mailbox
== '#'){ /* Strip the leading "#news." */
5535 strncpy(group_name
, mailbox
+ 6, len
-1);
5536 group_name
[len
-1] = '\0';
5538 else if(mail_valid_net_parse(mailbox
, &mb
)){
5539 pine_send_newsgroup_name(mb
.mailbox
, group_name
, len
);
5546 /*----------------------------------------------------------------------
5547 Generate and send a message back to the pine development team
5554 phone_home(char *addr
)
5556 char tmp
[MAX_ADDRESS
];
5560 outgoing
= mail_newenvelope();
5561 if(!addr
|| !strindex(addr
, '@')){
5562 snprintf(addr
= tmp
, sizeof(tmp
), "alpine%s@%s", PHONE_HOME_VERSION
, PHONE_HOME_HOST
);
5563 tmp
[sizeof(tmp
)-1] = '\0';
5566 rfc822_parse_adrlist(&outgoing
->to
, addr
, ps_global
->maildomain
);
5568 outgoing
->message_id
= generate_message_id();
5569 outgoing
->subject
= cpystr("Document Request");
5570 outgoing
->from
= phone_home_from();
5572 body
= mail_newbody();
5573 body
->type
= TYPETEXT
;
5575 if((body
->contents
.text
.data
= (void *)so_get(PicoText
,NULL
,EDIT_ACCESS
)) != NULL
){
5576 so_puts((STORE_S
*)body
->contents
.text
.data
, "Document request: ");
5577 so_puts((STORE_S
*)body
->contents
.text
.data
, "Alpine-");
5578 so_puts((STORE_S
*)body
->contents
.text
.data
, ALPINE_VERSION
);
5579 if(ps_global
->first_time_user
)
5580 so_puts((STORE_S
*)body
->contents
.text
.data
, " for New Users");
5582 if(ps_global
->VAR_INBOX_PATH
&& ps_global
->VAR_INBOX_PATH
[0] == '{')
5583 so_puts((STORE_S
*)body
->contents
.text
.data
, " and IMAP");
5585 if(ps_global
->VAR_NNTP_SERVER
&& ps_global
->VAR_NNTP_SERVER
[0]
5586 && ps_global
->VAR_NNTP_SERVER
[0][0])
5587 so_puts((STORE_S
*)body
->contents
.text
.data
, " and NNTP");
5589 (void) pine_simple_send(outgoing
, &body
, NULL
,NULL
,NULL
,NULL
, SS_NULLRP
);
5591 q_status_message(SM_ORDER
, 1, 3, "Thank you for being counted!");
5594 q_status_message(SM_ORDER
| SM_DING
, 3, 4,
5595 "Problem creating space for message text.");
5597 mail_free_envelope(&outgoing
);
5598 pine_free_body(&body
);
5603 /*----------------------------------------------------------------------
5604 Set up fields for passing to pico. Assumes first text part is
5605 intended to be passed along for editing, and is in the form of
5606 of a storage object brought into existence sometime before pico_send().
5609 outgoing2strings(METAENV
*header
, struct mail_bodystruct
*bod
, void **text
,
5610 PATMT
**pico_a
, int from_bounce
)
5615 * SIMPLIFYING ASSUMPTION #37: the first TEXT part's storage object
5616 * is guaranteed to be of type PicoText!
5618 if(bod
->type
== TYPETEXT
){
5619 *text
= so_text((STORE_S
*) bod
->contents
.text
.data
);
5621 /* mark storage object as user edited */
5623 (void) so_attr((STORE_S
*) bod
->contents
.text
.data
, "edited", "1");
5625 else if(bod
->type
== TYPEMULTIPART
){
5628 char *type
, *name
, *p
;
5632 * We used to jump out the window if the first part wasn't text,
5633 * but that may not be the case when bouncing a message with
5634 * a leading non-text segment. So, IT'S UNDERSTOOD that the
5635 * contents of the first part to send is still ALWAYS in a
5636 * PicoText storage object, *AND* if that object doesn't contain
5637 * data of type text, then it must contain THE ENCODED NON-TEXT
5638 * DATA of the piece being sent.
5640 * It's up to the programmer to make sure that such a message is
5641 * sent via pine_simple_send and never get to the composer via
5646 *text
= so_text((STORE_S
*) bod
->nested
.part
->body
.contents
.text
.data
);
5648 /* mark storage object as user edited */
5650 (void) so_attr((STORE_S
*) bod
->nested
.part
->body
.contents
.text
.data
, "edited", "1");
5653 * If we already had a list, blast it now, so we can build a new
5654 * attachment list that reflects what's really there...
5657 free_attachment_list(pico_a
);
5660 /* Simplifyihg assumption #28e. (see cross reference)
5661 All parts in the body passed in here that are not already
5662 in the attachments list are added to the end of the attachments
5663 list. Attachment items not in the body list will be taken care
5664 of in strings2outgoing, but they are unlikey to occur
5667 for(part
= bod
->nested
.part
->next
; part
!= NULL
; part
= part
->next
) {
5668 /* Already in list? */
5670 *ppa
&& strcmp((*ppa
)->id
, part
->body
.id
);
5671 ppa
= &(*ppa
)->next
)
5674 if(!*ppa
){ /* Not in the list! append it... */
5675 *ppa
= (PATMT
*)fs_get(sizeof(PATMT
));
5677 if(part
->body
.description
){
5681 len
= 4*strlen(part
->body
.description
)+1;
5682 p
= (char *)fs_get(len
*sizeof(char));
5683 if(rfc1522_decode_to_utf8((unsigned char *)p
,
5684 len
, part
->body
.description
) == (unsigned char *) p
){
5685 (*ppa
)->description
= p
;
5688 fs_give((void **)&p
);
5689 (*ppa
)->description
= cpystr(part
->body
.description
);
5693 (*ppa
)->description
= cpystr("");
5695 type
= type_desc(part
->body
.type
, part
->body
.subtype
,
5696 part
->body
.parameter
, NULL
, 0);
5699 * If we can find a "name" parm, display that too...
5701 if((name
= parameter_val(part
->body
.parameter
, "name")) != NULL
){
5702 /* Convert any [ or ]'s the name contained */
5703 for(p
= name
; *p
; p
++)
5714 (*ppa
)->filename
= fs_get(strlen(type
) + name_l
+ 5);
5716 snprintf((*ppa
)->filename
, strlen(type
) + name_l
+ 5, "[%s%s%s]", type
,
5717 name
? ": " : "", name
? name
: "");
5718 (*ppa
)->filename
[strlen(type
) + name_l
+ 5 - 1] = '\0';
5721 fs_give((void **) &name
);
5723 (*ppa
)->flags
= A_FLIT
;
5724 (*ppa
)->size
= cpystr(byte_string(
5725 send_body_size(&part
->body
)));
5727 part
->body
.id
= generate_message_id();
5729 (*ppa
)->id
= cpystr(part
->body
.id
);
5730 (*ppa
)->next
= NULL
;
5737 /*------------------------------------------------------------------
5738 Malloc strings to pass to composer editor because it expects
5739 such strings so it can realloc them
5740 -----------------------------------------------------------------*/
5742 * turn any address fields into text strings
5745 * SIMPLIFYING ASSUMPTION #116: all header strings are understood
5746 * NOT to be RFC1522 decoded. Said differently, they're understood
5747 * to be RFC1522 ENCODED as necessary. The intent is to preserve
5748 * original charset tagging as far into the compose/send pipe as
5751 for(pf
= header
->local
; pf
&& pf
->name
; pf
= pf
->next
)
5759 pf
->scratch
= addr_list_string(*pf
->addr
, NULL
, 1);
5762 * Scan for and fix-up patently bogus fields.
5764 * NOTE: collaboration with this code and what's done in
5765 * reply.c:reply_cp_addr to package up the bogus stuff
5768 for(p
= pf
->scratch
; (p
= strstr(p
, "@" RAWFIELD
)); )
5770 if(*t
== '&'){ /* find "leading" token */
5774 * Rfc822_cat has been changed so that it now quotes
5775 * this sometimes. So we have to look out for quotes
5776 * which confuse the decoder. It was only quoting
5777 * because we were putting \r \n in the input, I think.
5779 if(t
> pf
->scratch
&& t
[-1] == '\"' && p
[-1] == '\"')
5780 t
[-1] = p
[-1] = ' ';
5782 *t
++ = ' '; /* replace token */
5783 *p
= '\0'; /* tie off string */
5784 u
= rfc822_base64((unsigned char *) t
,
5785 (unsigned long) strlen(t
),
5786 (unsigned long *) &l
);
5790 replacelen
= strlen(t
);
5791 *p
= '@'; /* restore 'p' */
5792 rplstr(p
, strlen(p
), 12, ""); /* clear special token */
5793 rplstr(t
, strlen(u
)-replacelen
+1, replacelen
, u
);
5795 fs_give((void **) &u
);
5798 HE(pf
)->start_here
= 1;
5802 else if(t
== pf
->scratch
)
5805 removing_leading_white_space(pf
->scratch
);
5810 * Replace control characters with ^C notation, unless
5811 * some conditions are met (see istrncpy).
5812 * If user doesn't edit, then we switch back to the
5813 * original version. If user does edit, then all bets
5816 iutf8ncpy((char *)tmp_20k_buf
, pf
->scratch
, SIZEOF_20KBUF
-1);
5817 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
5818 if((l
=strlen((char *)tmp_20k_buf
)) > strlen(pf
->scratch
)){
5819 fs_give((void **)&pf
->scratch
);
5820 pf
->scratch
= (char *)fs_get((l
+1) * sizeof(char));
5823 strncpy(pf
->scratch
, (char *)tmp_20k_buf
, l
+1);
5834 src
= pf
->scratch
? pf
->scratch
5835 : (*pf
->text
) ? *pf
->text
: "";
5837 len
= 4*strlen(src
)+1;
5838 p
= (char *)fs_get(len
* sizeof(char));
5839 if(rfc1522_decode_to_utf8((unsigned char *)p
, len
, src
) == (unsigned char *) p
){
5841 fs_give((void **)&pf
->scratch
);
5846 fs_give((void **)&p
);
5848 pf
->scratch
= cpystr(src
);
5855 * Replace control characters with ^C notation, unless
5856 * some conditions are met (see istrncpy).
5857 * If user doesn't edit, then we switch back to the
5858 * original version. If user does edit, then all bets
5861 iutf8ncpy((char *)tmp_20k_buf
, pf
->scratch
, SIZEOF_20KBUF
-1);
5862 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
5863 if((l
=strlen((char *)tmp_20k_buf
)) > strlen(pf
->scratch
)){
5864 fs_give((void **)&pf
->scratch
);
5865 pf
->scratch
= (char *)fs_get((l
+1) * sizeof(char));
5868 strncpy(pf
->scratch
, (char *)tmp_20k_buf
, l
+1);
5880 /*----------------------------------------------------------------------
5881 Restore fields returned from pico to form useful to sending
5885 strings2outgoing(METAENV
*header
, struct mail_bodystruct
**bod
, PATMT
*attach
, int flow_it
)
5890 we_cancel
= busy_cue(NULL
, NULL
, 1);
5893 * turn any local address strings into address lists
5895 for(pf
= header
->local
; pf
&& pf
->name
; pf
= pf
->next
)
5897 char *the_address
= NULL
;
5901 removing_trailing_white_space(pf
->scratch
);
5903 if((the_address
|| *pf
->scratch
) && pf
->addr
){
5904 ADDRESS
*new_addr
= NULL
;
5905 static char *fakedomain
= "@";
5908 the_address
= pf
->scratch
;
5910 rfc822_parse_adrlist(&new_addr
, the_address
,
5911 (F_ON(F_COMPOSE_REJECTS_UNQUAL
, ps_global
))
5912 ? fakedomain
: ps_global
->maildomain
);
5913 mail_free_address(pf
->addr
); /* free old addrs */
5914 *pf
->addr
= new_addr
; /* assign new addr */
5917 mail_free_address(pf
->addr
); /* free old addrs */
5923 fs_give((void **)pf
->text
);
5926 *pf
->text
= cpystr(pf
->scratch
);
5935 fs_give((void **)&pf
->scratch
); /* free now useless text */
5938 create_message_body(bod
, attach
, flow_it
);
5941 cancel_busy_cue(-1);
5945 /*----------------------------------------------------------------------
5947 The head of the body list here is always either TEXT or MULTIPART. It may be
5948 changed from TEXT to MULTIPART if there are attachments to be added
5949 and it is not already multipart.
5952 create_message_body(struct mail_bodystruct
**b
, PATMT
*attach
, int flow_it
)
5956 BODY
*tmp_body
, *text_body
= NULL
;
5957 void *file_contents
;
5961 TIME_STAMP("create_body start.", 1);
5963 * if conditions are met short circuit MIME wrapping
5965 if((*b
)->type
!= TYPEMULTIPART
&& !attach
){
5967 /* only override assigned encoding if it might need upgrading */
5968 if((*b
)->type
== TYPETEXT
&& (*b
)->encoding
== ENC7BIT
)
5969 (*b
)->encoding
= ENCOTHER
;
5971 create_message_body_text(*b
, flow_it
);
5973 if(F_ON(F_COMPOSE_ALWAYS_DOWNGRADE
, ps_global
)
5974 || !((*b
)->encoding
== ENC8BIT
5975 || (*b
)->encoding
== ENCBINARY
)){
5976 TIME_STAMP("create_body end.", 1);
5979 else /* protect 8bit in multipart */
5983 if((*b
)->type
== TYPETEXT
) {
5984 /*-- Current type is text, but there are attachments to add --*/
5985 /*-- Upgrade to a TYPEMULTIPART --*/
5986 tmp_body
= (BODY
*)mail_newbody();
5987 tmp_body
->type
= TYPEMULTIPART
;
5988 tmp_body
->nested
.part
= mail_newbody_part();
5991 * Why do we do this?
5992 * The problem is that base64 or quoted-printable encoding is
5993 * sensitive to having random data appended to it's end. If
5994 * we use a single part TEXT message and something in between
5995 * us and the end appends advertising without adjusting for
5996 * the encoding, the message is screwed up. So we wrap the
5997 * text part inside a multipart and then the appended data
5998 * will come after the boundary.
6000 * We wish we could do this on the way out the door in a
6001 * child of post_rfc822_output because at that point we know
6002 * the character set and the encoding being used. For example,
6003 * iso-2022-jp is an encoding that is not sensitive to data
6004 * appended to the end, so it wouldn't need to be wrapped.
6005 * We could conceivably have post_rfc822_body inspect the
6006 * body and change it before doing the output. It would work
6007 * but would be very fragile. We'd be passed a body from
6008 * c-client to output and instead of just doing the output
6009 * we'd change the body and then output it. Not worth it
6010 * since the multipart wrapping is completely correct for
6011 * MIME-aware mailers.
6013 (void) copy_body(&(tmp_body
->nested
.part
->body
), *b
);
6014 /* move contents which were NOT copied */
6015 tmp_body
->nested
.part
->body
.contents
.text
.data
= (*b
)->contents
.text
.data
;
6016 (*b
)->contents
.text
.data
= NULL
;
6019 tmp_body
->nested
.part
->body
= **b
;
6021 (*b
)->subtype
= (*b
)->id
= (*b
)->description
= NULL
;
6022 (*b
)->parameter
= NULL
;
6023 (*b
)->contents
.text
.data
= NULL
;
6031 /*-- Now type must be MULTIPART with first part text --*/
6032 (*b
)->nested
.part
->body
.encoding
= ENCOTHER
;
6033 create_message_body_text(&((*b
)->nested
.part
->body
), flow_it
);
6036 /*------ Go through the parts list remove those to be deleted -----*/
6037 for(pp
= &(*b
)->nested
.part
->next
; *pp
;){
6038 for(pa
= attach
; pa
&& (*pp
)->body
.id
; pa
= pa
->next
)
6039 /* already existed? */
6040 if(pa
->id
&& strcmp(pa
->id
, (*pp
)->body
.id
) == 0){
6041 char *orig_descp
= NULL
, *cs
= NULL
;
6044 * decode original to see if it matches what was decoded
6045 * when we sent it in.
6048 if((*pp
)->body
.description
)
6049 orig_descp
= (char *) rfc1522_decode_to_utf8((unsigned char *) tmp_20k_buf
,
6050 SIZEOF_20KBUF
, (*pp
)->body
.description
);
6052 if(!(*pp
)->body
.description
/* update description? */
6053 || (pa
->description
&& strcmp(pa
->description
, orig_descp
))){
6054 if((*pp
)->body
.description
)
6055 fs_give((void **) &(*pp
)->body
.description
);
6057 /* encoding happens as msg text is written */
6058 (*pp
)->body
.description
= cpystr(pa
->description
);
6062 fs_give((void **) &cs
);
6068 p
= *pp
; /* prepare to zap *pp */
6069 *pp
= p
->next
; /* pull next one in list up */
6070 p
->next
= NULL
; /* tie off removed node */
6072 pine_free_body_data(&p
->body
); /* clean up contained data */
6073 mail_free_body_part(&p
); /* free up the part */
6079 /*---------- Now add any new attachments ---------*/
6080 for(p
= (*b
)->nested
.part
; p
->next
!= NULL
; p
= p
->next
);
6081 for(pa
= attach
; pa
!= NULL
; pa
= pa
->next
) {
6083 continue; /* Has an ID, it's old */
6086 * the idea is handle ALL attachments as open FILE *'s. Actual
6087 * encoding and such is handled at the time the message
6088 * is shoved into the mail slot or written to disk...
6090 * Also, we never unlink a file, so it's up to whoever opens
6091 * it to deal with tmpfile issues.
6093 if((file_contents
= (void *)so_get(FileStar
, pa
->filename
,
6094 READ_ACCESS
)) == NULL
){
6095 q_status_message2(SM_ORDER
| SM_DING
, 3, 4,
6096 _("Error \"%s\", couldn't attach file \"%s\""),
6097 error_description(errno
), pa
->filename
);
6098 display_message('x');
6102 p
->next
= mail_newbody_part();
6104 p
->body
.id
= generate_message_id();
6105 p
->body
.contents
.text
.data
= file_contents
;
6108 * Set type to unknown and let set_mime_type_by_* figure it out.
6109 * Always encode attachments we add as BINARY.
6111 p
->body
.type
= TYPEOTHER
;
6112 p
->body
.encoding
= ENCBINARY
;
6113 p
->body
.size
.bytes
= name_file_size(pa
->filename
);
6114 if(!set_mime_type_by_extension(&p
->body
, pa
->filename
)){
6115 set_mime_type_by_grope(&p
->body
);
6116 set_charset_possibly_to_ascii(&p
->body
, ps_global
->keyboard_charmap
);
6119 so_release((STORE_S
*)p
->body
.contents
.text
.data
);
6121 if(pa
->description
) /* encoding happens when msg written */
6122 p
->body
.description
= cpystr(pa
->description
);
6124 /* Add name attribute for backward compatibility */
6125 for(parmp
= &p
->body
.parameter
; *parmp
; )
6126 if(!struncmp((*parmp
)->attribute
, "name", 4)
6127 && (!*((*parmp
)->attribute
+ 4)
6128 || *((*parmp
)->attribute
+ 4) == '*')){
6129 PARAMETER
*free_me
= *parmp
;
6130 *parmp
= (*parmp
)->next
;
6131 free_me
->next
= NULL
;
6132 mail_free_body_parameter(&free_me
);
6135 parmp
= &(*parmp
)->next
;
6137 set_parameter(parmp
, "name",
6139 ? ((lc
= last_cmpnt(pa
->filename
)) ? lc
: pa
->filename
)
6142 /* Then set the Content-Disposition ala RFC1806 */
6143 if(!p
->body
.disposition
.type
){
6144 p
->body
.disposition
.type
= cpystr("attachment");
6145 for(parmp
= &p
->body
.disposition
.parameter
; *parmp
; )
6146 if(!struncmp((*parmp
)->attribute
, "filename", 4)
6147 && (!*((*parmp
)->attribute
+ 4)
6148 || *((*parmp
)->attribute
+ 4) == '*')){
6149 PARAMETER
*free_me
= *parmp
;
6150 *parmp
= (*parmp
)->next
;
6151 free_me
->next
= NULL
;
6152 mail_free_body_parameter(&free_me
);
6155 parmp
= &(*parmp
)->next
;
6157 set_parameter(parmp
, "filename",
6159 ? ((lc
= last_cmpnt(pa
->filename
)) ? lc
: pa
->filename
)
6164 pa
->id
= cpystr(p
->body
.id
);
6168 * Now, if this multipart has but one text piece (that is, no
6169 * attachments), then downgrade from a composite type to a discrete
6170 * text/plain message if CTE is not 8bit.
6172 if(!(*b
)->nested
.part
->next
6173 && (*b
)->nested
.part
->body
.type
== TYPETEXT
6174 && (F_ON(F_COMPOSE_ALWAYS_DOWNGRADE
, ps_global
)
6175 || !((*b
)->nested
.part
->body
.encoding
== ENC8BIT
6176 || (*b
)->nested
.part
->body
.encoding
== ENCBINARY
))){
6177 /* Clone the interesting body part */
6178 tmp_body
= mail_newbody();
6179 *tmp_body
= (*b
)->nested
.part
->body
;
6180 /* and rub out what we don't want cleaned up when it's free'd */
6181 mail_initbody(&(*b
)->nested
.part
->body
);
6187 TIME_STAMP("create_body end.", 1);
6192 * Fill in text BODY part's structure
6196 create_message_body_text(struct mail_bodystruct
*b
, int flow_it
)
6198 set_mime_type_by_grope(b
);
6199 if(F_OFF(F_QUELL_FLOWED_TEXT
, ps_global
)
6200 && F_OFF(F_STRIP_WS_BEFORE_SEND
, ps_global
)
6202 set_parameter(b
? &b
->parameter
: NULL
, "format", "flowed");
6209 * free_attachment_list - free attachments in given list
6212 free_attachment_list(PATMT
**alist
)
6216 while(alist
&& *alist
){ /* pointer pointing to something */
6217 leading
= (*alist
)->next
;
6218 if((*alist
)->description
)
6219 fs_give((void **)&(*alist
)->description
);
6221 if((*alist
)->filename
){
6222 if((*alist
)->flags
& A_TMP
)
6223 if(our_unlink((*alist
)->filename
) < 0)
6224 dprint((1, "-- Can't unlink(%s): %s\n",
6225 (*alist
)->filename
? (*alist
)->filename
: "?",
6226 error_description(errno
)));
6228 fs_give((void **)&(*alist
)->filename
);
6232 fs_give((void **)&(*alist
)->size
);
6235 fs_give((void **)&(*alist
)->id
);
6237 fs_give((void **)alist
);
6245 set_body_size(struct mail_bodystruct
*b
)
6250 we_cancel
= busy_cue(NULL
, NULL
, 1);
6251 so_seek((STORE_S
*)b
->contents
.text
.data
, 0L, 0);
6253 while(so_readc(&c
, (STORE_S
*)b
->contents
.text
.data
))
6257 cancel_busy_cue(-1);
6262 * view_as_rich - set the rich_header flag
6264 * name - name of the header field
6265 * deflt - default value to return if user didn't set it
6267 * Note: if the user tries to turn them all off with "", then
6268 * we take that to mean default, since otherwise there is no
6269 * way to get to the headers.
6272 view_as_rich(char *name
, int deflt
)
6277 p
= ps_global
->VAR_COMP_HDRS
;
6280 for(; (q
= *p
) != NULL
; p
++){
6281 if(!struncmp(q
, name
, strlen(name
)))
6282 return 0; /* 0 means we *do* view it by default */
6285 return 1; /* 1 means it starts out hidden */
6292 * background_posting - return whether or not we're already in the process
6296 background_posting(int gripe
)
6298 if(ps_global
->post
){
6300 q_status_message(SM_ORDER
|SM_DING
, 3, 3,
6301 _("Can't post while posting!"));
6309 /*----------------------------------------------------------------------
6310 Validate the given subject relative to any news groups.
6314 Returns: always returns 1, but also returns error if
6317 valid_subject(char *given
, char **expanded
, char **error
, BUILDER_ARG
*fcc
, int *mangled
)
6319 struct headerentry
*hp
;
6322 *expanded
= cpystr(given
);
6326 * Now look for any header entry we passed to pico that has to do
6327 * with news. If there's no subject, gripe.
6329 for(hp
= pbf
->headents
; hp
->prompt
; hp
++)
6330 if(hp
->help
== h_composer_news
){
6331 if(hp
->hd_text
->text
[0] && !*given
)
6333 _("News postings MUST have a subject! Please add one!"));
6344 * This is the build_address used by the composer to check for an address
6347 * Args: to -- the passed in line to parse
6348 * full_to -- Address of a pointer to return the full address in.
6349 * This will be allocated here and freed by the caller.
6350 * error -- Address of a pointer to return an error message in.
6351 * This will be allocated here and freed by the caller.
6352 * barg -- Address of a pointer to return the fcc in is in
6353 * fcc->tptr. It will have already been allocated by the
6354 * caller but we may free it and reallocate if we wish.
6355 * Caller will free it.
6357 * Result: 0 is returned if address was OK,
6358 * -1 if address wasn't OK.
6360 * Side effect: Can flush addrbook entry cache entries so they need to be
6361 * re-fetched afterwords.
6364 build_address(char *to
, char **full_to
, char **error
, BUILDER_ARG
*barg
, int *mangled
)
6367 int ret_val
, no_repo
= 0, *save_nesting_level
;
6369 PrivateTop
*pt
= NULL
;
6370 PrivateAffector
*af
= NULL
;
6371 char *fcc_local
= NULL
;
6372 jmp_buf save_jmp_buf
;
6374 dprint((5, "- build_address - (%s)\n", to
? to
: "nul"));
6376 /* check to see if to string is empty to avoid work */
6377 for(p
= to
; p
&& *p
&& isspace((unsigned char)*p
); p
++)
6382 *full_to
= cpystr(to
? to
: ""); /* because pico does a strcmp() */
6388 *full_to
= (char *)NULL
;
6391 *error
= (char *)NULL
;
6393 /* No guarantee cursor or status line is how we saved it */
6395 mark_status_unknown();
6397 if(ps_global
->remote_abook_validity
> 0 &&
6398 adrbk_check_and_fix_all(ab_nesting_level
== 0, 0, 0) && mangled
)
6399 *mangled
|= BUILDER_SCREEN_MANGLED
;
6402 * If we end up jumping back here because somebody else changed one of
6403 * our addrbooks out from underneath us, we may well leak some memory.
6404 * That's probably ok since this will be very rare.
6406 * The reason for the memcpy of the jmp_buf is that we may actually
6407 * be indirectly calling this function from within the address book.
6408 * For example, we may be in the address book screen and then run
6409 * the ComposeTo command which puts us in the composer, then we call
6410 * build_address from there which resets addrbook_changed_unexpectedly.
6411 * Once we leave build_address we need to reset addrbook_changed_un...
6412 * because this position on the stack will no longer be valid.
6413 * Same is true of the other setjmp's in this file which are wrapped
6416 save_nesting_level
= cpyint(ab_nesting_level
);
6417 memcpy(save_jmp_buf
, addrbook_changed_unexpectedly
, sizeof(jmp_buf));
6418 if(setjmp(addrbook_changed_unexpectedly
)){
6424 *error
= (char *)NULL
;
6426 if(full_to
&& *full_to
)
6427 fs_give((void **)full_to
);
6429 q_status_message(SM_ORDER
, 3, 5, "Resetting address book...");
6431 "RESETTING address book... build_address(%s)!\n", to
? to
: "?"));
6433 ab_nesting_level
= *save_nesting_level
;
6439 ret_val
= build_address_internal(bldto
, full_to
, error
,
6440 barg
? &fcc_local
: NULL
,
6441 &no_repo
, NULL
, save_and_restore
,
6444 if(save_nesting_level
)
6445 fs_give((void **)&save_nesting_level
);
6448 * Have to rfc1522_decode the full_to string before sending it back.
6450 if(full_to
&& *full_to
){
6454 len
= 4*strlen(*full_to
)+1;
6455 q
= (char *)fs_get(len
* sizeof(char));
6456 p
= (char *)rfc1522_decode_to_utf8((unsigned char *)q
, len
, *full_to
);
6458 /* p == q means that decoding happened, p is decoded *full_to */
6460 fs_give((void **)full_to
);
6464 fs_give((void **)&q
);
6470 /* Pt will point to headents[Fcc].bldr_private */
6472 if(barg
&& barg
->aff
)
6473 pt
= (PrivateTop
*)(*barg
->aff
);
6476 * If *barg->aff is set, that means fcc was set from a list
6477 * during some previous builder call.
6478 * If the current To line contains the old expansion as a prefix, then
6479 * we should leave things as they are. In order to decide that,
6480 * we look at a hash value computed from the strings.
6482 if(pt
&& (af
=pt
->affector
) && af
->who
== BP_To
){
6486 if(len
>= af
->cksumlen
){
6489 save
= to
[af
->cksumlen
];
6490 to
[af
->cksumlen
] = '\0';
6491 csum
= line_hash(to
);
6492 to
[af
->cksumlen
] = save
;
6495 csum
= af
->cksumval
+ 1; /* something not equal to cksumval */
6500 (pt
->affector
->who
== BP_To
&& csum
!= pt
->affector
->cksumval
)){
6502 /* replace fcc value */
6504 fs_give((void **)&barg
->tptr
);
6506 barg
->tptr
= fcc_local
;
6510 *barg
->aff
= (void *)fs_get(sizeof(PrivateTop
));
6511 pt
= (PrivateTop
*)(*barg
->aff
);
6512 memset((void *)pt
, 0, sizeof(PrivateTop
));
6518 (PrivateAffector
*)fs_get(sizeof(PrivateAffector
));
6522 af
->cksumlen
= strlen(((full_to
&& *full_to
)
6524 af
->cksumval
= line_hash(((full_to
&& *full_to
)
6529 * If result is reproducible, we don't keep track here.
6532 fs_give((void **)&pt
->affector
);
6537 fs_give((void **)&fcc_local
); /* unused in this case */
6540 /* This is so pico will erase the old message */
6541 if(error
!= NULL
&& *error
== NULL
)
6542 *error
= cpystr("");
6544 memcpy(addrbook_changed_unexpectedly
, save_jmp_buf
, sizeof(jmp_buf));
6545 flush_status_messages(1);
6551 * This is the builder used by the composer for the Lcc line.
6553 * Args: lcc -- the passed in Lcc line to parse
6554 * full_lcc -- Address of a pointer to return the full address in.
6555 * This will be allocated here and freed by the caller.
6556 * error -- Address of a pointer to return an error message in.
6557 * This is not allocated so should not be freed by the caller.
6558 * barg -- This is a pointer to text for affected entries which
6559 * we may be changing. The first one in the list is the
6560 * To entry. We may put the name of the list in empty
6561 * group syntax form there (like List Name: ;).
6562 * The second one in the list is the fcc field.
6563 * The tptr members already point to text allocated in the
6564 * caller. We may free and reallocate here, caller will
6565 * free the result in any case.
6567 * Result: 0 is returned if address was OK,
6568 * -1 if address wasn't OK.
6570 * Side effect: Can flush addrbook entry cache entries so they need to be
6571 * re-fetched afterwords.
6574 build_addr_lcc(char *lcc
, char **full_lcc
, char **error
, BUILDER_ARG
*barg
, int *mangled
)
6577 no_repo
= 0; /* fcc or lcc not reproducible */
6578 int *save_nesting_level
;
6580 PrivateTop
*pt
= NULL
;
6581 PrivateAffector
*af
= NULL
;
6586 jmp_buf save_jmp_buf
;
6588 dprint((5, "- build_addr_lcc - (%s)\n", lcc
? lcc
: "nul"));
6590 /* check to see if to string is empty to avoid work */
6591 for(p
= lcc
; p
&& *p
&& isspace((unsigned char)*p
); p
++)
6596 *full_lcc
= cpystr(lcc
? lcc
: ""); /* because pico does a strcmp() */
6602 *error
= (char *)NULL
;
6604 if(ps_global
->remote_abook_validity
> 0 &&
6605 adrbk_check_and_fix_all(ab_nesting_level
== 0, 0, 0) && mangled
)
6606 *mangled
|= BUILDER_SCREEN_MANGLED
;
6609 * If we end up jumping back here because somebody else changed one of
6610 * our addrbooks out from underneath us, we may well leak some memory.
6611 * That's probably ok since this will be very rare.
6613 save_nesting_level
= cpyint(ab_nesting_level
);
6614 memcpy(save_jmp_buf
, addrbook_changed_unexpectedly
, sizeof(jmp_buf));
6615 if(setjmp(addrbook_changed_unexpectedly
)){
6622 *error
= (char *)NULL
;
6624 if(full_lcc
&& *full_lcc
)
6625 fs_give((void **)full_lcc
);
6627 q_status_message(SM_ORDER
, 3, 5, "Resetting address book...");
6629 "RESETTING address book... build_address(%s)!\n", lcc
? lcc
: "?"));
6631 ab_nesting_level
= *save_nesting_level
;
6636 bldlcc
.arg
.str
= lcc
;
6639 * To is first affected_entry and Fcc is second.
6640 * The conditional stuff for the fcc argument says to only change the
6641 * fcc if the fcc pointer is passed in non-null, and the To pointer
6642 * is also non-null. If they are null, that means they've already been
6643 * entered (are sticky). We don't affect fcc if either fcc or To has
6646 ret_val
= build_address_internal(bldlcc
,
6649 (barg
&& barg
->next
&& barg
->next
->tptr
&& barg
->tptr
)
6650 ? &fcc_local
: NULL
,
6652 (barg
&& barg
->tptr
) ? &to
: NULL
,
6653 save_and_restore
, 0, mangled
);
6656 if(save_nesting_level
)
6657 fs_give((void **)&save_nesting_level
);
6659 /* full_lcc is what ends up in the Lcc: line */
6660 if(full_lcc
&& *full_lcc
){
6664 * Have to rfc1522_decode the full_lcc string before sending it back.
6666 len
= 4*strlen(*full_lcc
)+1;
6667 p
= (char *)fs_get(len
* sizeof(char));
6668 if(rfc1522_decode_to_utf8((unsigned char *)p
, len
, *full_lcc
) == (unsigned char *)p
){
6669 fs_give((void **)full_lcc
);
6673 fs_give((void **)&p
);
6676 /* to is what ends up in the To: line */
6682 * Have to rfc1522_decode the full_to string before sending it back.
6684 len
= 4*strlen(to
)+1;
6685 p
= (char *)fs_get(len
* sizeof(char));
6687 if(rfc1522_decode_to_utf8((unsigned char *)p
, len
, to
) == (unsigned char *)p
){
6689 * If the caller wants us to try to preserve the charset
6690 * information (they set aff) we copy it into encoded->etext.
6691 * We don't have to worry about pasting together pieces of
6692 * etext like we do in build_address because whenever the
6693 * Lcc line is setting the To line it will be setting the
6694 * whole line, not modifying it.
6695 * Pt will point to headents[To].bldr_private.
6697 if(barg
&& barg
->aff
){
6698 pt
= (PrivateTop
*)(*barg
->aff
);
6701 *barg
->aff
= (void *)fs_get(sizeof(PrivateTop
));
6702 pt
= (PrivateTop
*)(*barg
->aff
);
6703 memset((void *)pt
, 0, sizeof(PrivateTop
));
6707 fs_give((void **)&to
);
6711 fs_give((void **)&p
);
6714 fs_give((void **)&dummy
);
6718 * This part is recording the fact that the To line was set to
6719 * what it is by entering something on the Lcc line. In particular,
6720 * if a list alias was entered here then the fullname of the list
6721 * goes in the To line. We save this affector information so that
6722 * we can tell it shouldn't be modified if we call build_addr_lcc
6723 * again unless we actually modified what's in the Lcc line so that
6724 * it doesn't start with the same thing. The problem we're solving
6725 * is that the contents of the Lcc line no longer look like the
6726 * list they were derived from.
6727 * Pt will point to headents[To].bldr_private.
6729 if(barg
&& barg
->aff
)
6730 pt
= (PrivateTop
*)(*barg
->aff
);
6732 if(pt
&& (af
=pt
->affector
) && af
->who
== BP_Lcc
){
6736 if(len
>= af
->cksumlen
){
6739 save
= lcc
[af
->cksumlen
];
6740 lcc
[af
->cksumlen
] = '\0';
6741 csum
= line_hash(lcc
);
6742 lcc
[af
->cksumlen
] = save
;
6745 csum
= af
->cksumval
+ 1; /* so they aren't equal */
6750 pt
->affector
->who
!= BP_Lcc
||
6751 (pt
->affector
->who
== BP_Lcc
&& csum
!= pt
->affector
->cksumval
)){
6753 /* replace to value */
6754 if(barg
->tptr
&& barg
->tptr
[0]){
6758 l
= strlen(barg
->tptr
) + strlen(to
? to
: "") + 2;
6759 t
= (char *)fs_get((l
+1) * sizeof(char));
6760 snprintf(t
, l
+1, "%s%s%s",
6762 (to
&& *to
) ? ", " : "",
6763 (to
&& *to
) ? to
: "");
6764 fs_give((void **)&barg
->tptr
);
6766 fs_give((void **)&to
);
6772 fs_give((void **)&barg
->tptr
);
6779 *barg
->aff
= (void *)fs_get(sizeof(PrivateTop
));
6780 pt
= (PrivateTop
*)(*barg
->aff
);
6781 memset((void *)pt
, 0, sizeof(PrivateTop
));
6787 (PrivateAffector
*)fs_get(sizeof(PrivateAffector
));
6791 af
->cksumlen
= strlen(((full_lcc
&& *full_lcc
)
6793 af
->cksumval
= line_hash(((full_lcc
&& *full_lcc
)
6798 * If result is reproducible, we don't keep track here.
6801 fs_give((void **)&pt
->affector
);
6806 fs_give((void **)&to
); /* unused in this case */
6813 * If *barg->next->aff is set, that means fcc was set from a list
6814 * during some previous builder call. If the current Lcc line
6815 * contains the old expansion as a prefix, then we should leave
6816 * things as they are. In order to decide that we look at a hash
6817 * value computed from the strings.
6818 * Pt will point to headents[Fcc].bldr_private
6821 if(barg
&& barg
->next
&& barg
->next
->aff
)
6822 pt
= (PrivateTop
*)(*barg
->next
->aff
);
6824 if(pt
&& (af
=pt
->affector
) && af
->who
== BP_Lcc
){
6828 if(len
>= af
->cksumlen
){
6831 save
= lcc
[af
->cksumlen
];
6832 lcc
[af
->cksumlen
] = '\0';
6833 csum
= line_hash(lcc
);
6834 lcc
[af
->cksumlen
] = save
;
6837 csum
= af
->cksumval
+ 1; /* something not equal to cksumval */
6842 pt
->affector
->who
!= BP_Lcc
||
6843 (pt
->affector
->who
== BP_Lcc
&& csum
!= pt
->affector
->cksumval
)){
6845 /* replace fcc value */
6846 if(barg
->next
->tptr
)
6847 fs_give((void **)&barg
->next
->tptr
);
6849 barg
->next
->tptr
= fcc_local
;
6851 if(barg
->next
->aff
){
6853 *barg
->next
->aff
= (void *)fs_get(sizeof(PrivateTop
));
6854 pt
= (PrivateTop
*)(*barg
->next
->aff
);
6855 memset((void *)pt
, 0, sizeof(PrivateTop
));
6861 (PrivateAffector
*)fs_get(sizeof(PrivateAffector
));
6865 af
->cksumlen
= strlen(((full_lcc
&& *full_lcc
)
6867 af
->cksumval
= line_hash(((full_lcc
&& *full_lcc
)
6872 * If result is reproducible, we don't keep track here.
6875 fs_give((void **)&pt
->affector
);
6880 fs_give((void **)&fcc_local
); /* unused in this case */
6884 if(error
!= NULL
&& *error
== NULL
)
6885 *error
= cpystr("");
6887 memcpy(addrbook_changed_unexpectedly
, save_jmp_buf
, sizeof(jmp_buf));
6888 flush_status_messages(0);
6893 /*----------------------------------------------------------------------
6894 Verify and canonicalize news groups names.
6895 Called from the message composer
6897 Args: given_group -- List of groups typed by user
6898 expanded_group -- pointer to point to expanded list, which will be
6899 allocated here and freed in caller. If this is
6900 NULL, don't attempt to validate.
6901 error -- pointer to store error message
6902 fcc -- pointer to point to fcc, which will be
6903 allocated here and freed in caller
6905 Returns: 0 if all is OK
6906 -1 if addresses weren't valid
6908 Test the given list of newstroups against those recognized by our nntp
6909 servers. Testing by actually trying to open the list is much cheaper, both
6910 in bandwidth and memory, than yanking the whole list across the wire.
6913 news_build(char *given_group
, char **expanded_group
, char **error
, BUILDER_ARG
*fcc
, int *mangled
)
6916 char *fccptr
= NULL
;
6918 if(fcc
&& fcc
->tptr
)
6919 fccptr
= cpystr(fcc
->tptr
);
6923 rv
= news_grouper(given_group
, expanded_group
, error
, &fccptr
, news_build_busy
);
6925 /* assign any new fcc to the BUILDER_ARG */
6929 if(fcc
->tptr
&& strcmp(fcc
->tptr
, fccptr
)){
6930 fs_give((void **) &fcc
->tptr
);
6937 fs_give((void **) &fccptr
);
6940 /* deal with any busy indicator */
6944 mark_status_dirty();
6945 display_message('x');
6947 *mangled
|= BUILDER_MESSAGE_DISPLAYED
;
6956 news_build_busy(void)
6958 news_busy_cue
= busy_cue("Validating newsgroup(s)", NULL
, 0);
6962 #if defined(DOS) || defined(OS2)
6964 /*----------------------------------------------------------------------
6965 Verify that the necessary pieces are around to allow for
6966 message sending under DOS
6968 Args: strict -- tells us if a remote stream is required before
6969 sending is permitted.
6971 The idea is to make sure pine knows enough to put together a valid
6972 from line. The things we MUST know are a user-id, user-domain and
6973 smtp server to dump the message off on. Typically these are
6974 provided in pine's configuration file, but if not, the user is
6980 char prompt
[100], answer
[80];
6985 * query for user name portion of address, use IMAP login
6988 if(!ps_global
->VAR_USER_ID
|| ps_global
->VAR_USER_ID
[0] == '\0'){
6990 int no_prompt_user_id
= 0;
6992 if(ps_global
->mail_stream
&& ps_global
->mail_stream
->mailbox
6993 && mail_valid_net_parse(ps_global
->mail_stream
->mailbox
, &mb
)
6995 strncpy(answer
, mb
.user
, sizeof(answer
)-1);
6996 answer
[sizeof(answer
)-1] = '\0';
6998 else if(F_ON(F_QUELL_USER_ID_PROMPT
, ps_global
)){
6999 /* no user-id prompting if set */
7000 no_prompt_user_id
= 1;
7002 if(!ps_global
->mail_stream
)
7003 do_broach_folder(ps_global
->inbox_name
,
7004 ps_global
->context_list
, NULL
, DB_INBOXWOCNTXT
);
7005 if(ps_global
->mail_stream
&& ps_global
->mail_stream
->mailbox
7006 && mail_valid_net_parse(ps_global
->mail_stream
->mailbox
, &mb
)
7008 strncpy(answer
, mb
.user
, sizeof(answer
)-1);
7009 answer
[sizeof(answer
)-1] = '\0';
7017 if(F_ON(F_QUELL_USER_ID_PROMPT
, ps_global
) && answer
[0]){
7018 /* No prompt, just assume mailbox login is user-id */
7019 no_prompt_user_id
= 1;
7023 snprintf(prompt
,sizeof(prompt
),_("User-id for From address : "));
7024 prompt
[sizeof(prompt
)-1] = '\0';
7027 while(!no_prompt_user_id
) {
7028 flags
= OE_APPEND_CURRENT
;
7029 rc
= optionally_enter(answer
,-FOOTER_ROWS(ps_global
),0,
7030 sizeof(answer
),prompt
,NULL
,help
,&flags
);
7035 help
= (help
== NO_HELP
) ? h_sticky_user_id
: NO_HELP
;
7043 if(rc
== 1 || (rc
== 0 && !answer
[0])) {
7044 q_status_message(SM_ORDER
, 3, 4,
7045 _("Send cancelled (User-id must be provided before sending)"));
7050 snprintf(prompt
, sizeof(prompt
), _("Preserve %.*s as \"user-id\" in PINERC"),
7051 sizeof(prompt
)-50, answer
);
7052 prompt
[sizeof(prompt
)-1] = '\0';
7053 if(ps_global
->blank_user_id
7054 && !no_prompt_user_id
7055 && want_to(prompt
, 'y', 'n', NO_HELP
, WT_NORM
) == 'y'){
7056 set_variable(V_USER_ID
, answer
, 1, 1, Main
);
7059 fs_give((void **)&(ps_global
->VAR_USER_ID
));
7060 ps_global
->VAR_USER_ID
= cpystr(answer
);
7064 /* query for personal name */
7065 if(!ps_global
->VAR_PERSONAL_NAME
|| ps_global
->VAR_PERSONAL_NAME
[0]=='\0'
7066 && F_OFF(F_QUELL_PERSONAL_NAME_PROMPT
, ps_global
)){
7068 snprintf(prompt
, sizeof(prompt
), _("Personal name for From address : "));
7069 prompt
[sizeof(prompt
)-1] = '\0';
7073 flags
= OE_APPEND_CURRENT
;
7074 rc
= optionally_enter(answer
,-FOOTER_ROWS(ps_global
),0,
7075 sizeof(answer
),prompt
,NULL
,help
,&flags
);
7080 help
= (help
== NO_HELP
) ? h_sticky_personal_name
: NO_HELP
;
7088 if(rc
== 0 && answer
){ /* save the name */
7089 snprintf(prompt
, sizeof(prompt
), _("Preserve %.*s as \"personal-name\" in PINERC"),
7090 sizeof(prompt
)-50, answer
);
7091 prompt
[sizeof(prompt
)-1] = '\0';
7092 if(ps_global
->blank_personal_name
7093 && want_to(prompt
, 'y', 'n', NO_HELP
, WT_NORM
) == 'y'){
7094 set_variable(V_PERSONAL_NAME
, answer
, 1, 1, Main
);
7097 fs_give((void **)&(ps_global
->VAR_PERSONAL_NAME
));
7098 ps_global
->VAR_PERSONAL_NAME
= cpystr(answer
);
7104 * query for host/domain portion of address, using IMAP
7107 if(ps_global
->blank_user_domain
7108 || ps_global
->maildomain
== ps_global
->localdomain
7109 || ps_global
->maildomain
== ps_global
->hostname
){
7110 if(ps_global
->inbox_name
[0] == '{'){
7112 i
< sizeof(answer
)-1 && ps_global
->inbox_name
[i
+1] != '}'; i
++)
7113 answer
[i
] = ps_global
->inbox_name
[i
+1];
7120 snprintf(prompt
,sizeof(prompt
),_("Host/domain for From address : "));
7121 prompt
[sizeof(prompt
)-1] = '\0';
7125 flags
= OE_APPEND_CURRENT
;
7126 rc
= optionally_enter(answer
,-FOOTER_ROWS(ps_global
),0,
7127 sizeof(answer
),prompt
,NULL
,help
,&flags
);
7132 help
= (help
== NO_HELP
) ? h_sticky_domain
: NO_HELP
;
7140 if(rc
== 1 || (rc
== 0 && !answer
[0])) {
7141 q_status_message(SM_ORDER
, 3, 4,
7142 _("Send cancelled (Host/domain name must be provided before sending)"));
7147 snprintf(prompt
, sizeof(prompt
), _("Preserve %.*s as \"user-domain\" in PINERC"),
7148 sizeof(prompt
)-50, answer
);
7149 prompt
[sizeof(prompt
)-1] = '\0';
7150 if(!ps_global
->userdomain
&& !ps_global
->blank_user_domain
7151 && want_to(prompt
, 'y', 'n', NO_HELP
, WT_NORM
) == 'y'){
7152 set_variable(V_USER_DOMAIN
, answer
, 1, 1, Main
);
7153 fs_give((void **)&(ps_global
->maildomain
)); /* blast old val */
7154 ps_global
->userdomain
= cpystr(answer
);
7155 ps_global
->maildomain
= ps_global
->userdomain
;
7158 fs_give((void **)&(ps_global
->maildomain
));
7159 ps_global
->userdomain
= cpystr(answer
);
7160 ps_global
->maildomain
= ps_global
->userdomain
;
7164 /* check for smtp server */
7165 if(!ps_global
->VAR_SMTP_SERVER
||
7166 !ps_global
->VAR_SMTP_SERVER
[0] ||
7167 !ps_global
->VAR_SMTP_SERVER
[0][0]){
7170 if(ps_global
->inbox_name
[0] == '{'){
7172 i
< sizeof(answer
)-1 && ps_global
->inbox_name
[i
+1] != '}'; i
++)
7173 answer
[i
] = ps_global
->inbox_name
[i
+1];
7180 snprintf(prompt
,sizeof(prompt
),_("SMTP server to forward message : "));
7181 prompt
[sizeof(prompt
)-1] = '\0';
7185 flags
= OE_APPEND_CURRENT
;
7186 rc
= optionally_enter(answer
,-FOOTER_ROWS(ps_global
),0,
7187 sizeof(answer
),prompt
,NULL
,help
,&flags
);
7192 help
= (help
== NO_HELP
) ? h_sticky_smtp
: NO_HELP
;
7200 if(rc
== 1 || (rc
== 0 && answer
[0] == '\0')) {
7201 q_status_message(SM_ORDER
, 3, 4,
7202 _("Send cancelled (SMTP server must be provided before sending)"));
7207 list
= (char **) fs_get(2 * sizeof(char *));
7208 list
[0] = cpystr(answer
);
7210 set_variable_list(V_SMTP_SERVER
, list
, TRUE
, Main
);
7211 fs_give((void *)&list
[0]);
7212 fs_give((void *)list
);
7218 #endif /* defined(DOS) || defined(OS2) */