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-2016 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 "patches.freeiz.com"
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
; *(p
+1); p
++)
2176 pf
->type
= pf_template
[index
].type
;
2177 pf
->canedit
= pf_template
[index
].canedit
;
2178 pf
->rcptto
= pf_template
[index
].rcptto
;
2179 pf
->writehdr
= pf_template
[index
].writehdr
;
2180 pf
->localcopy
= pf_template
[index
].localcopy
;
2184 he
->rich_header
= view_as_rich(pf
->name
, he
->rich_header
);
2185 if(F_OFF(F_ENABLE_TAB_COMPLETE
,ps_global
))
2186 he
->nickcmpl
= NULL
;
2189 case FreeText
: /* realaddr points to c-client env */
2190 if(index
== N_NEWS
){
2191 sending_order
[1] = pf
;
2192 he
->realaddr
= &outgoing
->newsgroups
;
2195 switch(set_default_hdrval(pf
, custom
)){
2198 fs_give((void **)he
->realaddr
);
2200 *he
->realaddr
= pf
->textbuf
;
2206 if(*he
->realaddr
){ /* combine values */
2207 if(pf
->textbuf
&& *pf
->textbuf
){
2211 l
= strlen(*he
->realaddr
) + strlen(pf
->textbuf
) + 1;
2212 combined_hdr
= (char *) fs_get((l
+1) * sizeof(char));
2213 strncpy(combined_hdr
, *he
->realaddr
, l
);
2214 combined_hdr
[l
] = '\0';
2215 strncat(combined_hdr
, ",", l
+1-1-strlen(combined_hdr
));
2216 combined_hdr
[l
] = '\0';
2217 strncat(combined_hdr
, pf
->textbuf
, l
+1-1-strlen(combined_hdr
));
2218 combined_hdr
[l
] = '\0';
2220 fs_give((void **)he
->realaddr
);
2221 *he
->realaddr
= combined_hdr
;
2222 q_status_message(SM_ORDER
, 3, 3,
2223 "Adding newsgroup from role");
2228 *he
->realaddr
= pf
->textbuf
;
2235 /* if no value, use default */
2237 *he
->realaddr
= pf
->textbuf
;
2247 /* If there is a newsgroup, we'd better show it */
2248 if(outgoing
->newsgroups
&& *outgoing
->newsgroups
)
2249 he
->rich_header
= 0; /* force on by default */
2252 fs_give((void **)&pf
->textbuf
);
2254 pf
->text
= he
->realaddr
;
2256 else if(index
== N_DATE
){
2257 sending_order
[2] = pf
;
2258 pf
->text
= (char **) &outgoing
->date
;
2261 else if(index
== N_INREPLY
){
2262 sending_order
[NN
+9] = pf
;
2263 pf
->text
= &outgoing
->in_reply_to
;
2266 else if(index
== N_MSGID
){
2267 sending_order
[NN
+10] = pf
;
2268 pf
->text
= &outgoing
->message_id
;
2271 else if(index
== N_REF
){
2272 sending_order
[NN
+11] = pf
;
2273 pf
->text
= &outgoing
->references
;
2276 else if(index
== N_PRIORITY
){
2277 sending_order
[NN
+12] = pf
;
2278 pf
->text
= &pf
->textbuf
;
2281 else if(index
== N_USERAGENT
){
2282 sending_order
[NN
+13] = pf
;
2283 pf
->text
= &pf
->textbuf
;
2284 pf
->textbuf
= generate_user_agent();
2287 else if(index
== N_POSTERR
){
2288 sending_order
[NN
+14] = pf
;
2290 pf
->text
= &pf
->textbuf
;
2293 else if(index
== N_RPLUID
){
2294 sending_order
[NN
+15] = pf
;
2296 pf
->text
= &pf
->textbuf
;
2299 else if(index
== N_RPLMBOX
){
2300 sending_order
[NN
+16] = pf
;
2302 pf
->text
= &pf
->textbuf
;
2305 else if(index
== N_SMTP
){
2306 sending_order
[NN
+17] = pf
;
2307 pf_smtp_server
= pf
;
2308 pf
->text
= &pf
->textbuf
;
2311 else if(index
== N_NNTP
){
2312 sending_order
[NN
+18] = pf
;
2313 pf_nntp_server
= pf
;
2314 pf
->text
= &pf
->textbuf
;
2317 else if(index
== N_CURPOS
){
2318 sending_order
[NN
+19] = pf
;
2320 pf
->text
= &pf
->textbuf
;
2323 else if(index
== N_OURREPLYTO
){
2324 sending_order
[NN
+20] = pf
;
2326 pf
->text
= &pf
->textbuf
;
2329 else if(index
== N_OURHDRS
){
2330 sending_order
[NN
+21] = pf
;
2332 pf
->text
= &pf
->textbuf
;
2335 else if(index
== N_AUTHRCVD
){
2336 sending_order
[0] = pf
;
2338 pf
->text
= &pf
->textbuf
;
2342 q_status_message(SM_ORDER
| SM_DING
, 3, 7,
2343 "Botched: Unmatched FreeText header in pine_send");
2348 /* can't do a default for this one */
2350 /* If there is an attachment already, we'd better show them */
2351 if(body
&& *body
&& (*body
)->type
!= TYPETEXT
)
2352 he
->rich_header
= 0; /* force on by default */
2359 sending_order
[3] = pf
;
2360 pf
->addr
= &outgoing
->from
;
2361 if(role
&& role
->from
){
2362 if(ps_global
->never_allow_changing_from
)
2363 q_status_message(SM_ORDER
, 3, 3, _("Site policy doesn't allow changing From address so role's From has no effect"));
2365 outgoing
->from
= copyaddrlist(role
->from
);
2366 he
->display_it
= 1; /* show it */
2367 he
->rich_header
= 0;
2375 sending_order
[NN
+2] = pf
;
2376 pf
->addr
= &outgoing
->to
;
2377 /* If already set, make it act like we typed it in */
2379 && outgoing
->to
->mailbox
2380 && outgoing
->to
->mailbox
[0]
2381 && flags
& PS_STICKY_TO
)
2389 sending_order
[NN
+5] = pf
;
2391 if(ps_global
->VAR_EMPTY_HDR_MSG
2392 && !ps_global
->VAR_EMPTY_HDR_MSG
[0]){
2396 nobody_addr
= mail_newaddr();
2397 nobody_addr
->next
= mail_newaddr();
2398 nobody_addr
->mailbox
= cpystr(rfc1522_encode(tmp_20k_buf
,
2400 (unsigned char *)(ps_global
->VAR_EMPTY_HDR_MSG
2401 ? ps_global
->VAR_EMPTY_HDR_MSG
2402 : "undisclosed-recipients"),
2403 ps_global
->posting_charmap
));
2404 pf
->addr
= &nobody_addr
;
2410 sending_order
[NN
+3] = pf
;
2411 pf
->addr
= &outgoing
->cc
;
2415 sending_order
[NN
+4] = pf
;
2416 pf
->addr
= &outgoing
->bcc
;
2417 /* if bcc exists, make sure it's exposed so nothing's
2418 * sent by mistake...
2426 sending_order
[NN
+1] = pf
;
2427 pf
->addr
= &outgoing
->reply_to
;
2428 if(role
&& role
->replyto
){
2429 if(outgoing
->reply_to
)
2430 mail_free_address(&outgoing
->reply_to
);
2432 outgoing
->reply_to
= copyaddrlist(role
->replyto
);
2433 he
->display_it
= 1; /* show it */
2434 he
->rich_header
= 0;
2440 sending_order
[NN
+7] = pf
;
2441 pf
->addr
= &lcc_addr
;
2444 build_address(lcc_arg
, &addr
, NULL
, NULL
, NULL
);
2445 rfc822_parse_adrlist(&lcc_addr
, addr
,
2446 ps_global
->maildomain
);
2447 fs_give((void **)&addr
);
2453 #if !(defined(DOS) || defined(OS2)) || defined(NOAUTH)
2455 sending_order
[4] = pf
;
2456 pf
->addr
= &outgoing
->sender
;
2461 q_status_message1(SM_ORDER
,3,7,
2462 "Internal error: Address header %s", comatose(index
));
2467 * If this is a reply to news, don't show the regular email
2468 * recipient headers (unless they are non-empty).
2470 if((outgoing
->newsgroups
&& *outgoing
->newsgroups
)
2471 && (index
== N_TO
|| index
== N_CC
2472 || index
== N_BCC
|| index
== N_LCC
)
2473 && (pf
->addr
&& !*pf
->addr
)){
2474 if((ct
=set_default_hdrval(pf
, custom
)) >= UseAsDef
&&
2475 pf
->textbuf
&& *pf
->textbuf
){
2476 removing_trailing_white_space(pf
->textbuf
);
2477 (void)removing_double_quotes(pf
->textbuf
);
2478 build_address(pf
->textbuf
, &addr
, NULL
, NULL
, NULL
);
2479 rfc822_parse_adrlist(pf
->addr
, addr
,
2480 ps_global
->maildomain
);
2481 fs_give((void **)&addr
);
2486 he
->rich_header
= 1; /* hide */
2490 * If this address doesn't already have a value, then we check
2491 * for a default value assigned by the user.
2493 else if(pf
->addr
&& !*pf
->addr
){
2494 if((ct
=set_default_hdrval(pf
, custom
)) >= UseAsDef
&&
2496 (!ps_global
->never_allow_changing_from
&&
2497 F_ON(F_ALLOW_CHANGING_FROM
, ps_global
))) &&
2498 pf
->textbuf
&& *pf
->textbuf
){
2500 removing_trailing_white_space(pf
->textbuf
);
2501 (void)removing_double_quotes(pf
->textbuf
);
2504 * Try to set To based on Lcc. Don't attempt Fcc.
2506 if(index
== N_LCC
&& !he_to
->sticky
&& pf_to
&& pf_to
->addr
){
2507 BUILDER_ARG
*barg
= NULL
;
2511 ppp
= addr_list_string(*pf_to
->addr
, NULL
, 1);
2516 barg
= (BUILDER_ARG
*) fs_get(sizeof(*barg
));
2517 memset(barg
, 0, sizeof(*barg
));
2518 barg
->me
= &(he
->bldr_private
);
2519 barg
->aff
= &(he_to
->bldr_private
);
2520 barg
->tptr
= cpystr(ppp
);
2522 build_addr_lcc(pf
->textbuf
, &addr
, NULL
, barg
, NULL
);
2525 rfc822_parse_adrlist(pf
->addr
, addr
,
2526 ps_global
->maildomain
);
2528 fs_give((void **) &addr
);
2533 if(barg
&& barg
->tptr
&& strcmp(ppp
, barg
->tptr
)){
2536 rfc822_parse_adrlist(&a
, barg
->tptr
,
2537 ps_global
->maildomain
);
2540 mail_free_address(pf_to
->addr
);
2548 fs_give((void **) &barg
->tptr
);
2550 fs_give((void **) &barg
);
2554 fs_give((void **) &ppp
);
2557 build_address(pf
->textbuf
, &addr
, NULL
, NULL
, NULL
);
2558 rfc822_parse_adrlist(pf
->addr
, addr
,
2559 ps_global
->maildomain
);
2561 fs_give((void **) &addr
);
2568 /* if we still don't have a from */
2569 if(index
== N_FROM
&& !*pf
->addr
)
2570 *pf
->addr
= generate_from();
2574 * Addr is already set in the rest of the cases.
2576 else if((index
== N_FROM
|| index
== N_REPLYTO
) && pf
->addr
){
2577 ADDRESS
*adr
= NULL
;
2580 * We get to this case of the ifelse if the from or reply-to
2581 * addr was set by a role above.
2584 /* figure out the default value */
2585 (void)set_default_hdrval(pf
, custom
);
2586 if(pf
->textbuf
&& *pf
->textbuf
){
2587 removing_trailing_white_space(pf
->textbuf
);
2588 (void)removing_double_quotes(pf
->textbuf
);
2589 build_address(pf
->textbuf
, &addr
, NULL
, NULL
, NULL
);
2590 rfc822_parse_adrlist(&adr
, addr
,
2591 ps_global
->maildomain
);
2592 fs_give((void **)&addr
);
2595 /* if value set by role is different from default, show it */
2596 if(adr
&& !address_is_same(*pf
->addr
, adr
))
2597 he
->display_it
= 1; /* start this off showing */
2600 if(!(*pf
->addr
)->mailbox
){
2601 fs_give((void **)pf
->addr
);
2606 mail_free_address(&adr
);
2608 else if((index
== N_TO
|| index
== N_CC
|| index
== N_BCC
)
2610 ADDRESS
*a
= NULL
, **tail
;
2613 * These three are different from the others because we
2614 * might add the addresses to what is already there instead
2618 switch(set_default_hdrval(pf
, custom
)){
2621 mail_free_address(pf
->addr
);
2623 removing_trailing_white_space(pf
->textbuf
);
2624 (void)removing_double_quotes(pf
->textbuf
);
2625 build_address(pf
->textbuf
, &addr
, NULL
, NULL
, NULL
);
2626 rfc822_parse_adrlist(pf
->addr
, addr
, ps_global
->maildomain
);
2627 fs_give((void **)&addr
);
2632 removing_trailing_white_space(pf
->textbuf
);
2633 (void)removing_double_quotes(pf
->textbuf
);
2634 build_address(pf
->textbuf
, &addr
, NULL
, NULL
, NULL
);
2635 rfc822_parse_adrlist(&a
, addr
, ps_global
->maildomain
);
2636 fs_give((void **)&addr
);
2639 for(tail
= pf
->addr
; *tail
; tail
= &(*tail
)->next
)
2641 *tail
= reply_cp_addr(ps_global
, 0, NULL
, NULL
,
2642 *pf
->addr
, NULL
, a
, RCA_ALL
);
2643 q_status_message(SM_ORDER
, 3, 3,
2644 "Adding addresses from role");
2645 mail_free_address(&a
);
2655 he
->display_it
= 1; /* start this off showing */
2658 switch(set_default_hdrval(pf
, custom
)){
2662 mail_free_address(pf
->addr
);
2664 removing_trailing_white_space(pf
->textbuf
);
2665 (void)removing_double_quotes(pf
->textbuf
);
2666 build_address(pf
->textbuf
, &addr
, NULL
, NULL
, NULL
);
2667 rfc822_parse_adrlist(pf
->addr
, addr
, ps_global
->maildomain
);
2668 fs_give((void **)&addr
);
2680 if(pf
->addr
&& *pf
->addr
&& !(*pf
->addr
)->mailbox
){
2681 mail_free_address(pf
->addr
);
2682 he
->display_it
= 1; /* start this off showing */
2685 if(pf
->textbuf
) /* free default value in any case */
2686 fs_give((void **)&pf
->textbuf
);
2688 /* outgoing2strings will alloc the string pf->scratch below */
2689 he
->realaddr
= &pf
->scratch
;
2693 sending_order
[NN
+8] = pf
;
2695 if(role
&& role
->fcc
)
2698 fcc
= get_fcc(fcc_arg
);
2701 fs_give((void **)&fcc_to_free
);
2705 if(((flags
& PS_STICKY_FCC
) && fcc
[0]) || (role
&& role
->fcc
))
2711 if(strcmp(fcc
, ps_global
->VAR_DEFAULT_FCC
) != 0)
2712 he
->display_it
= 1; /* start this off showing */
2714 he
->realaddr
= &fcc
;
2720 sending_order
[NN
+6] = pf
;
2722 switch(set_default_hdrval(pf
, custom
)){
2725 pf
->scratch
= pf
->textbuf
;
2728 if(outgoing
->subject
)
2729 fs_give((void **)&outgoing
->subject
);
2735 /* if no value, use default */
2736 if(outgoing
->subject
){
2737 pf
->scratch
= cpystr(outgoing
->subject
);
2740 pf
->scratch
= pf
->textbuf
;
2747 he
->realaddr
= &pf
->scratch
;
2748 pf
->text
= &outgoing
->subject
;
2752 q_status_message1(SM_ORDER
,3,7,
2753 "Unknown header type %d in pine_send",
2759 * We may or may not want to give the user the chance to edit
2760 * the From and Reply-To lines. If they are listed in either
2761 * Default-composer-hdrs or Customized-hdrs, then they can edit
2763 * If canedit is not set, that means that this header is not in
2764 * the user's customized-hdrs. If rich_header is set, that
2765 * means that this header is not in the user's
2766 * default-composer-hdrs (since From and Reply-To are rich
2767 * by default). So, don't give it an he to edit with in that case.
2769 * For other types, just not setting canedit will cause it to be
2770 * uneditable, regardless of what the user does.
2774 /* to allow it, we let this fall through to the reply-to case below */
2775 if(ps_global
->never_allow_changing_from
||
2776 (F_OFF(F_ALLOW_CHANGING_FROM
, ps_global
) &&
2777 !(role
&& role
->from
))){
2778 if(pf
->canedit
|| !he
->rich_header
)
2779 q_status_message(SM_ORDER
, 3, 3,
2780 _("Not allowed to change header \"From\""));
2782 memset(he
, 0, (size_t)sizeof(*he
));
2788 if(!pf
->canedit
&& he
->rich_header
){
2789 memset(he
, 0, (size_t)sizeof(*he
));
2801 memset(he
, 0, (size_t)sizeof(*he
));
2812 * This is so the builder can tell the composer to fill the affected
2813 * field based on the value in the field on the left.
2815 * Note that this mechanism isn't completely general. Each entry has
2816 * only a single next_affected, so if some other entry points an
2817 * affected entry at an entry with a next_affected, they all inherit
2818 * that next_affected. Since this isn't used much a careful ordering
2819 * of the affected fields should make it a sufficient mechanism.
2821 he_to
->affected_entry
= he_fcc
;
2822 he_news
->affected_entry
= he_fcc
;
2823 he_lcc
->affected_entry
= he_to
;
2824 he_to
->next_affected
= he_fcc
;
2826 (--pf
)->next
= (total_cnt
!= fixed_cnt
) ? header
.custom
: NULL
;
2828 i
--; /* subtract one because N_ATTCH doesn't get a sending_order slot */
2830 * Set up headerentries for custom fields.
2831 * NOTE: "i" is assumed to now index first custom field in sending
2834 for(pf
= pf
->next
; pf
&& pf
->name
; pf
= pf
->next
){
2848 if(pf
->addr
){ /* better be set */
2849 sending_order
[i
++] = pf
;
2850 *he
= he_custom_addr_templ
;
2851 /* change default text into an ADDRESS */
2852 /* strip quotes around whole default */
2853 removing_trailing_white_space(pf
->textbuf
);
2854 (void)removing_double_quotes(pf
->textbuf
);
2855 build_address(pf
->textbuf
, &addr
, NULL
, NULL
, NULL
);
2856 rfc822_parse_adrlist(pf
->addr
, addr
, ps_global
->maildomain
);
2857 fs_give((void **)&addr
);
2859 fs_give((void **)&pf
->textbuf
);
2861 he
->realaddr
= &pf
->scratch
;
2862 if(F_OFF(F_ENABLE_TAB_COMPLETE
,ps_global
))
2863 he
->nickcmpl
= NULL
;
2869 sending_order
[i
++] = pf
;
2870 *he
= he_custom_free_templ
;
2871 he
->realaddr
= &pf
->textbuf
;
2872 pf
->text
= &pf
->textbuf
;
2873 if(((!pf
->val
|| !pf
->val
[0]) && pf
->textbuf
&& pf
->textbuf
[0]) ||
2874 (pf
->val
&& (!pf
->textbuf
|| strcmp(pf
->textbuf
, pf
->val
))))
2875 he
->display_it
= 1; /* show it */
2880 q_status_message1(SM_ORDER
,0,7,"Unknown custom header type %d",
2885 he
->name
= pf
->name
;
2887 /* use first 8 characters for prompt */
2888 he
->prompt
= cpystr(" : ");
2889 strncpy(he
->prompt
, he
->name
, MIN(strlen(he
->name
), he
->prwid
- 2));
2891 he
->rich_header
= view_as_rich(he
->name
, he
->rich_header
);
2896 * Make sure at least *one* field is displayable...
2898 for(index
= -1, i
=0, pf
=header
.local
; pf
&& pf
->name
; pf
=pf
->next
, i
++)
2899 if(HE(pf
) && !HE(pf
)->rich_header
){
2905 * None displayable!!! Warn and display defaults.
2908 q_status_message(SM_ORDER
,0,5,
2909 "No default-composer-hdrs matched, displaying defaults");
2910 for(i
= 0, pf
= header
.local
; pf
; pf
= pf
->next
, i
++)
2911 if((i
== N_TO
|| i
== N_CC
|| i
== N_SUBJ
|| i
== N_ATTCH
)
2913 HE(pf
)->rich_header
= 0;
2917 * Save information about body which set_mime_type_by_grope might change.
2918 * Then, if we get an error sending, we reset these things so that
2919 * grope can do it's thing again after we edit some more.
2921 if ((*body
)->type
== TYPEMULTIPART
)
2922 bp
= save_body_particulars(&(*body
)->nested
.part
->body
);
2924 bp
= save_body_particulars(*body
);
2927 local_redraft_pos
= redraft_pos
;
2929 /*----------------------------------------------------------------------
2930 Loop calling the editor until everything goes well
2933 int saved_user_timeout
;
2935 /* Reset body to what it was when we started. */
2936 if ((*body
)->type
== TYPEMULTIPART
)
2937 reset_body_particulars(bp
, &(*body
)->nested
.part
->body
);
2939 reset_body_particulars(bp
,*body
);
2941 * set initial cursor position based on how many times we've been
2944 if(reply
&& reply
->pseudo
){
2945 pbf
->pine_flags
|= reply
->data
.pico_flags
;
2947 else if(body_start
){
2948 pbf
->pine_flags
|= P_BODY
;
2949 body_start
= 0; /* maybe not next time */
2951 else if(local_redraft_pos
){
2952 pbf
->edit_offset
= local_redraft_pos
->offset
;
2953 /* set the start_here bit in correct header */
2954 for(pf
= header
.local
; pf
&& pf
->name
; pf
= pf
->next
)
2955 if(strcmp(pf
->name
, local_redraft_pos
->hdrname
) == 0
2957 HE(pf
)->start_here
= 1;
2961 /* If didn't find it, we start in body. */
2962 if(!pf
|| !pf
->name
)
2963 pbf
->pine_flags
|= P_BODY
;
2965 else if(reply
&& (!reply
->forw
&& !reply
->forwarded
)){
2966 pbf
->pine_flags
|= P_BODY
;
2969 /* in case these were turned on in previous pass through loop */
2971 pf_nobody
->writehdr
= 0;
2972 pf_nobody
->localcopy
= 0;
2976 pf_fcc
->localcopy
= 0;
2979 * If a sending attempt failed after we passed the message text
2980 * thru a user-defined filter, "orig_so" points to the original
2981 * text. Replace the body's encoded data with the original...
2984 STORE_S
**so
= (STORE_S
**)(((*body
)->type
== TYPEMULTIPART
)
2985 ? &(*body
)->nested
.part
->body
.contents
.text
.data
2986 : &(*body
)->contents
.text
.data
);
2993 * Convert the envelope and body to the string format that
2996 outgoing2strings(&header
, *body
, &pbf
->msgtext
, &pbf
->attachments
, 0);
2998 for(pf
= header
.local
; pf
&& pf
->name
; pf
= pf
->next
){
3000 * If this isn't the first time through this loop, we may have
3001 * freed some of the FreeText headers below so that they wouldn't
3002 * show up as empty headers in the finished message. Need to
3003 * alloc them again here so they can be edited.
3005 if(pf
->type
== FreeText
&& HE(pf
) && !*HE(pf
)->realaddr
)
3006 *HE(pf
)->realaddr
= cpystr("");
3008 if(pf
->type
!= Attachment
&& HE(pf
) && *HE(pf
)->realaddr
)
3009 HE(pf
)->maxlen
= strlen(*HE(pf
)->realaddr
);
3013 * If From is exposed, probably by a role, then start the cursor
3014 * on the first line which isn't filled in. If it isn't, then we
3015 * don't move the cursor, mostly for back-compat.
3017 if((!reply
|| reply
->forw
|| reply
->forwarded
) &&
3018 !local_redraft_pos
&& !(pbf
->pine_flags
& P_BODY
) && he_from
&&
3019 (he_from
->display_it
|| !he_from
->rich_header
)){
3020 for(pf
= header
.local
; pf
&& pf
->name
; pf
= pf
->next
)
3022 (HE(pf
)->display_it
|| !HE(pf
)->rich_header
) &&
3024 (!*HE(pf
)->realaddr
|| !**HE(pf
)->realaddr
)){
3025 HE(pf
)->start_here
= 1;
3031 mswin_setwindowmenu (MENU_COMPOSER
);
3034 cancel_busy_cue(-1);
3035 flush_status_messages(1);
3037 /* turn off user input timeout when in composer */
3038 saved_user_timeout
= ps_global
->hours_to_timeout
;
3039 ps_global
->hours_to_timeout
= 0;
3040 dprint((1, "\n ---- COMPOSER ----\n"));
3041 editor_result
= pico(pbf
);
3042 dprint((4, "... composer returns (0x%x)\n", editor_result
));
3043 ps_global
->hours_to_timeout
= saved_user_timeout
;
3046 mswin_setwindowmenu (MENU_DEFAULT
);
3048 fix_windsize(ps_global
);
3051 * Only reinitialize signals if we didn't receive an interesting
3052 * one while in pico, since pico's return is part of processing that
3053 * signal and it should continue to be ignored.
3055 if(!(editor_result
& COMP_GOTHUP
))
3056 init_signals(); /* Pico has it's own signal stuff */
3059 * We're going to save in DEADLETTER. Dump attachments first.
3061 if(editor_result
& COMP_CANCEL
)
3062 free_attachment_list(&pbf
->attachments
);
3064 /* Turn strings back into structures */
3065 strings2outgoing(&header
, body
, pbf
->attachments
, flowing_requested
);
3067 /* Make newsgroups NULL if it is "" (so won't show up in headers) */
3068 if(outgoing
->newsgroups
){
3069 sqzspaces(outgoing
->newsgroups
);
3070 if(!outgoing
->newsgroups
[0])
3071 fs_give((void **)&(outgoing
->newsgroups
));
3074 /* Make subject NULL if it is "" (so won't show up in headers) */
3075 if(outgoing
->subject
&& !outgoing
->subject
[0])
3076 fs_give((void **)&(outgoing
->subject
));
3078 /* remove custom fields that are empty */
3079 for(pf
= header
.local
; pf
&& pf
->name
; pf
= pf
->next
){
3080 if(pf
->type
== FreeText
&& pf
->textbuf
){
3081 if(pf
->textbuf
[0] == '\0'){
3082 fs_give((void **)&pf
->textbuf
);
3088 removing_trailing_white_space(fcc
);
3090 /*-------- Stamp it with a current date -------*/
3091 if(outgoing
->date
) /* update old date */
3092 fs_give((void **)&(outgoing
->date
));
3094 if(F_ON(F_QUELL_TIMEZONE
, ps_global
))
3095 mail_parameters(NULL
, SET_DISABLE822TZTEXT
, (void *) TRUE
);
3097 rfc822_date(tmp_20k_buf
); /* format and copy new date */
3098 if(F_ON(F_QUELL_TIMEZONE
, ps_global
))
3099 mail_parameters(NULL
, SET_DISABLE822TZTEXT
, (void *) FALSE
);
3101 outgoing
->date
= (unsigned char *) cpystr(tmp_20k_buf
);
3103 /* Set return_path based on From which is going to be used */
3104 if(outgoing
->return_path
)
3105 mail_free_address(&outgoing
->return_path
);
3107 outgoing
->return_path
= rfc822_cpy_adr(outgoing
->from
);
3110 * Don't ever believe the sender that is there.
3111 * If From doesn't look quite right, generate our own sender.
3113 if(outgoing
->sender
)
3114 mail_free_address(&outgoing
->sender
);
3117 * If the LHS of the address doesn't match, or the RHS
3118 * doesn't match one of localdomain or hostname,
3119 * then add a sender line (really X-X-Sender).
3121 * Don't add a personal_name since the user can change that.
3123 if(F_OFF(F_DISABLE_SENDER
, ps_global
)
3126 || !outgoing
->from
->mailbox
3127 || strucmp(outgoing
->from
->mailbox
, ps_global
->VAR_USER_ID
) != 0
3128 || !outgoing
->from
->host
3129 || !(strucmp(outgoing
->from
->host
, ps_global
->localdomain
) == 0
3130 || strucmp(outgoing
->from
->host
, ps_global
->hostname
) == 0))){
3132 outgoing
->sender
= mail_newaddr();
3133 outgoing
->sender
->mailbox
= cpystr(ps_global
->VAR_USER_ID
);
3134 outgoing
->sender
->host
= cpystr(ps_global
->hostname
);
3137 if(ps_global
->newthread
){
3138 if(outgoing
->in_reply_to
) fs_give((void **)&outgoing
->in_reply_to
);
3139 if(outgoing
->references
) fs_give((void **)&outgoing
->references
);
3142 /*----- Message is edited, now decide what to do with it ----*/
3143 if(editor_result
& (COMP_SUSPEND
| COMP_GOTHUP
| COMP_CANCEL
)){
3144 /*=========== Postpone or Interrupted message ============*/
3145 CONTEXT_S
*fcc_cntxt
= NULL
;
3146 char folder
[MAXPATH
+1];
3150 dprint((4, "pine_send:%s handling\n",
3151 (editor_result
& COMP_SUSPEND
)
3153 : (editor_result
& COMP_GOTHUP
)
3155 : (editor_result
& COMP_CANCEL
)
3156 ? "CANCEL" : "HUH?"));
3157 if((editor_result
& COMP_CANCEL
)
3158 && (F_ON(F_QUELL_DEAD_LETTER
, ps_global
)
3159 || ps_global
->deadlets
== 0)){
3160 q_status_message(SM_ORDER
, 0, 3, "Message cancelled");
3165 * The idea here is to use the Fcc: writing facility
3166 * to append to the special postponed message folder...
3168 * NOTE: the strategy now is to write the message and
3169 * all attachments as they exist at composition time.
3170 * In other words, attachments are postponed by value
3171 * and not reference. This may change later, but we'll
3172 * need a local "message/external-body" type that
3173 * outgoing2strings knows how to properly set up for
3174 * the composer. Maybe later...
3179 if(F_ON(F_COMPOSE_REJECTS_UNQUAL
, ps_global
)
3180 && (editor_result
& COMP_SUSPEND
)
3181 && (check_addresses(&header
) == CA_BAD
)){
3182 /*--- Addresses didn't check out---*/
3183 q_status_message(SM_ORDER
, 7, 7,
3184 _("Not allowed to postpone message until addresses are qualified"));
3189 * Build the local message copy so.
3191 * In the HUP case, we'll write the bezerk delimiter by
3192 * hand and output the message directly into the folder.
3193 * It's not only faster, we don't have to worry about
3194 * c-client reentrance and less hands paw over the data so
3195 * there's less chance of a problem.
3197 * In the Postpone case, just create it if the user wants to
3198 * and create a temporary storage object to write into. */
3200 lmc
.all_written
= lmc
.text_only
= lmc
.text_written
= 0;
3201 if(editor_result
& (COMP_GOTHUP
| COMP_CANCEL
)){
3203 time_t now
= time((time_t *)0);
3205 #if defined(DOS) || defined(OS2)
3207 * we can't assume anything about root or home dirs, so
3208 * just plunk it down in the same place as the pinerc
3210 if(!getenv("HOME")){
3211 char *lc
= last_cmpnt(ps_global
->pinerc
);
3214 strncpy(folder
,ps_global
->pinerc
,
3215 MIN(lc
-ps_global
->pinerc
,sizeof(folder
)-1));
3216 folder
[MIN(lc
-ps_global
->pinerc
,sizeof(folder
)-1)]='\0';
3219 strncat(folder
, (editor_result
& COMP_GOTHUP
)
3220 ? INTERRUPTED_MAIL
: DEADLETTER
,
3221 sizeof(folder
)-strlen(folder
)-1);
3226 ps_global
->VAR_OPER_DIR
3227 ? ps_global
->VAR_OPER_DIR
: ps_global
->home_dir
,
3228 (editor_result
& COMP_GOTHUP
)
3229 ? INTERRUPTED_MAIL
: DEADLETTER
,
3232 if(editor_result
& COMP_CANCEL
){
3233 char filename
[MAXPATH
+1], newfname
[MAXPATH
+1], nbuf
[5];
3235 if(strlen(folder
) + 1 < sizeof(filename
))
3236 for(i
= ps_global
->deadlets
- 1; i
> 0 && i
< 9; i
--){
3237 strncpy(filename
, folder
, sizeof(filename
));
3238 filename
[sizeof(filename
)-1] = '\0';
3239 strncpy(newfname
, filename
, sizeof(newfname
));
3240 newfname
[sizeof(newfname
)-1] = '\0';
3243 snprintf(nbuf
, sizeof(nbuf
), "%d", i
);
3244 nbuf
[sizeof(nbuf
)-1] = '\0';
3245 strncat(filename
, nbuf
,
3246 sizeof(filename
)-strlen(filename
)-1);
3247 filename
[sizeof(filename
)-1] = '\0';
3250 snprintf(nbuf
, sizeof(nbuf
), "%d", i
+1);
3251 nbuf
[sizeof(nbuf
)-1] = '\0';
3252 strncat(newfname
, nbuf
,
3253 sizeof(newfname
)-strlen(newfname
)-1);
3254 newfname
[sizeof(newfname
)-1] = '\0';
3255 (void) rename_file(filename
, newfname
);
3261 newfile
= can_access(folder
, ACCESS_EXISTS
);
3263 if((lmc
.so
= so_get(FCC_SOURCE
, NULL
, WRITE_ACCESS
)) != NULL
){
3264 if (outgoing
->from
){
3265 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, "%sFrom %s@%s %.24s\015\012",
3266 newfile
? "" : "\015\012",
3267 outgoing
->from
->mailbox
,
3268 outgoing
->from
->host
, ctime(&now
));
3269 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
3270 if(!so_puts(lmc
.so
, tmp_20k_buf
)){
3271 if(editor_result
& COMP_CANCEL
)
3272 q_status_message2(SM_ORDER
| SM_DING
, 3, 3,
3273 "Can't write \"%s\": %s",
3274 folder
, error_description(errno
));
3276 dprint((1, "* * * CAN'T WRITE %s: %s\n",
3277 folder
? folder
: "?",
3278 error_description(errno
)));
3283 else{ /* Must be COMP_SUSPEND */
3284 if(!ps_global
->VAR_POSTPONED_FOLDER
3285 || !ps_global
->VAR_POSTPONED_FOLDER
[0]){
3286 q_status_message(SM_ORDER
| SM_DING
, 3, 3,
3287 _("No postponed file defined"));
3292 * Store the cursor position
3294 * First find the header entry with the start_here
3295 * bit set, if any. This means the editor is telling
3296 * us to start on this header field next time.
3298 start_here_name
= NULL
;
3299 for(pf
= header
.local
; pf
&& pf
->name
; pf
= pf
->next
)
3300 if(HE(pf
) && HE(pf
)->start_here
){
3301 start_here_name
= pf
->name
;
3305 /* If there wasn't one, ":" means we start in the body. */
3306 if(!start_here_name
|| !*start_here_name
)
3307 start_here_name
= ":";
3309 if(ps_global
->VAR_FORM_FOLDER
3310 && ps_global
->VAR_FORM_FOLDER
[0]
3311 && postpone_prompt() == 'f'){
3312 strncpy(folder
, ps_global
->VAR_FORM_FOLDER
,
3314 folder
[sizeof(folder
)-1] = '\0';
3315 strncpy(label
, "form letter", sizeof(label
));
3316 label
[sizeof(label
)-1] = '\0';
3319 strncpy(folder
, ps_global
->VAR_POSTPONED_FOLDER
,
3321 folder
[sizeof(folder
)-1] = '\0';
3322 strncpy(label
, "postponed message", sizeof(label
));
3323 label
[sizeof(label
)-1] = '\0';
3326 lmc
.so
= open_fcc(folder
,&fcc_cntxt
, 1, NULL
, NULL
);
3333 /* copy fcc line to postponed or interrupted folder */
3335 pf_fcc
->localcopy
= 1;
3337 /* plug error into header for later display to user */
3338 if((editor_result
& ~0xff) && (lmq
= last_message_queued()) != NULL
){
3339 pf_err
->writehdr
= 1;
3340 pf_err
->localcopy
= 1;
3341 pf_err
->textbuf
= lmq
;
3345 * if reply, write (UID)folder header field so we can
3346 * later flag the replied-to message \\ANSWERED
3347 * DON'T save MSGNO's.
3349 if(reply
&& reply
->uid
){
3350 char uidbuf
[MAILTMPLEN
], *p
;
3353 for(i
= 0L, p
= tmp_20k_buf
; reply
->data
.uid
.msgs
[i
]; i
++){
3355 sstrncpy(&p
, ",", SIZEOF_20KBUF
-(p
-tmp_20k_buf
));
3357 sstrncpy(&p
,ulong2string(reply
->data
.uid
.msgs
[i
]),SIZEOF_20KBUF
-(p
-tmp_20k_buf
));
3360 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
3362 pf_uid
->writehdr
= 1;
3363 pf_uid
->localcopy
= 1;
3364 snprintf(uidbuf
, sizeof(uidbuf
), "(%s%s%s)(%ld %lu %s)%s",
3365 reply
->prefix
? int2string(strlen(reply
->prefix
))
3366 : (reply
->forwarded
) ? "": "0 ",
3367 reply
->prefix
? " " : "",
3368 reply
->prefix
? reply
->prefix
: "",
3369 i
, reply
->data
.uid
.validity
,
3370 tmp_20k_buf
, reply
->mailbox
);
3371 uidbuf
[sizeof(uidbuf
)-1] = '\0';
3372 pf_uid
->textbuf
= cpystr(uidbuf
);
3375 * Logically, this ought to be part of pf_uid, but this
3376 * was added later and so had to be in a separate header
3377 * for backwards compatibility.
3379 pf_mbox
->writehdr
= 1;
3380 pf_mbox
->localcopy
= 1;
3381 pf_mbox
->textbuf
= cpystr(reply
->origmbox
3386 /* Save cursor position */
3387 if(start_here_name
&& *start_here_name
){
3388 char curposbuf
[MAILTMPLEN
];
3390 pf_curpos
->writehdr
= 1;
3391 pf_curpos
->localcopy
= 1;
3392 snprintf(curposbuf
, sizeof(curposbuf
), "%s %ld", start_here_name
,
3394 curposbuf
[sizeof(curposbuf
)-1] = '\0';
3395 pf_curpos
->textbuf
= cpystr(curposbuf
);
3399 * Work around c-client reply-to bug. C-client will
3400 * return a reply_to in an envelope even if there is
3401 * no reply-to header field. We want to note here whether
3402 * the reply-to is real or not.
3404 if(outgoing
->reply_to
|| hdr_is_in_list("reply-to", custom
)){
3405 pf_ourrep
->writehdr
= 1;
3406 pf_ourrep
->localcopy
= 1;
3407 if(outgoing
->reply_to
)
3408 pf_ourrep
->textbuf
= cpystr("Full");
3410 pf_ourrep
->textbuf
= cpystr("Empty");
3413 /* Save the role-specific smtp server */
3414 if(role
&& role
->smtp
&& role
->smtp
[0]){
3415 char *q
, *smtp
= NULL
;
3420 * Turn the list of smtp servers into a space-
3421 * delimited list in a single string.
3423 for(lp
= role
->smtp
; (q
= *lp
) != NULL
; lp
++)
3424 len
+= (strlen(q
) + 1);
3427 smtp
= (char *) fs_get(len
* sizeof(char));
3429 for(lp
= role
->smtp
; (q
= *lp
) != NULL
; lp
++){
3430 if(lp
!= role
->smtp
)
3431 strncat(smtp
, " ", len
-strlen(smtp
)-1);
3433 strncat(smtp
, q
, len
-strlen(smtp
)-1);
3439 pf_smtp_server
->writehdr
= 1;
3440 pf_smtp_server
->localcopy
= 1;
3442 pf_smtp_server
->textbuf
= smtp
;
3444 pf_smtp_server
->textbuf
= cpystr("");
3447 /* Save the role-specific nntp server */
3448 if(suggested_nntp_server
||
3449 (role
&& role
->nntp
&& role
->nntp
[0])){
3450 char *q
, *nntp
= NULL
;
3454 if(role
&& role
->nntp
&& role
->nntp
[0]){
3456 * Turn the list of nntp servers into a space-
3457 * delimited list in a single string.
3459 for(lp
= role
->nntp
; (q
= *lp
) != NULL
; lp
++)
3460 len
+= (strlen(q
) + 1);
3463 nntp
= (char *) fs_get(len
* sizeof(char));
3465 for(lp
= role
->nntp
; (q
= *lp
) != NULL
; lp
++){
3466 if(lp
!= role
->nntp
)
3467 strncat(nntp
, " ", len
-strlen(nntp
)-1);
3469 strncat(nntp
, q
, len
-strlen(nntp
)-1);
3476 nntp
= cpystr(suggested_nntp_server
);
3478 pf_nntp_server
->writehdr
= 1;
3479 pf_nntp_server
->localcopy
= 1;
3481 pf_nntp_server
->textbuf
= nntp
;
3483 pf_nntp_server
->textbuf
= cpystr("");
3487 * Write the list of custom headers to the
3488 * X-Our-Headers header so that we can recover the
3492 for(pf
= header
.custom
; pf
&& pf
->name
; pf
= pf
->next
)
3493 sz
+= strlen(pf
->name
) + 1;
3498 pf_ourhdrs
->writehdr
= 1;
3499 pf_ourhdrs
->localcopy
= 1;
3500 pf_ourhdrs
->textbuf
= (char *)fs_get(sz
);
3501 memset(pf_ourhdrs
->textbuf
, 0, sz
);
3502 q
= pf_ourhdrs
->textbuf
;
3503 for(pf
= header
.custom
; pf
&& pf
->name
; pf
= pf
->next
){
3504 if(pf
!= header
.custom
)
3505 sstrncpy(&q
, ",", sz
-(q
-pf_ourhdrs
->textbuf
));
3507 sstrncpy(&q
, pf
->name
, sz
-(q
-pf_ourhdrs
->textbuf
));
3510 pf_ourhdrs
->textbuf
[sz
-1] = '\0';;
3514 * We need to make sure any header values that got cleared
3515 * get written to the postponed message (they won't if
3516 * pf->text is NULL). Otherwise, we can't tell previously
3517 * non-existent custom headers or default values from
3518 * custom (or other) headers that got blanked in the
3521 for(pf
= header
.local
; pf
&& pf
->name
; pf
= pf
->next
)
3522 if(pf
->type
== FreeText
&& HE(pf
) && !*(HE(pf
)->realaddr
))
3523 *(HE(pf
)->realaddr
) = cpystr("");
3526 * We're saving the message for use later. It may be that the
3527 * characters in the message are not all convertible to the
3528 * user's posting_charmap. We'll save it as UTF-8 instead
3529 * and worry about that the next time they try to send it.
3530 * Use a different save pointer just to be sure we don't
3531 * mess up the other stuff. We should probably make the
3532 * charset an argument.
3534 * We also need to fix the charset of the body part
3535 * the user is editing so that we can read it back
3536 * successfully when we resume the composition.
3538 ps_global
->post_utf8
= 1;
3543 if((*body
)->type
== TYPEMULTIPART
)
3544 bp
= &(*body
)->nested
.part
->body
;
3548 for(pm
= bp
->parameter
;
3549 pm
&& strucmp(pm
->attribute
, "charset") != 0;
3555 fs_give((void **) &pm
->value
);
3557 pm
->value
= cpystr("UTF-8");
3561 if(pine_rfc822_output(&header
,*body
,NULL
,NULL
) >= 0L){
3562 if(editor_result
& (COMP_GOTHUP
| COMP_CANCEL
)){
3568 if(editor_result
& COMP_CANCEL
){
3569 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
,
3570 "Saving to \"%s\"", folder
);
3571 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
3572 we_cancel
= busy_cue((char *)tmp_20k_buf
, NULL
, 1);
3576 so_get(FileStar
, folder
, WRITE_ACCESS
|OWNER_ONLY
)) != NULL
){
3577 gf_set_so_readc(&gc
, lmc
.so
);
3578 gf_set_so_writec(&pc
, hup_so
);
3579 so_seek(lmc
.so
, 0L, 0); /* read msg copy and */
3580 so_seek(hup_so
, 0L, 2); /* append to folder */
3582 gf_link_filter(gf_nvtnl_local
, NULL
);
3583 if(!(fcc_result
= !(err
= gf_pipe(gc
, pc
))))
3584 dprint((1, "*** PIPE FAILED: %s\n",
3587 gf_clear_so_readc(lmc
.so
);
3588 gf_clear_so_writec(hup_so
);
3592 dprint((1, "*** CAN'T CREATE %s: %s\n",
3593 folder
? folder
: "?",
3594 error_description(errno
)));
3597 cancel_busy_cue(-1);
3600 fcc_result
= write_fcc(folder
, fcc_cntxt
,
3601 lmc
.so
, NULL
, label
, NULL
);
3604 /* discontinue coerced UTF-8 posting */
3605 ps_global
->post_utf8
= 0;
3610 dprint((1, "***CAN'T ALLOCATE temp store: %s ",
3611 error_description(errno
)));
3613 if(editor_result
& COMP_GOTHUP
){
3615 * Special Hack #291: if any hi-byte bits are set in
3616 * editor's result, we put them there.
3618 if(editor_result
& 0xff00)
3619 exit(editor_result
>> 8);
3621 dprint((1, "Save composition on HUP %sED\n",
3622 fcc_result
? "SUCCEED" : "FAIL"));
3623 hup_signal(); /* Do what we normally do on SIGHUP */
3625 else if((editor_result
& COMP_SUSPEND
) && fcc_result
){
3626 if(ps_global
->VAR_FORM_FOLDER
3627 && ps_global
->VAR_FORM_FOLDER
[0]
3628 && !strcmp(folder
, ps_global
->VAR_FORM_FOLDER
))
3629 q_status_message(SM_ORDER
, 0, 3,
3630 _("Composition saved to Form Letter Folder. Select Compose to send."));
3632 q_status_message(SM_ORDER
, 0, 3,
3633 _("Composition postponed. Select Compose to resume."));
3635 break; /* postpone went OK, get out of here */
3637 else if(editor_result
& COMP_CANCEL
){
3640 if(fcc_result
&& folder
)
3641 lc
= last_cmpnt(folder
);
3643 q_status_message3(SM_ORDER
, 0, 3,
3644 _("Message cancelled%s%s%s"),
3645 (lc
&& *lc
) ? " and copied to \"" : "",
3646 (lc
&& *lc
) ? lc
: "",
3647 (lc
&& *lc
) ? "\" file" : "");
3651 q_status_message(SM_ORDER
, 0, 4,
3652 _("Continuing composition. Message not postponed or sent"));
3654 continue; /* postpone failed, jump back in to composer */
3658 /*------ Must be sending mail or posting ! -----*/
3659 int result
, valid_addr
, continue_with_only_fcc
= 0;
3660 CONTEXT_S
*fcc_cntxt
= NULL
;
3663 dprint((4, "=== sending: "));
3665 /* --- If posting, confirm with user ----*/
3666 if(outgoing
->newsgroups
&& *outgoing
->newsgroups
3667 && F_OFF(F_QUELL_EXTRA_POST_PROMPT
, ps_global
)
3668 && want_to(POST_PMT
, 'n', 'n', NO_HELP
, WT_NORM
) == 'n'){
3669 q_status_message(SM_ORDER
, 0, 3, _("Message not posted"));
3670 dprint((4, "no post, continuing\n"));
3674 if(!(outgoing
->to
|| outgoing
->cc
|| outgoing
->bcc
|| lcc_addr
3675 || outgoing
->newsgroups
)){
3677 if(F_OFF(F_AUTO_FCC_ONLY
, ps_global
) &&
3678 want_to(_("No recipients, really copy only to Fcc "),
3679 'n', 'n', h_send_fcc_only
, WT_NORM
) != 'y')
3682 continue_with_only_fcc
++;
3685 q_status_message(SM_ORDER
, 3, 4,
3686 _("No recipients specified!"));
3687 dprint((4, "no recip, continuing\n"));
3692 if((valid_addr
= check_addresses(&header
)) == CA_BAD
){
3693 /*--- Addresses didn't check out---*/
3694 dprint((4, "addrs failed, continuing\n"));
3698 if(F_ON(F_WARN_ABOUT_NO_TO_OR_CC
, ps_global
)
3699 && !continue_with_only_fcc
3700 && !(outgoing
->to
|| outgoing
->cc
|| lcc_addr
3701 || outgoing
->newsgroups
)
3702 && (want_to(_("No To, Cc, or Newsgroup specified, send anyway "),
3703 'n', 'n', h_send_check_to_cc
, WT_NORM
) != 'y')){
3704 dprint((4, "No To or CC or Newsgroup, continuing\n"));
3705 if(local_redraft_pos
&& local_redraft_pos
!= redraft_pos
)
3706 free_redraft_pos(&local_redraft_pos
);
3709 = (REDRAFT_POS_S
*) fs_get(sizeof(*local_redraft_pos
));
3710 memset((void *) local_redraft_pos
,0,sizeof(*local_redraft_pos
));
3711 local_redraft_pos
->hdrname
= cpystr(TONAME
);
3715 if(F_ON(F_WARN_ABOUT_NO_SUBJECT
, ps_global
)
3716 && check_for_subject(&header
) == CF_MISSING
){
3717 dprint((4, "No subject, continuing\n"));
3718 if(local_redraft_pos
&& local_redraft_pos
!= redraft_pos
)
3719 free_redraft_pos(&local_redraft_pos
);
3722 = (REDRAFT_POS_S
*) fs_get(sizeof(*local_redraft_pos
));
3723 memset((void *) local_redraft_pos
,0,sizeof(*local_redraft_pos
));
3724 local_redraft_pos
->hdrname
= cpystr(SUBJNAME
);
3728 if(F_ON(F_WARN_ABOUT_NO_FCC
, ps_global
)
3729 && check_for_fcc(fcc
) == CF_MISSING
){
3730 dprint((4, "No fcc, continuing\n"));
3731 if(local_redraft_pos
&& local_redraft_pos
!= redraft_pos
)
3732 free_redraft_pos(&local_redraft_pos
);
3735 = (REDRAFT_POS_S
*) fs_get(sizeof(*local_redraft_pos
));
3736 memset((void *) local_redraft_pos
,0,sizeof(*local_redraft_pos
));
3737 local_redraft_pos
->hdrname
= cpystr("Fcc");
3743 /*---- Check out fcc -----*/
3746 * If special name "inbox" then replace it with the
3749 if(ps_global
->VAR_INBOX_PATH
3750 && strucmp(fcc
, ps_global
->inbox_name
) == 0){
3753 replace_fcc
= cpystr(ps_global
->VAR_INBOX_PATH
);
3754 fs_give((void **)&fcc
);
3758 lmc
.all_written
= lmc
.text_written
= 0;
3759 /* lmc.text_only set on command line */
3760 if(!(lmc
.so
= open_fcc(fcc
, &fcc_cntxt
, 0, NULL
, NULL
))){
3761 /* ---- Open or allocation of fcc failed ----- */
3762 dprint((4,"can't open/allocate fcc, cont'g\n"));
3765 * Find field entry associated with fcc, and start
3768 for(pf
= header
.local
; pf
&& pf
->name
; pf
= pf
->next
)
3769 if(pf
->type
== Fcc
&& HE(pf
))
3770 HE(pf
)->start_here
= 1;
3775 so_truncate(lmc
.so
, fcc_size_guess(*body
) + 2048);
3780 /*---- Take care of any requested prefiltering ----*/
3781 if(sending_filter_requested
3782 && !filter_message_text(sending_filter_requested
, outgoing
,
3783 *body
, &orig_so
, &header
)){
3784 q_status_message1(SM_ORDER
, 3, 3,
3785 _("Problem filtering! Nothing sent%s."),
3786 fcc
? " or saved to fcc" : "");
3790 /*------ Actually post -------*/
3791 if(outgoing
->newsgroups
){
3792 char **alt_nntp
= NULL
, *alt_nntp_p
[2];
3793 if(((role
&& role
->nntp
)
3794 || suggested_nntp_server
)){
3795 if(ps_global
->FIX_NNTP_SERVER
3796 && ps_global
->FIX_NNTP_SERVER
[0])
3797 q_status_message(SM_ORDER
| SM_DING
, 5, 5,
3798 "Using nntp-server that is administratively fixed");
3799 else if(role
&& role
->nntp
)
3800 alt_nntp
= role
->nntp
;
3802 alt_nntp_p
[0] = suggested_nntp_server
;
3803 alt_nntp_p
[1] = NULL
;
3804 alt_nntp
= alt_nntp_p
;
3807 if(news_poster(&header
, *body
, alt_nntp
, pipe_callback
) < 0){
3808 dprint((1, "Post failed, continuing\n"));
3809 if(outgoing
->message_id
)
3810 fs_give((void **) &outgoing
->message_id
);
3812 outgoing
->message_id
= generate_message_id();
3817 result
|= P_NEWS_WIN
;
3821 * BUG: IF we've posted the message *and* an fcc was specified
3822 * then we've already got a neatly formatted message in the
3823 * lmc.so. It'd be nice not to have to re-encode everything
3824 * to insert it into the smtp slot...
3828 * Turn on "undisclosed recipients" header if no To or cc.
3830 if(!(outgoing
->to
|| outgoing
->cc
)
3831 && (outgoing
->bcc
|| lcc_addr
) && pf_nobody
&& pf_nobody
->addr
){
3832 pf_nobody
->writehdr
= 1;
3833 pf_nobody
->localcopy
= 1;
3836 if(priority_requested
){
3837 (void) set_priority_header(&header
, priority_requested
);
3838 fs_give((void **) &priority_requested
);
3841 #if defined(BACKGROUND_POST) && defined(SIGCHLD)
3843 * If requested, launch backgroud posting...
3845 if(background_requested
&& !(call_mailer_flags
& CM_VERBOSE
)){
3846 ps_global
->post
= (POST_S
*)fs_get(sizeof(POST_S
));
3847 memset(ps_global
->post
, 0, sizeof(POST_S
));
3849 ps_global
->post
->fcc
= cpystr(fcc
);
3851 if((ps_global
->post
->pid
= fork()) == 0){
3853 * Put us in new process group...
3855 setpgrp(0, ps_global
->post
->pid
);
3857 /* BUG: should fix argv[0] to indicate what we're up to */
3860 * If there are any live streams, pretend we never
3861 * knew them. Problem is two processes writing
3862 * same server process.
3863 * This is not clean but we're just going to exit
3864 * right away anyway. We just want to be sure to leave
3865 * the stuff that the parent is going to use alone.
3866 * The next three lines will disable the re-use of the
3867 * existing streams and cause us to open a new one if
3870 ps_global
->mail_stream
= NULL
;
3871 ps_global
->s_pool
.streams
= NULL
;
3872 ps_global
->s_pool
.nstream
= 0;
3874 /* quell any display output */
3875 ps_global
->in_init_seq
= 1;
3877 /*------- Actually mail the message ------*/
3878 if(valid_addr
== CA_OK
3879 && (outgoing
->to
|| outgoing
->cc
3880 || outgoing
->bcc
|| lcc_addr
)){
3881 char **alt_smtp
= NULL
;
3883 if(role
&& role
->smtp
){
3884 if(ps_global
->FIX_SMTP_SERVER
3885 && ps_global
->FIX_SMTP_SERVER
[0])
3886 q_status_message(SM_ORDER
| SM_DING
, 5, 5, "Use of a role-defined smtp-server is administratively prohibited");
3888 alt_smtp
= role
->smtp
;
3891 result
|= (call_mailer(&header
, *body
, alt_smtp
,
3893 call_mailer_file_result
,
3895 ? P_MAIL_WIN
: P_MAIL_LOSE
;
3897 if(result
& P_MAIL_LOSE
)
3898 mark_address_failure_for_pico(&header
);
3901 /*----- Was there an fcc involved? -----*/
3903 /*------ Write it if at least something worked ------*/
3904 if((result
& (P_MAIL_WIN
| P_NEWS_WIN
))
3905 || (!(result
& (P_MAIL_BITS
| P_NEWS_BITS
))
3906 && pine_rfc822_output(&header
, *body
,
3910 strncpy(label
, "Fcc", sizeof(label
));
3911 label
[sizeof(label
)-1] = '\0';
3912 if(strcmp(fcc
, ps_global
->VAR_DEFAULT_FCC
)){
3913 snprintf(label
+ 3, sizeof(label
)-3, " to %s", fcc
);
3914 label
[sizeof(label
)-1] = '\0';
3917 /*-- Now actually copy to fcc folder and close --*/
3918 result
|= (write_fcc(fcc
, fcc_cntxt
, lmc
.so
,
3920 F_ON(F_MARK_FCC_SEEN
, ps_global
)
3922 ? P_FCC_WIN
: P_FCC_LOSE
;
3924 else if(!(result
& (P_MAIL_BITS
| P_NEWS_BITS
))){
3925 q_status_message(SM_ORDER
, 3, 5,
3926 _("Fcc Failed!. No message saved."));
3928 "explicit fcc write failed!\n"));
3929 result
|= P_FCC_LOSE
;
3935 if(result
& (P_MAIL_LOSE
| P_NEWS_LOSE
| P_FCC_LOSE
)){
3937 * Encode child's result in hi-byte of
3940 editor_result
= ((result
<< 8) | COMP_GOTHUP
);
3947 if(ps_global
->post
->pid
> 0){
3948 q_status_message(SM_ORDER
, 3, 3,
3949 _("Message handed off for posting"));
3950 break; /* up to our child now */
3953 q_status_message1(SM_ORDER
| SM_DING
, 3, 3,
3954 "Can't fork for send: %s",
3955 error_description(errno
));
3956 if(ps_global
->post
->fcc
)
3957 fs_give((void **) &ps_global
->post
->fcc
);
3959 fs_give((void **) &ps_global
->post
);
3962 if(lmc
.so
) /* throw away unused store obj */
3965 if(outgoing
->message_id
)
3966 fs_give((void **) &outgoing
->message_id
);
3968 outgoing
->message_id
= generate_message_id();
3970 continue; /* if we got here, there was a prob */
3972 #endif /* BACKGROUND_POST */
3974 /*------- Actually mail the message ------*/
3975 if(valid_addr
== CA_OK
3976 && (outgoing
->to
|| outgoing
->cc
|| outgoing
->bcc
|| lcc_addr
)){
3977 char **alt_smtp
= NULL
;
3979 if(role
&& role
->smtp
){
3980 if(ps_global
->FIX_SMTP_SERVER
3981 && ps_global
->FIX_SMTP_SERVER
[0])
3982 q_status_message(SM_ORDER
| SM_DING
, 5, 5, "Use of a role-defined smtp-server is administratively prohibited");
3984 alt_smtp
= role
->smtp
;
3987 result
|= (call_mailer(&header
, *body
, alt_smtp
,
3989 call_mailer_file_result
,
3991 ? P_MAIL_WIN
: P_MAIL_LOSE
;
3993 if(result
& P_MAIL_LOSE
)
3994 mark_address_failure_for_pico(&header
);
3997 /*----- Was there an fcc involved? -----*/
3999 /*------ Write it if at least something worked ------*/
4000 if((result
& (P_MAIL_WIN
| P_NEWS_WIN
))
4001 || (!(result
& (P_MAIL_BITS
| P_NEWS_BITS
))
4002 && pine_rfc822_output(&header
, *body
, NULL
, NULL
))){
4005 strncpy(label
, "Fcc", sizeof(label
));
4006 label
[sizeof(label
)-1] = '\0';
4007 if(strcmp(fcc
, ps_global
->VAR_DEFAULT_FCC
)){
4008 snprintf(label
+ 3, sizeof(label
)-3, " to %s", fcc
);
4009 label
[sizeof(label
)-1] = '\0';
4012 /*-- Now actually copy to fcc folder and close --*/
4013 result
|= (write_fcc(fcc
, fcc_cntxt
, lmc
.so
, NULL
, label
,
4014 F_ON(F_MARK_FCC_SEEN
, ps_global
)
4016 ? P_FCC_WIN
: P_FCC_LOSE
;
4018 else if(!(result
& (P_MAIL_BITS
| P_NEWS_BITS
))){
4019 q_status_message(SM_ORDER
,3,5,
4020 _("Fcc Failed!. No message saved."));
4021 dprint((1, "explicit fcc write failed!\n"));
4022 result
|= P_FCC_LOSE
;
4028 /*----- Mail Post FAILED, back to composer -----*/
4029 if(result
& (P_MAIL_LOSE
| P_FCC_LOSE
)){
4030 dprint((1, "Send failed, continuing\n"));
4032 if(result
& P_FCC_LOSE
){
4034 * Find field entry associated with fcc, and start
4037 for(pf
= header
.local
; pf
&& pf
->name
; pf
= pf
->next
)
4038 if(pf
->type
== Fcc
&& HE(pf
))
4039 HE(pf
)->start_here
= 1;
4041 q_status_message(SM_ORDER
| SM_DING
, 3, 3,
4042 pine_send_status(result
, fcc
,
4043 tmp_20k_buf
, SIZEOF_20KBUF
, NULL
));
4046 if(outgoing
->message_id
)
4047 fs_give((void **) &outgoing
->message_id
);
4049 outgoing
->message_id
= generate_message_id();
4055 * If message sent *completely* successfully, there's a
4056 * reply struct AND we're allowed to write back state, do it.
4057 * But also protect against shifted message numbers due
4058 * to new mail arrival. Since the number passed is based
4059 * on the real imap msg no, AND we're sure no expunge has
4060 * been done, just fix up the sorted number...
4062 update_answered_flags(reply
);
4064 /*----- Signed, sealed, delivered! ------*/
4065 q_status_message(SM_ORDER
, 0, 3,
4066 pine_send_status(result
, fcc
, tmp_20k_buf
, SIZEOF_20KBUF
, NULL
));
4068 break; /* All's well, pop out of here */
4076 fs_give((void **)&fcc
);
4078 free_body_particulars(bp
);
4080 free_attachment_list(&pbf
->attachments
);
4082 standard_picobuf_teardown(pbf
);
4084 for(i
=0; i
< fixed_cnt
; i
++){
4085 if(pfields
[i
].textbuf
)
4086 fs_give((void **)&pfields
[i
].textbuf
);
4088 fs_give((void **)&pfields
[i
].name
);
4092 mail_free_address(&lcc_addr
);
4095 mail_free_address(&nobody_addr
);
4097 free_prompts(header
.custom
);
4098 free_customs(header
.custom
);
4099 fs_give((void **)&pfields
);
4100 free_headents(&headents
);
4101 fs_give((void **)&sending_order
);
4102 if(suggested_nntp_server
)
4103 fs_give((void **)&suggested_nntp_server
);
4105 fs_give((void **)&title
);
4107 if(local_redraft_pos
&& local_redraft_pos
!= redraft_pos
)
4108 free_redraft_pos(&local_redraft_pos
);
4110 pbf
= save_previous_pbuf
;
4113 dprint((4, "=== send returning ===\n"));
4118 * Check for subject in outgoing message.
4120 * Asks user whether to proceed with no subject.
4123 check_for_subject(METAENV
*header
)
4128 for(pf
= header
->local
; pf
&& pf
->name
; pf
= pf
->next
)
4129 if(pf
->type
== Subject
){
4130 if(pf
->text
&& *pf
->text
&& **pf
->text
)
4133 if(want_to("No Subject, send anyway ",
4134 'n', 'n', h_send_check_subj
, WT_NORM
) == 'y')
4149 * Check for fcc in outgoing message.
4151 * Asks user whether to proceed with no fcc.
4154 check_for_fcc(char *fcc
)
4161 if(want_to("No Fcc, send anyway ", 'n', 'n', h_send_check_fcc
, WT_NORM
) == 'y')
4172 * Confirm that the user wants to send to MAILER-DAEMON
4175 confirm_daemon_send(void)
4177 return(want_to("Really send this message to the MAILER-DAEMON",
4178 'n', 'n', NO_HELP
, WT_NORM
) == 'y');
4183 free_prompts(PINEFIELD
*head
)
4187 for(pf
= head
; pf
&& pf
->name
; pf
= pf
->next
){
4188 if(HE(pf
) && HE(pf
)->prompt
)
4189 fs_give((void **)& HE(pf
)->prompt
);
4195 postpone_prompt(void)
4197 static ESCKEY_S pstpn_form_opt
[] = { {'p', 'p', "P", N_("Postponed Folder")},
4198 {'f', 'f', "F", N_("Form Letter Folder")},
4199 {-1, 0, NULL
, NULL
} };
4201 return(radio_buttons(PSTPN_FORM_PMT
, -FOOTER_ROWS(ps_global
),
4202 pstpn_form_opt
, 'p', 0, NO_HELP
, RB_FLUSH_IN
));
4207 * call__mailer_file_result - some results from call_mailer might be in a file.
4208 * dislplay that file.
4211 call_mailer_file_result(char *filename
, int style
)
4214 if(style
& CM_BR_VERBOSE
){
4215 display_output_file(filename
, "Verbose SMTP Interaction", NULL
, DOF_BRIEF
);
4218 display_output_file(filename
, "POSTING ERRORS", "Posting Error", DOF_EMPTY
);
4224 mark_address_failure_for_pico(METAENV
*header
)
4228 int error_count
= 0;
4229 struct headerentry
*last_he
= NULL
;
4231 for(pf
= header
->local
; pf
&& pf
->name
; pf
= pf
->next
)
4232 if(pf
->type
== Address
&& pf
->rcptto
&& pf
->addr
&& *pf
->addr
)
4233 for(a
= *pf
->addr
; a
!= NULL
; a
= a
->next
)
4235 && error_count
++ < MAX_ADDR_ERROR
4237 if(last_he
) /* start last reported err */
4238 last_he
->start_here
= 0;
4240 (last_he
= HE(pf
))->start_here
= 1;
4247 * This is specialized routine. It assumes that the only things that we
4248 * care about restoring are the body type, subtype, encoding and the
4249 * state of the charset parameter. It also assumes that if the charset
4250 * parameter exists when we save it, it won't be removed later.
4252 BODY_PARTICULARS_S
*
4253 save_body_particulars(struct mail_bodystruct
*body
)
4255 BODY_PARTICULARS_S
*bp
;
4258 bp
= (BODY_PARTICULARS_S
*)fs_get(sizeof(BODY_PARTICULARS_S
));
4260 bp
->type
= body
->type
;
4261 bp
->encoding
= body
->encoding
;
4262 bp
->subtype
= body
->subtype
? cpystr(body
->subtype
) : NULL
;
4263 bp
->parameter
= body
->parameter
;
4264 for(pm
= bp
->parameter
;
4265 pm
&& strucmp(pm
->attribute
, "charset") != 0;
4267 ;/* searching for possible charset parameter */
4269 if(pm
){ /* found one */
4270 bp
->had_csp
= 1; /* saved body had charset parameter */
4271 bp
->charset
= pm
->value
? cpystr(pm
->value
) : NULL
;
4283 reset_body_particulars(BODY_PARTICULARS_S
*bp
, struct mail_bodystruct
*body
)
4285 body
->type
= bp
->type
;
4286 body
->encoding
= bp
->encoding
;
4288 fs_give((void **)&body
->subtype
);
4290 body
->subtype
= bp
->subtype
? cpystr(bp
->subtype
) : NULL
;
4293 PARAMETER
*pm
, *pm_prev
= NULL
;
4295 for(pm
= body
->parameter
;
4296 pm
&& strucmp(pm
->attribute
, "charset") != 0;
4300 if(pm
){ /* body has charset parameter */
4301 if(bp
->had_csp
){ /* reset to what it used to be */
4303 fs_give((void **)&pm
->value
);
4305 pm
->value
= bp
->charset
? cpystr(bp
->charset
) : NULL
;
4307 else{ /* remove charset parameter */
4309 pm_prev
->next
= pm
->next
;
4311 body
->parameter
= pm
->next
;
4313 mail_free_body_parameter(&pm
);
4319 * This can't happen because grope never removes
4320 * the charset parameter.
4322 q_status_message(SM_ORDER
| SM_DING
, 5, 5,
4323 "Programmer error: saved charset but no current charset param in pine_send");
4327 ok, still no parameter
4334 mail_free_body_parameter(&body
->parameter
);
4336 body
->parameter
= NULL
;
4342 free_body_particulars(BODY_PARTICULARS_S
*bp
)
4346 fs_give((void **)&bp
->subtype
);
4349 fs_give((void **)&bp
->charset
);
4351 fs_give((void **)&bp
);
4356 /*----------------------------------------------------------------------
4357 Build a status message suitable for framing
4359 Returns: pointer to resulting buffer
4362 pine_send_status(int result
, char *fcc_name
, char *buf
, size_t buflen
, int *goodorbad
)
4364 int avail
= ps_global
->ttyo
->screen_cols
- 2;
4365 int fixedneed
, need
, lenfcc
;
4366 char *part1
, *part2
, *part3
, *part4
, *part5
;
4367 char fbuf
[MAILTMPLEN
+1];
4369 part1
= (result
& P_NEWS_WIN
)
4371 : (result
& P_NEWS_LOSE
)
4374 part2
= ((result
& P_NEWS_BITS
) && (result
& P_MAIL_BITS
)
4375 && (result
& P_FCC_BITS
))
4377 : ((result
& P_NEWS_BITS
) && (result
& (P_MAIL_BITS
| P_FCC_BITS
)))
4380 part3
= (result
& P_MAIL_WIN
)
4382 : (result
& P_MAIL_LOSE
)
4385 part4
= ((result
& P_MAIL_BITS
) && (result
& P_FCC_BITS
))
4388 part5
= ((result
& P_FCC_WIN
) && !(result
& (P_MAIL_WIN
| P_NEWS_WIN
)))
4390 : (result
& P_FCC_WIN
)
4392 : (result
& P_FCC_LOSE
)
4395 lenfcc
= MIN(sizeof(fbuf
)-1, (result
& P_FCC_BITS
) ? strlen(fcc_name
) : 0);
4397 fixedneed
= 9 + strlen(part1
) + strlen(part2
) + strlen(part3
) +
4398 strlen(part4
) + strlen(part5
);
4399 need
= fixedneed
+ ((result
& P_FCC_BITS
) ? 2 : 0) + lenfcc
;
4401 if(need
> avail
&& fixedneed
+ 3 >= avail
){
4402 /* dots on end of fixed, no fcc */
4403 snprintf(fbuf
, sizeof(fbuf
), "Message %s%s%s%s%s ",
4404 part1
, part2
, part3
, part4
, part5
);
4405 short_str(fbuf
, buf
, buflen
, avail
, EndDots
);
4407 else if(need
> avail
){
4408 /* include whole fixed part, quotes and dots at end of fcc name */
4410 lenfcc
= MAX(1, lenfcc
-(need
-avail
));
4412 snprintf(buf
, buflen
, "Message %s%s%s%s%s%s%s%s.",
4413 part1
, part2
, part3
, part4
, part5
,
4414 (result
& P_FCC_BITS
) ? "\"" : "",
4415 short_str((result
& P_FCC_BITS
) ? fcc_name
: "",
4416 fbuf
, sizeof(fbuf
), lenfcc
, FrontDots
),
4417 (result
& P_FCC_BITS
) ? "\"" : "");
4421 snprintf(buf
, buflen
, "Message %s%s%s%s%s%s%s%s.",
4422 part1
, part2
, part3
, part4
, part5
,
4423 (result
& P_FCC_BITS
) ? "\"" : "",
4424 (result
& P_FCC_BITS
) ? fcc_name
: "",
4425 (result
& P_FCC_BITS
) ? "\"" : "");
4429 *goodorbad
= (result
& (P_MAIL_LOSE
| P_NEWS_LOSE
| P_FCC_LOSE
)) == 0;
4434 /* Callback from Pico to set the conditions for Alpine to start a new thread
4438 new_thread_on_blank_subject(void)
4440 ps_global
->newthread
= F_ON(F_NEW_THREAD_ON_BLANK_SUBJECT
, ps_global
);
4445 /*----------------------------------------------------------------------
4446 Call back for pico to insert the specified message's text
4448 Args: n -- message number to format
4449 f -- function to use to output the formatted message
4452 Returns: returns msg number formatted on success, zero on error.
4455 message_format_for_pico(long int n
, int (*f
) (int))
4459 char *old_quote
= NULL
;
4462 if(!(n
> 0L && n
<= mn_get_total(ps_global
->msgmap
)
4463 && (e
= pine_mail_fetchstructure(ps_global
->mail_stream
,
4464 mn_m2raw(ps_global
->msgmap
, n
), &b
)))){
4465 q_status_message(SM_ORDER
|SM_DING
,3,3,"Error inserting Message");
4466 flush_status_messages(0);
4470 /* temporarily assign a new quote string */
4471 old_quote
= pbf
->quote_str
;
4472 pbf
->quote_str
= reply_quote_str(e
);
4474 /* build separator line */
4475 reply_delimiter(e
, NULL
, f
);
4477 /* actually write message text */
4478 if(!format_message(mn_m2raw(ps_global
->msgmap
, n
), e
, b
, NULL
,
4479 FM_NEW_MESS
| FM_DISPLAY
| FM_NOCOLOR
| FM_NOINDENT
, f
)){
4480 q_status_message(SM_ORDER
|SM_DING
,3,3,"Error inserting Message");
4481 flush_status_messages(0);
4485 fs_give((void **)&pbf
->quote_str
);
4486 pbf
->quote_str
= old_quote
;
4491 /*----------------------------------------------------------------------
4492 Call back for pico to prompt the user for exit confirmation
4494 Args: dflt -- default answer for confirmation prompt
4496 Returns: either NULL if the user accepts exit, or string containing
4497 reason why the user declined.
4500 send_exit_for_pico(struct headerentry
*he
, void (*redraw_pico
)(void), int allow_flowed
,
4503 int i
, rv
, c
, verbose_label
= 0, bg_label
= 0, old_suspend
;
4504 int dsn_label
= 0, fcc_label
= 0, lparen
;
4505 int flowing_label
= 0, double_rad
;
4506 char *rstr
= NULL
, *p
, *lc
, *optp
;
4507 char dsn_string
[30];
4508 void (*redraw
)(void) = ps_global
->redrawer
;
4513 struct filters
*prev
, *next
;
4514 } *filters
= NULL
, *fp
;
4516 sending_filter_requested
= NULL
;
4517 call_mailer_flags
= 0;
4518 background_requested
= 0;
4519 flowing_requested
= allow_flowed
? 1 : 0;
4520 lmc
.text_only
= F_ON(F_NO_FCC_ATTACH
, ps_global
) != 0;
4521 if(priority_requested
)
4522 fs_give((void **) &priority_requested
);
4524 if(background_posting(FALSE
)){
4526 *result
= "Can't send while background posting. Use postpone.";
4531 if(F_ON(F_SEND_WO_CONFIRM
, ps_global
)){
4538 ps_global
->redrawer
= redraw_pico
;
4540 if((old_suspend
= F_ON(F_CAN_SUSPEND
, ps_global
)) != 0)
4541 (void) F_SET(F_CAN_SUSPEND
, ps_global
, 0);
4544 * Build list of available filters...
4546 for(i
=0; ps_global
->VAR_SEND_FILTER
&& ps_global
->VAR_SEND_FILTER
[i
]; i
++){
4547 for(p
= ps_global
->VAR_SEND_FILTER
[i
];
4548 *p
&& !isspace((unsigned char)*p
); p
++)
4553 if(!(is_absolute_path(ps_global
->VAR_SEND_FILTER
[i
])
4554 && can_access(ps_global
->VAR_SEND_FILTER
[i
],EXECUTE_ACCESS
) ==0)){
4559 fp
= (struct filters
*)fs_get(sizeof(struct filters
));
4561 if((lc
= last_cmpnt(ps_global
->VAR_SEND_FILTER
[i
])) != NULL
){
4562 fp
->filter
= cpystr(lc
);
4564 else if((p
- ps_global
->VAR_SEND_FILTER
[i
]) > 20){
4565 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, "...%s", p
- 17);
4566 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
4567 fp
->filter
= cpystr(tmp_20k_buf
);
4570 fp
->filter
= cpystr(ps_global
->VAR_SEND_FILTER
[i
]);
4576 fp
->prev
= filters
->prev
;
4577 fp
->prev
->next
= filters
->prev
= fp
;
4580 filters
= (struct filters
*)fs_get(sizeof(struct filters
));
4581 filters
->index
= -1;
4582 filters
->filter
= NULL
;
4583 filters
->next
= filters
->prev
= fp
;
4584 fp
->next
= fp
->prev
= filters
;
4592 opts
[i
++].label
= N_("Yes");
4597 opts
[i
++].label
= N_("No");
4600 /* set global_filter_pointer to desired filter or NULL if none */
4601 /* prepare two keymenu slots for selecting filter */
4602 opts
[i
].ch
= ctrl('P');
4604 opts
[i
].name
= "^P";
4605 opts
[i
++].label
= N_("Prev Filter");
4607 opts
[i
].ch
= ctrl('N');
4609 opts
[i
].name
= "^N";
4610 opts
[i
++].label
= N_("Next Filter");
4612 if(F_ON(F_FIRST_SEND_FILTER_DFLT
, ps_global
))
4613 filters
= filters
->next
;
4616 if(F_ON(F_VERBOSE_POST
, ps_global
)){
4617 /* setup keymenu slot to toggle verbose mode */
4618 opts
[i
].ch
= ctrl('W');
4620 opts
[i
].name
= "^W";
4621 verbose_label
= i
++;
4625 /* setup keymenu slot to toggle flowed mode */
4626 opts
[i
].ch
= ctrl('V');
4628 opts
[i
].name
= "^V";
4629 flowing_label
= i
++;
4630 flowing_requested
= 1;
4633 if(F_ON(F_NO_FCC_ATTACH
, ps_global
)){
4634 /* setup keymenu slot to toggle attacment on fcc */
4635 opts
[i
].ch
= ctrl('F');
4637 opts
[i
].name
= "^F";
4641 #if defined(BACKGROUND_POST) && defined(SIGCHLD)
4642 if(F_ON(F_BACKGROUND_POST
, ps_global
)){
4643 opts
[i
].ch
= ctrl('R');
4645 opts
[i
].name
= "^R";
4653 opts
[i
++].label
= N_("Priority");
4656 if(F_OFF(F_DONT_DO_SMIME
, ps_global
)){
4660 opts
[i
++].label
= "Encrypt";
4665 opts
[i
++].label
= "Sign";
4667 if(ps_global
->smime
){
4668 ps_global
->smime
->do_encrypt
= F_ON(F_ENCRYPT_DEFAULT_ON
, ps_global
);
4669 ps_global
->smime
->do_sign
= F_ON(F_SIGN_DEFAULT_ON
, ps_global
);
4676 if(F_ON(F_DSN
, ps_global
)){
4677 /* setup keymenu slots to toggle dsn bits */
4681 opts
[i
].label
= N_("DSNOpts");
4686 opts
[i
++].label
= "";
4690 opts
[i
++].label
= "";
4694 opts
[i
++].label
= "";
4698 opts
[i
].ch
= KEY_UP
;
4701 opts
[i
++].label
= "";
4703 opts
[i
].ch
= KEY_DOWN
;
4706 opts
[i
++].label
= "";
4711 fix_windsize(ps_global
);
4714 if(filters
&& filters
->filter
&& (p
= strindex(filters
->filter
, ' ')))
4720 strncpy(tmp_20k_buf
, "Send message", SIZEOF_20KBUF
);
4721 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
4722 optp
= tmp_20k_buf
+ strlen(tmp_20k_buf
);
4724 if(F_ON(F_NO_FCC_ATTACH
, ps_global
) && !lmc
.text_only
)
4725 sstrncpy(&optp
, " and Fcc Atmts", SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4727 if(allow_flowed
&& !flowing_requested
){
4728 if((optp
-tmp_20k_buf
)+2 < SIZEOF_20KBUF
){
4738 sstrncpy(&optp
, "not flowed", SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4742 if((optp
-tmp_20k_buf
)+2 < SIZEOF_20KBUF
){
4754 if(filters
->filter
){
4755 sstrncpy(&optp
, "filtered thru \"", SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4756 sstrncpy(&optp
, filters
->filter
, SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4757 if((optp
-tmp_20k_buf
) < SIZEOF_20KBUF
)
4761 sstrncpy(&optp
, "unfiltered", SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4764 if((call_mailer_flags
& CM_VERBOSE
) || background_requested
){
4765 if((optp
-tmp_20k_buf
)+2 < SIZEOF_20KBUF
){
4775 sstrncpy(&optp
, "in ", SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4776 if(call_mailer_flags
& CM_VERBOSE
)
4777 sstrncpy(&optp
, "verbose ", SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4779 if(background_requested
)
4780 sstrncpy(&optp
, "background ", SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4782 sstrncpy(&optp
, "mode", SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4785 if(g_rolenick
&& !(he
&& he
[N_FROM
].dirty
)){
4786 if((optp
-tmp_20k_buf
)+2 < SIZEOF_20KBUF
){
4796 sstrncpy(&optp
, "as \"", SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4797 sstrncpy(&optp
, g_rolenick
, SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4798 sstrncpy(&optp
, "\"", SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4801 if(call_mailer_flags
& CM_DSN_SHOW
){
4802 if((optp
-tmp_20k_buf
)+2 < SIZEOF_20KBUF
){
4814 sstrncpy(&optp
, dsn_string
, SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4818 if(ps_global
->smime
&& ps_global
->smime
->do_encrypt
){
4819 if((optp
-tmp_20k_buf
)+2 < SIZEOF_20KBUF
){
4831 sstrncpy(&optp
, "Encrypted", SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4834 if(ps_global
->smime
&& ps_global
->smime
->do_sign
){
4835 if((optp
-tmp_20k_buf
)+2 < SIZEOF_20KBUF
){
4847 sstrncpy(&optp
, "Signed", SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4851 if(lparen
&& (optp
-tmp_20k_buf
) < SIZEOF_20KBUF
)
4854 sstrncpy(&optp
, "? ", SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4855 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
4861 opts
[flowing_label
].label
= flowing_requested
? N_("NoFlow") : N_("Flow");
4864 opts
[verbose_label
].label
= (call_mailer_flags
& CM_VERBOSE
) ? N_("Normal") : N_("Verbose");
4867 opts
[bg_label
].label
= background_requested
4868 ? N_("Foreground") : N_("Background");
4871 opts
[fcc_label
].label
= lmc
.text_only
? N_("Fcc Attchmnts")
4872 : N_("No Fcc Atmts ");
4874 if(F_ON(F_DSN
, ps_global
)){
4875 if(call_mailer_flags
& CM_DSN_SHOW
){
4876 opts
[dsn_label
].label
= (call_mailer_flags
& CM_DSN_DELAY
)
4877 ? N_("NoDelay") : N_("Delay");
4878 opts
[dsn_label
+1].ch
= 's';
4879 opts
[dsn_label
+1].label
= (call_mailer_flags
& CM_DSN_SUCCESS
)
4880 ? N_("NoSuccess") : N_("Success");
4881 opts
[dsn_label
+2].ch
= 'x';
4882 opts
[dsn_label
+2].label
= (call_mailer_flags
& CM_DSN_NEVER
)
4883 ? N_("ErrRets") : N_("NoErrRets");
4884 opts
[dsn_label
+3].ch
= 'h';
4885 opts
[dsn_label
+3].label
= (call_mailer_flags
& CM_DSN_FULL
)
4886 ? N_("RetHdrs") : N_("RetFull");
4891 ((call_mailer_flags
& CM_DSN_SHOW
)
4892 ? 4 : F_ON(F_DSN
, ps_global
) ? 1 : 0) > 11)
4893 rv
= double_radio_buttons(tmp_20k_buf
, -FOOTER_ROWS(ps_global
), opts
,
4895 (F_ON(F_DSN
, ps_global
) && allow_flowed
)
4896 ? h_send_prompt_dsn_flowed
:
4897 F_ON(F_DSN
, ps_global
) ? h_send_prompt_dsn
:
4898 allow_flowed
? h_send_prompt_flowed
:
4902 rv
= radio_buttons(tmp_20k_buf
, -FOOTER_ROWS(ps_global
), opts
,
4905 ((call_mailer_flags
& CM_DSN_SHOW
)
4906 ? 4 : F_ON(F_DSN
, ps_global
) ? 1 : 0) == 11)
4908 (F_ON(F_DSN
, ps_global
) && allow_flowed
)
4909 ? h_send_prompt_dsn_flowed
:
4910 F_ON(F_DSN
, ps_global
) ? h_send_prompt_dsn
:
4911 allow_flowed
? h_send_prompt_flowed
:
4915 if(rv
== 'y'){ /* user ACCEPTS! */
4918 else if(rv
== 'n'){ /* Declined! */
4919 rstr
= _("No Message Sent");
4922 else if(rv
== 'z'){ /* Cancelled! */
4923 rstr
= _("Send Cancelled");
4926 else if(rv
== 10){ /* PREVIOUS filter */
4927 filters
= filters
->prev
;
4929 else if(rv
== 11){ /* NEXT filter */
4930 filters
= filters
->next
;
4933 lmc
.text_only
= !lmc
.text_only
;
4935 else if(rv
== 12){ /* flip verbose bit */
4936 if(call_mailer_flags
& CM_VERBOSE
)
4937 call_mailer_flags
&= ~CM_VERBOSE
;
4939 call_mailer_flags
|= CM_VERBOSE
;
4941 if((call_mailer_flags
& CM_VERBOSE
) && background_requested
)
4942 background_requested
= 0;
4944 else if(rv
== 22){ /* flip flowing bit */
4945 flowing_requested
= !flowing_requested
;
4948 if((background_requested
= !background_requested
)
4949 && (call_mailer_flags
& CM_VERBOSE
))
4950 call_mailer_flags
&= ~CM_VERBOSE
; /* clear verbose */
4952 else if(call_mailer_flags
& CM_DSN_SHOW
){
4953 if(rv
== 's'){ /* flip success bit */
4954 call_mailer_flags
^= CM_DSN_SUCCESS
;
4955 /* turn off related bits */
4956 if(call_mailer_flags
& CM_DSN_SUCCESS
)
4957 call_mailer_flags
&= ~(CM_DSN_NEVER
);
4959 else if(rv
== 'd'){ /* flip delay bit */
4960 call_mailer_flags
^= CM_DSN_DELAY
;
4961 /* turn off related bits */
4962 if(call_mailer_flags
& CM_DSN_DELAY
)
4963 call_mailer_flags
&= ~(CM_DSN_NEVER
);
4965 else if(rv
== 'x'){ /* flip never bit */
4966 call_mailer_flags
^= CM_DSN_NEVER
;
4967 /* turn off related bits */
4968 if(call_mailer_flags
& CM_DSN_NEVER
)
4969 call_mailer_flags
&= ~(CM_DSN_SUCCESS
| CM_DSN_DELAY
);
4971 else if(rv
== 'h'){ /* flip full bit */
4972 call_mailer_flags
^= CM_DSN_FULL
;
4975 else if(rv
== 'd'){ /* show dsn options */
4977 * When you turn on DSN, the default is to notify on
4978 * failure, success, or delay; and to return the whole
4981 call_mailer_flags
|= (CM_DSN_SHOW
| CM_DSN_SUCCESS
| CM_DSN_DELAY
| CM_DSN_FULL
);
4983 else if(rv
== 'p'){ /* choose X-Priority */
4986 prio
= choose_a_priority(priority_requested
);
4987 if((ps_global
->redrawer
= redraw_pico
) != NULL
){
4988 (*ps_global
->redrawer
)();
4989 fix_windsize(ps_global
);
4993 if(priority_requested
)
4994 fs_give((void **) &priority_requested
);
4997 priority_requested
= prio
;
4999 fs_give((void **) &prio
);
5004 if(ps_global
->smime
)
5005 ps_global
->smime
->do_encrypt
= !ps_global
->smime
->do_encrypt
;
5008 if(ps_global
->smime
)
5009 ps_global
->smime
->do_sign
= !ps_global
->smime
->do_sign
;
5013 snprintf(dsn_string
, sizeof(dsn_string
), "DSN requested[%s%s%s%s]",
5014 (call_mailer_flags
& CM_DSN_NEVER
)
5016 (call_mailer_flags
& CM_DSN_DELAY
)
5018 (call_mailer_flags
& CM_DSN_SUCCESS
)
5020 (call_mailer_flags
& CM_DSN_NEVER
)
5022 : (call_mailer_flags
& CM_DSN_FULL
) ? "-Full"
5024 dsn_string
[sizeof(dsn_string
)-1] = '\0';
5027 /* remember selection */
5028 if(filters
&& filters
->index
> -1)
5029 sending_filter_requested
= ps_global
->VAR_SEND_FILTER
[filters
->index
];
5032 filters
->prev
->next
= NULL
; /* tie off list */
5033 while(filters
){ /* then free it */
5036 fs_give((void **)&filters
->filter
);
5038 fs_give((void **)&filters
);
5044 (void) F_SET(F_CAN_SUSPEND
, ps_global
, 1);
5049 ps_global
->redrawer
= redraw
;
5051 return((rstr
== NULL
) ? 0 : 1);
5056 * Allow user to choose a priority for sending.
5058 * Returns an allocated priority on success, NULL otherwise.
5061 choose_a_priority(char *default_val
)
5063 char *choice
= NULL
;
5064 char **priority_list
, **lp
;
5065 char *starting_val
= NULL
;
5070 for(cnt
= 0, p
= priorities
; p
&& p
->desc
; p
++)
5073 cnt
++; /* for NONE entry */
5074 lp
= priority_list
= (char **) fs_get((cnt
+ 1) * sizeof(*priority_list
));
5075 memset(priority_list
, 0, (cnt
+1) * sizeof(*priority_list
));
5077 for(i
= 0, p
= priorities
; p
&& p
->desc
; p
++){
5078 *lp
= cpystr(p
->desc
);
5079 if(default_val
&& !strcmp(default_val
, p
->desc
))
5080 starting_val
= (*lp
);
5085 none
= _("NONE - No X-Priority header included");
5088 starting_val
= (*lp
);
5090 /* TRANSLATORS: SELECT A PRIORITY is a screen title
5091 TRANSLATORS: Print something1 using something2.
5092 "priorities" is something1 */
5093 choice
= choose_item_from_list(priority_list
, NULL
, _("SELECT A PRIORITY"),
5094 _("priorities"), h_select_priority_screen
,
5095 _("HELP FOR SELECTING A PRIORITY"),
5099 q_status_message(SM_ORDER
, 1, 4, _("No change"));
5100 else if(!strcmp(choice
, none
))
5103 free_list_array(&priority_list
);
5110 dont_flow_this_time(void)
5112 return(flowing_requested
? 0 : 1);
5116 /*----------------------------------------------------------------------
5117 Call back for pico to display mime type of attachment
5119 Args: file -- filename being attached
5121 Returns: returns 1 on success (message queued), zero otherwise (don't know
5122 type so nothing queued).
5125 mime_type_for_pico(char *file
)
5129 void *file_contents
;
5131 body
= mail_newbody();
5132 body
->type
= TYPEOTHER
;
5133 body
->encoding
= ENCOTHER
;
5135 /* don't know where the cursor's been, reset it */
5137 if(!set_mime_type_by_extension(body
, file
)){
5138 if((file_contents
=(void *)so_get(FileStar
,file
,READ_ACCESS
|READ_FROM_LOCALE
)) != NULL
){
5139 body
->contents
.text
.data
= file_contents
;
5140 set_mime_type_by_grope(body
);
5144 if(body
->type
!= TYPEOTHER
){
5146 q_status_message3(SM_ORDER
, 0, 3,
5147 _("File %s attached as type %s/%s"), file
,
5148 body_types
[body
->type
],
5149 body
->subtype
? body
->subtype
: rfc822_default_subtype(body
->type
));
5154 pine_free_body(&body
);
5159 /*----------------------------------------------------------------------
5160 Call back for pico to receive an uploaded message
5162 Args: fname -- name for uploaded file (empty if they want us to assign it)
5163 size -- pointer to long to hold the attachment's size
5165 Notes: the attachment is uploaded to a temp file, and
5167 Returns: TRUE on success, FALSE otherwise
5170 upload_msg_to_pico(char *fname
, size_t fnlen
, long int *size
)
5172 char cmd
[MAXPATH
+1], *fnp
= NULL
;
5173 char *locale_name
= NULL
;
5177 dprint((1, "Upload cmd called to xfer \"%s\"\n",
5178 fname
? fname
: "<NO FILE>"));
5180 if(!fname
) /* no place for file name */
5183 if(!*fname
){ /* caller wants temp file */
5184 if((fnp
= temp_nam(NULL
, "pu")) != NULL
){
5185 strncpy(fname
, fnp
, fnlen
);
5186 fname
[fnlen
-1] = '\0';
5188 fs_give((void **)&fnp
);
5192 locale_name
= convert_to_locale(fname
);
5194 build_updown_cmd(cmd
, sizeof(cmd
), ps_global
->VAR_UPLOAD_CMD_PREFIX
,
5195 ps_global
->VAR_UPLOAD_CMD
, locale_name
? locale_name
: fname
);
5196 if((syspipe
= open_system_pipe(cmd
, NULL
, NULL
, PIPE_USER
| PIPE_RESET
,
5197 0, pipe_callback
, pipe_report_error
)) != NULL
){
5198 (void) close_system_pipe(&syspipe
, NULL
, pipe_callback
);
5199 if((l
= name_file_size(locale_name
? locale_name
: fname
)) < 0L){
5200 q_status_message2(SM_ORDER
| SM_DING
, 3, 4,
5201 "Error determining size of %s: %s", fname
,
5202 fnp
= error_description(errno
));
5204 "!!! Upload cmd \"%s\" failed for \"%s\": %s\n",
5206 fname
? fname
: "?",
5213 fs_give((void **) &locale_name
);
5218 q_status_message(SM_ORDER
| SM_DING
, 3, 4, _("Error opening pipe"));
5221 fs_give((void **) &locale_name
);
5228 cancel_for_pico(void (*redraw_pico
)(void))
5233 _("Cancel message (answering \"Confirm\" will abandon your mail message) ? ");
5234 void (*redraw
)(void) = ps_global
->redrawer
;
5235 static ESCKEY_S opts
[] = {
5236 {'c', 'c', "C", N_("Confirm")},
5237 {'n', 'n', "N", N_("No")},
5242 ps_global
->redrawer
= redraw_pico
;
5243 fix_windsize(ps_global
);
5246 rv
= radio_buttons(prompt
, -FOOTER_ROWS(ps_global
), opts
,
5247 'n', 'x', h_confirm_cancel
, RB_NORM
);
5248 if(rv
== 'c'){ /* user ACCEPTS! */
5253 q_status_message(SM_INFO
, 1, 3, _(" Type \"C\" to cancel message "));
5254 display_message('x');
5260 ps_global
->redrawer
= redraw
;
5265 /*----------------------------------------------------------------------
5266 Pass the first text segment of the message thru the "send filter"
5268 Args: body pointer and address for storage object of old data
5270 Returns: returns 1 on success, zero on error.
5273 filter_message_text(char *fcmd
, ENVELOPE
*outgoing
, struct mail_bodystruct
*body
,
5274 STORE_S
**old
, METAENV
*header
)
5276 char *cmd
, *tmpf
= NULL
, *resultf
= NULL
, *errstr
= NULL
, *mtf
= NULL
;
5277 int key
= 0, include_hdrs
= 0;
5279 STORE_S
**so
= (STORE_S
**)((body
->type
== TYPEMULTIPART
)
5280 ? &body
->nested
.part
->body
.contents
.text
.data
5281 : &body
->contents
.text
.data
),
5282 *tmp_so
= NULL
, *tmpf_so
,
5283 *save_local_so
, *readthis_so
, *our_tmpf_so
= NULL
;
5284 #define DO_HEADERS 1
5287 && (cmd
=expand_filter_tokens(fcmd
, outgoing
, &tmpf
, &resultf
, &mtf
,
5288 &key
, &include_hdrs
, NULL
))){
5291 * We need WRITE_TO_LOCALE here because the user is going to
5292 * be operating on tmpf. We need to change it back after they
5295 if((tmpf_so
= so_get(FileStar
, tmpf
, EDIT_ACCESS
|OWNER_ONLY
|WRITE_TO_LOCALE
)) != NULL
){
5297 so_puts(tmpf_so
, filter_session_key());
5298 so_puts(tmpf_so
, NEWLINE
);
5302 * If the headers are wanted for filtering, we can just
5303 * stick them in the tmpf file that is already there before
5304 * putting the body in.
5307 save_local_so
= lmc
.so
;
5308 lmc
.so
= tmpf_so
; /* write it to tmpf_so */
5309 lmc
.all_written
= lmc
.text_written
= lmc
.text_only
= 0;
5310 pine_rfc822_header(header
, body
, NULL
, NULL
);
5311 lmc
.so
= save_local_so
;
5314 so_seek(*so
, 0L, 0);
5315 gf_set_so_readc(&gc
, *so
);
5316 gf_set_so_writec(&pc
, tmpf_so
);
5318 errstr
= gf_pipe(gc
, pc
);
5319 gf_clear_so_readc(*so
);
5320 gf_clear_so_writec(tmpf_so
);
5324 errstr
= "Can't create space for filter temporary file.";
5326 else if(include_hdrs
){
5328 * Gf_filter wants a single storage object to read from.
5329 * If headers are wanted for filtering we'll have to put them
5330 * and the body into a temp file first and then use that
5331 * as the storage object for gf_filter.
5332 * We don't use WRITE_TO_LOCALE in this case because gf_filter
5333 * takes care of that.
5335 if((our_tmpf_so
= so_get(TmpFileStar
, NULL
, EDIT_ACCESS
|OWNER_ONLY
)) != NULL
){
5336 /* put headers in our_tmpf_so */
5337 save_local_so
= lmc
.so
;
5338 lmc
.so
= our_tmpf_so
; /* write it to our_tmpf_so */
5339 lmc
.all_written
= lmc
.text_written
= lmc
.text_only
= 0;
5340 pine_rfc822_header(header
, body
, NULL
, NULL
);
5341 lmc
.so
= save_local_so
;
5343 /* put body in our_tmpf_so */
5344 so_seek(*so
, 0L, 0);
5345 gf_set_so_readc(&gc
, *so
);
5346 gf_set_so_writec(&pc
, our_tmpf_so
);
5348 errstr
= gf_pipe(gc
, pc
);
5349 gf_clear_so_readc(*so
);
5350 gf_clear_so_writec(our_tmpf_so
);
5352 /* tell gf_filter to read from our_tmpf_so instead of *so */
5353 readthis_so
= our_tmpf_so
;
5356 errstr
= "Can't create space for temporary file.";
5362 if((tmp_so
= so_get(PicoText
, NULL
, EDIT_ACCESS
)) != NULL
){
5363 gf_set_so_writec(&pc
, tmp_so
);
5364 ps_global
->mangled_screen
= 1;
5371 if((fpipe
= open_system_pipe(cmd
, NULL
, NULL
,
5372 PIPE_NOSHELL
| PIPE_RESET
,
5373 0, pipe_callback
, pipe_report_error
)) != NULL
){
5374 if(close_system_pipe(&fpipe
, NULL
, pipe_callback
) == 0){
5376 /* now we undo the WRITE_FROM_LOCALE change in tmpf */
5377 if((tmpf_so
= so_get(FileStar
, tmpf
, READ_ACCESS
|READ_FROM_LOCALE
)) != NULL
){
5378 gf_set_so_readc(&gc
, tmpf_so
);
5380 errstr
= gf_pipe(gc
, pc
);
5381 gf_clear_so_readc(tmpf_so
);
5385 errstr
= "Can't open temp file filter wrote.";
5388 errstr
= "Filter command returned error.";
5391 errstr
= "Can't exec filter text.";
5394 errstr
= gf_filter(cmd
, key
? filter_session_key() : NULL
,
5395 readthis_so
, pc
, NULL
, 0, 0,
5399 so_give(&our_tmpf_so
);
5401 gf_clear_so_writec(tmp_so
);
5406 * Can't really be using stdout, so don't print message that
5407 * gets printed in the else. Ideally the program being called
5408 * will wait after showing the message, we might want to look
5409 * into doing the waiting in console based apps... or not.
5415 fprintf(stdout
, "\r\n%s Hit return to continue.", errstr
);
5417 while((ch
= read_char(300)) != ctrl('M')
5418 && ch
!= NO_OP_IDLE
)
5422 #endif /* _WINDOWS */
5423 BODY
*b
= (body
->type
== TYPEMULTIPART
)
5424 ? &body
->nested
.part
->body
: body
;
5426 *old
= *so
; /* save old so */
5427 *so
= tmp_so
; /* return new one */
5428 (*so
)->attr
= copy_parameters((*old
)->attr
);
5431 * If the command said it would return new MIME
5432 * mime type data, check it out...
5435 char buf
[MAILTMPLEN
], *s
;
5438 if((fp
= our_fopen(mtf
, "rb")) != NULL
){
5439 if(fgets(buf
, sizeof(buf
), fp
)
5440 && !struncmp(buf
, "content-", 8)
5441 && (s
= strchr(buf
+8, ':'))){
5442 BODY
*nb
= mail_newbody();
5444 for(*s
++ = '\0'; *s
== ' '; s
++)
5447 rfc822_parse_content_header(nb
,
5448 (char *) ucase((unsigned char *) buf
+8),s
);
5449 if(nb
->type
== TYPETEXT
5452 || strucmp(b
->subtype
, nb
->subtype
))){
5454 fs_give((void **) &b
->subtype
);
5456 b
->subtype
= nb
->subtype
;
5459 mail_free_body_parameter(&b
->parameter
);
5460 b
->parameter
= nb
->parameter
;
5461 nb
->parameter
= NULL
;
5462 mail_free_body_parameter(&nb
->parameter
);
5465 mail_free_body(&nb
);
5473 * Reevaluate the encoding in case form's changed...
5475 b
->encoding
= ENCOTHER
;
5476 set_mime_type_by_grope(b
);
5483 errstr
= "Can't create space for filtered text.";
5486 fs_give((void **)&cmd
);
5493 fs_give((void **)&tmpf
);
5498 fs_give((void **) &mtf
);
5502 if(name_file_size(resultf
) > 0L)
5503 display_output_file(resultf
, "Filter", NULL
, DOF_BRIEF
);
5504 our_unlink(resultf
);
5505 fs_give((void **)&resultf
);
5511 q_status_message1(SM_ORDER
| SM_DING
, 3, 6, _("Problem filtering: %s"),
5513 dprint((1, "Filter FAILED: %s\n",
5514 errstr
? errstr
: "?"));
5517 return(errstr
== NULL
);
5521 /*----------------------------------------------------------------------
5522 Copy the newsgroup name of the given mailbox into the given buffer
5529 pine_send_newsgroup_name(char *mailbox
, char *group_name
, size_t len
)
5533 if(*mailbox
== '#'){ /* Strip the leading "#news." */
5534 strncpy(group_name
, mailbox
+ 6, len
-1);
5535 group_name
[len
-1] = '\0';
5537 else if(mail_valid_net_parse(mailbox
, &mb
)){
5538 pine_send_newsgroup_name(mb
.mailbox
, group_name
, len
);
5545 /*----------------------------------------------------------------------
5546 Generate and send a message back to the pine development team
5553 phone_home(char *addr
)
5555 char tmp
[MAX_ADDRESS
];
5559 outgoing
= mail_newenvelope();
5560 if(!addr
|| !strindex(addr
, '@')){
5561 snprintf(addr
= tmp
, sizeof(tmp
), "alpine%s@%s", PHONE_HOME_VERSION
, PHONE_HOME_HOST
);
5562 tmp
[sizeof(tmp
)-1] = '\0';
5565 rfc822_parse_adrlist(&outgoing
->to
, addr
, ps_global
->maildomain
);
5567 outgoing
->message_id
= generate_message_id();
5568 outgoing
->subject
= cpystr("Document Request");
5569 outgoing
->from
= phone_home_from();
5571 body
= mail_newbody();
5572 body
->type
= TYPETEXT
;
5574 if((body
->contents
.text
.data
= (void *)so_get(PicoText
,NULL
,EDIT_ACCESS
)) != NULL
){
5575 so_puts((STORE_S
*)body
->contents
.text
.data
, "Document request: ");
5576 so_puts((STORE_S
*)body
->contents
.text
.data
, "Alpine-");
5577 so_puts((STORE_S
*)body
->contents
.text
.data
, ALPINE_VERSION
);
5578 if(ps_global
->first_time_user
)
5579 so_puts((STORE_S
*)body
->contents
.text
.data
, " for New Users");
5581 if(ps_global
->VAR_INBOX_PATH
&& ps_global
->VAR_INBOX_PATH
[0] == '{')
5582 so_puts((STORE_S
*)body
->contents
.text
.data
, " and IMAP");
5584 if(ps_global
->VAR_NNTP_SERVER
&& ps_global
->VAR_NNTP_SERVER
[0]
5585 && ps_global
->VAR_NNTP_SERVER
[0][0])
5586 so_puts((STORE_S
*)body
->contents
.text
.data
, " and NNTP");
5588 (void) pine_simple_send(outgoing
, &body
, NULL
,NULL
,NULL
,NULL
, SS_NULLRP
);
5590 q_status_message(SM_ORDER
, 1, 3, "Thank you for being counted!");
5593 q_status_message(SM_ORDER
| SM_DING
, 3, 4,
5594 "Problem creating space for message text.");
5596 mail_free_envelope(&outgoing
);
5597 pine_free_body(&body
);
5602 /*----------------------------------------------------------------------
5603 Set up fields for passing to pico. Assumes first text part is
5604 intended to be passed along for editing, and is in the form of
5605 of a storage object brought into existence sometime before pico_send().
5608 outgoing2strings(METAENV
*header
, struct mail_bodystruct
*bod
, void **text
,
5609 PATMT
**pico_a
, int from_bounce
)
5614 * SIMPLIFYING ASSUMPTION #37: the first TEXT part's storage object
5615 * is guaranteed to be of type PicoText!
5617 if(bod
->type
== TYPETEXT
){
5618 *text
= so_text((STORE_S
*) bod
->contents
.text
.data
);
5620 /* mark storage object as user edited */
5622 (void) so_attr((STORE_S
*) bod
->contents
.text
.data
, "edited", "1");
5624 else if(bod
->type
== TYPEMULTIPART
){
5627 char *type
, *name
, *p
;
5631 * We used to jump out the window if the first part wasn't text,
5632 * but that may not be the case when bouncing a message with
5633 * a leading non-text segment. So, IT'S UNDERSTOOD that the
5634 * contents of the first part to send is still ALWAYS in a
5635 * PicoText storage object, *AND* if that object doesn't contain
5636 * data of type text, then it must contain THE ENCODED NON-TEXT
5637 * DATA of the piece being sent.
5639 * It's up to the programmer to make sure that such a message is
5640 * sent via pine_simple_send and never get to the composer via
5645 *text
= so_text((STORE_S
*) bod
->nested
.part
->body
.contents
.text
.data
);
5647 /* mark storage object as user edited */
5649 (void) so_attr((STORE_S
*) bod
->nested
.part
->body
.contents
.text
.data
, "edited", "1");
5652 * If we already had a list, blast it now, so we can build a new
5653 * attachment list that reflects what's really there...
5656 free_attachment_list(pico_a
);
5659 /* Simplifyihg assumption #28e. (see cross reference)
5660 All parts in the body passed in here that are not already
5661 in the attachments list are added to the end of the attachments
5662 list. Attachment items not in the body list will be taken care
5663 of in strings2outgoing, but they are unlikey to occur
5666 for(part
= bod
->nested
.part
->next
; part
!= NULL
; part
= part
->next
) {
5667 /* Already in list? */
5669 *ppa
&& strcmp((*ppa
)->id
, part
->body
.id
);
5670 ppa
= &(*ppa
)->next
)
5673 if(!*ppa
){ /* Not in the list! append it... */
5674 *ppa
= (PATMT
*)fs_get(sizeof(PATMT
));
5676 if(part
->body
.description
){
5680 len
= 4*strlen(part
->body
.description
)+1;
5681 p
= (char *)fs_get(len
*sizeof(char));
5682 if(rfc1522_decode_to_utf8((unsigned char *)p
,
5683 len
, part
->body
.description
) == (unsigned char *) p
){
5684 (*ppa
)->description
= p
;
5687 fs_give((void **)&p
);
5688 (*ppa
)->description
= cpystr(part
->body
.description
);
5692 (*ppa
)->description
= cpystr("");
5694 type
= type_desc(part
->body
.type
, part
->body
.subtype
,
5695 part
->body
.parameter
, NULL
, 0);
5698 * If we can find a "name" parm, display that too...
5700 if((name
= parameter_val(part
->body
.parameter
, "name")) != NULL
){
5701 /* Convert any [ or ]'s the name contained */
5702 for(p
= name
; *p
; p
++)
5713 (*ppa
)->filename
= fs_get(strlen(type
) + name_l
+ 5);
5715 snprintf((*ppa
)->filename
, strlen(type
) + name_l
+ 5, "[%s%s%s]", type
,
5716 name
? ": " : "", name
? name
: "");
5717 (*ppa
)->filename
[strlen(type
) + name_l
+ 5 - 1] = '\0';
5720 fs_give((void **) &name
);
5722 (*ppa
)->flags
= A_FLIT
;
5723 (*ppa
)->size
= cpystr(byte_string(
5724 send_body_size(&part
->body
)));
5726 part
->body
.id
= generate_message_id();
5728 (*ppa
)->id
= cpystr(part
->body
.id
);
5729 (*ppa
)->next
= NULL
;
5736 /*------------------------------------------------------------------
5737 Malloc strings to pass to composer editor because it expects
5738 such strings so it can realloc them
5739 -----------------------------------------------------------------*/
5741 * turn any address fields into text strings
5744 * SIMPLIFYING ASSUMPTION #116: all header strings are understood
5745 * NOT to be RFC1522 decoded. Said differently, they're understood
5746 * to be RFC1522 ENCODED as necessary. The intent is to preserve
5747 * original charset tagging as far into the compose/send pipe as
5750 for(pf
= header
->local
; pf
&& pf
->name
; pf
= pf
->next
)
5758 pf
->scratch
= addr_list_string(*pf
->addr
, NULL
, 1);
5761 * Scan for and fix-up patently bogus fields.
5763 * NOTE: collaboration with this code and what's done in
5764 * reply.c:reply_cp_addr to package up the bogus stuff
5767 for(p
= pf
->scratch
; (p
= strstr(p
, "@" RAWFIELD
)); )
5769 if(*t
== '&'){ /* find "leading" token */
5773 * Rfc822_cat has been changed so that it now quotes
5774 * this sometimes. So we have to look out for quotes
5775 * which confuse the decoder. It was only quoting
5776 * because we were putting \r \n in the input, I think.
5778 if(t
> pf
->scratch
&& t
[-1] == '\"' && p
[-1] == '\"')
5779 t
[-1] = p
[-1] = ' ';
5781 *t
++ = ' '; /* replace token */
5782 *p
= '\0'; /* tie off string */
5783 u
= rfc822_base64((unsigned char *) t
,
5784 (unsigned long) strlen(t
),
5785 (unsigned long *) &l
);
5789 replacelen
= strlen(t
);
5790 *p
= '@'; /* restore 'p' */
5791 rplstr(p
, strlen(p
), 12, ""); /* clear special token */
5792 rplstr(t
, strlen(u
)-replacelen
+1, replacelen
, u
);
5794 fs_give((void **) &u
);
5797 HE(pf
)->start_here
= 1;
5801 else if(t
== pf
->scratch
)
5804 removing_leading_white_space(pf
->scratch
);
5809 * Replace control characters with ^C notation, unless
5810 * some conditions are met (see istrncpy).
5811 * If user doesn't edit, then we switch back to the
5812 * original version. If user does edit, then all bets
5815 iutf8ncpy((char *)tmp_20k_buf
, pf
->scratch
, SIZEOF_20KBUF
-1);
5816 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
5817 if((l
=strlen((char *)tmp_20k_buf
)) > strlen(pf
->scratch
)){
5818 fs_give((void **)&pf
->scratch
);
5819 pf
->scratch
= (char *)fs_get((l
+1) * sizeof(char));
5822 strncpy(pf
->scratch
, (char *)tmp_20k_buf
, l
+1);
5833 src
= pf
->scratch
? pf
->scratch
5834 : (*pf
->text
) ? *pf
->text
: "";
5836 len
= 4*strlen(src
)+1;
5837 p
= (char *)fs_get(len
* sizeof(char));
5838 if(rfc1522_decode_to_utf8((unsigned char *)p
, len
, src
) == (unsigned char *) p
){
5840 fs_give((void **)&pf
->scratch
);
5845 fs_give((void **)&p
);
5847 pf
->scratch
= cpystr(src
);
5854 * Replace control characters with ^C notation, unless
5855 * some conditions are met (see istrncpy).
5856 * If user doesn't edit, then we switch back to the
5857 * original version. If user does edit, then all bets
5860 iutf8ncpy((char *)tmp_20k_buf
, pf
->scratch
, SIZEOF_20KBUF
-1);
5861 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
5862 if((l
=strlen((char *)tmp_20k_buf
)) > strlen(pf
->scratch
)){
5863 fs_give((void **)&pf
->scratch
);
5864 pf
->scratch
= (char *)fs_get((l
+1) * sizeof(char));
5867 strncpy(pf
->scratch
, (char *)tmp_20k_buf
, l
+1);
5879 /*----------------------------------------------------------------------
5880 Restore fields returned from pico to form useful to sending
5884 strings2outgoing(METAENV
*header
, struct mail_bodystruct
**bod
, PATMT
*attach
, int flow_it
)
5889 we_cancel
= busy_cue(NULL
, NULL
, 1);
5892 * turn any local address strings into address lists
5894 for(pf
= header
->local
; pf
&& pf
->name
; pf
= pf
->next
)
5896 char *the_address
= NULL
;
5900 removing_trailing_white_space(pf
->scratch
);
5902 if((the_address
|| *pf
->scratch
) && pf
->addr
){
5903 ADDRESS
*new_addr
= NULL
;
5904 static char *fakedomain
= "@";
5907 the_address
= pf
->scratch
;
5909 rfc822_parse_adrlist(&new_addr
, the_address
,
5910 (F_ON(F_COMPOSE_REJECTS_UNQUAL
, ps_global
))
5911 ? fakedomain
: ps_global
->maildomain
);
5912 mail_free_address(pf
->addr
); /* free old addrs */
5913 *pf
->addr
= new_addr
; /* assign new addr */
5916 mail_free_address(pf
->addr
); /* free old addrs */
5922 fs_give((void **)pf
->text
);
5925 *pf
->text
= cpystr(pf
->scratch
);
5934 fs_give((void **)&pf
->scratch
); /* free now useless text */
5937 create_message_body(bod
, attach
, flow_it
);
5940 cancel_busy_cue(-1);
5944 /*----------------------------------------------------------------------
5946 The head of the body list here is always either TEXT or MULTIPART. It may be
5947 changed from TEXT to MULTIPART if there are attachments to be added
5948 and it is not already multipart.
5951 create_message_body(struct mail_bodystruct
**b
, PATMT
*attach
, int flow_it
)
5955 BODY
*tmp_body
, *text_body
= NULL
;
5956 void *file_contents
;
5960 TIME_STAMP("create_body start.", 1);
5962 * if conditions are met short circuit MIME wrapping
5964 if((*b
)->type
!= TYPEMULTIPART
&& !attach
){
5966 /* only override assigned encoding if it might need upgrading */
5967 if((*b
)->type
== TYPETEXT
&& (*b
)->encoding
== ENC7BIT
)
5968 (*b
)->encoding
= ENCOTHER
;
5970 create_message_body_text(*b
, flow_it
);
5972 if(F_ON(F_COMPOSE_ALWAYS_DOWNGRADE
, ps_global
)
5973 || !((*b
)->encoding
== ENC8BIT
5974 || (*b
)->encoding
== ENCBINARY
)){
5975 TIME_STAMP("create_body end.", 1);
5978 else /* protect 8bit in multipart */
5982 if((*b
)->type
== TYPETEXT
) {
5983 /*-- Current type is text, but there are attachments to add --*/
5984 /*-- Upgrade to a TYPEMULTIPART --*/
5985 tmp_body
= (BODY
*)mail_newbody();
5986 tmp_body
->type
= TYPEMULTIPART
;
5987 tmp_body
->nested
.part
= mail_newbody_part();
5990 * Why do we do this?
5991 * The problem is that base64 or quoted-printable encoding is
5992 * sensitive to having random data appended to it's end. If
5993 * we use a single part TEXT message and something in between
5994 * us and the end appends advertising without adjusting for
5995 * the encoding, the message is screwed up. So we wrap the
5996 * text part inside a multipart and then the appended data
5997 * will come after the boundary.
5999 * We wish we could do this on the way out the door in a
6000 * child of post_rfc822_output because at that point we know
6001 * the character set and the encoding being used. For example,
6002 * iso-2022-jp is an encoding that is not sensitive to data
6003 * appended to the end, so it wouldn't need to be wrapped.
6004 * We could conceivably have post_rfc822_body inspect the
6005 * body and change it before doing the output. It would work
6006 * but would be very fragile. We'd be passed a body from
6007 * c-client to output and instead of just doing the output
6008 * we'd change the body and then output it. Not worth it
6009 * since the multipart wrapping is completely correct for
6010 * MIME-aware mailers.
6012 (void) copy_body(&(tmp_body
->nested
.part
->body
), *b
);
6013 /* move contents which were NOT copied */
6014 tmp_body
->nested
.part
->body
.contents
.text
.data
= (*b
)->contents
.text
.data
;
6015 (*b
)->contents
.text
.data
= NULL
;
6018 tmp_body
->nested
.part
->body
= **b
;
6020 (*b
)->subtype
= (*b
)->id
= (*b
)->description
= NULL
;
6021 (*b
)->parameter
= NULL
;
6022 (*b
)->contents
.text
.data
= NULL
;
6030 /*-- Now type must be MULTIPART with first part text --*/
6031 (*b
)->nested
.part
->body
.encoding
= ENCOTHER
;
6032 create_message_body_text(&((*b
)->nested
.part
->body
), flow_it
);
6035 /*------ Go through the parts list remove those to be deleted -----*/
6036 for(pp
= &(*b
)->nested
.part
->next
; *pp
;){
6037 for(pa
= attach
; pa
&& (*pp
)->body
.id
; pa
= pa
->next
)
6038 /* already existed? */
6039 if(pa
->id
&& strcmp(pa
->id
, (*pp
)->body
.id
) == 0){
6040 char *orig_descp
= NULL
, *cs
= NULL
;
6043 * decode original to see if it matches what was decoded
6044 * when we sent it in.
6047 if((*pp
)->body
.description
)
6048 orig_descp
= (char *) rfc1522_decode_to_utf8((unsigned char *) tmp_20k_buf
,
6049 SIZEOF_20KBUF
, (*pp
)->body
.description
);
6051 if(!(*pp
)->body
.description
/* update description? */
6052 || (pa
->description
&& strcmp(pa
->description
, orig_descp
))){
6053 if((*pp
)->body
.description
)
6054 fs_give((void **) &(*pp
)->body
.description
);
6056 /* encoding happens as msg text is written */
6057 (*pp
)->body
.description
= cpystr(pa
->description
);
6061 fs_give((void **) &cs
);
6067 p
= *pp
; /* prepare to zap *pp */
6068 *pp
= p
->next
; /* pull next one in list up */
6069 p
->next
= NULL
; /* tie off removed node */
6071 pine_free_body_data(&p
->body
); /* clean up contained data */
6072 mail_free_body_part(&p
); /* free up the part */
6078 /*---------- Now add any new attachments ---------*/
6079 for(p
= (*b
)->nested
.part
; p
->next
!= NULL
; p
= p
->next
);
6080 for(pa
= attach
; pa
!= NULL
; pa
= pa
->next
) {
6082 continue; /* Has an ID, it's old */
6085 * the idea is handle ALL attachments as open FILE *'s. Actual
6086 * encoding and such is handled at the time the message
6087 * is shoved into the mail slot or written to disk...
6089 * Also, we never unlink a file, so it's up to whoever opens
6090 * it to deal with tmpfile issues.
6092 if((file_contents
= (void *)so_get(FileStar
, pa
->filename
,
6093 READ_ACCESS
)) == NULL
){
6094 q_status_message2(SM_ORDER
| SM_DING
, 3, 4,
6095 _("Error \"%s\", couldn't attach file \"%s\""),
6096 error_description(errno
), pa
->filename
);
6097 display_message('x');
6101 p
->next
= mail_newbody_part();
6103 p
->body
.id
= generate_message_id();
6104 p
->body
.contents
.text
.data
= file_contents
;
6107 * Set type to unknown and let set_mime_type_by_* figure it out.
6108 * Always encode attachments we add as BINARY.
6110 p
->body
.type
= TYPEOTHER
;
6111 p
->body
.encoding
= ENCBINARY
;
6112 p
->body
.size
.bytes
= name_file_size(pa
->filename
);
6113 if(!set_mime_type_by_extension(&p
->body
, pa
->filename
)){
6114 set_mime_type_by_grope(&p
->body
);
6115 set_charset_possibly_to_ascii(&p
->body
, ps_global
->keyboard_charmap
);
6118 so_release((STORE_S
*)p
->body
.contents
.text
.data
);
6120 if(pa
->description
) /* encoding happens when msg written */
6121 p
->body
.description
= cpystr(pa
->description
);
6123 /* Add name attribute for backward compatibility */
6124 for(parmp
= &p
->body
.parameter
; *parmp
; )
6125 if(!struncmp((*parmp
)->attribute
, "name", 4)
6126 && (!*((*parmp
)->attribute
+ 4)
6127 || *((*parmp
)->attribute
+ 4) == '*')){
6128 PARAMETER
*free_me
= *parmp
;
6129 *parmp
= (*parmp
)->next
;
6130 free_me
->next
= NULL
;
6131 mail_free_body_parameter(&free_me
);
6134 parmp
= &(*parmp
)->next
;
6136 set_parameter(parmp
, "name",
6138 ? ((lc
= last_cmpnt(pa
->filename
)) ? lc
: pa
->filename
)
6141 /* Then set the Content-Disposition ala RFC1806 */
6142 if(!p
->body
.disposition
.type
){
6143 p
->body
.disposition
.type
= cpystr("attachment");
6144 for(parmp
= &p
->body
.disposition
.parameter
; *parmp
; )
6145 if(!struncmp((*parmp
)->attribute
, "filename", 4)
6146 && (!*((*parmp
)->attribute
+ 4)
6147 || *((*parmp
)->attribute
+ 4) == '*')){
6148 PARAMETER
*free_me
= *parmp
;
6149 *parmp
= (*parmp
)->next
;
6150 free_me
->next
= NULL
;
6151 mail_free_body_parameter(&free_me
);
6154 parmp
= &(*parmp
)->next
;
6156 set_parameter(parmp
, "filename",
6158 ? ((lc
= last_cmpnt(pa
->filename
)) ? lc
: pa
->filename
)
6163 pa
->id
= cpystr(p
->body
.id
);
6167 * Now, if this multipart has but one text piece (that is, no
6168 * attachments), then downgrade from a composite type to a discrete
6169 * text/plain message if CTE is not 8bit.
6171 if(!(*b
)->nested
.part
->next
6172 && (*b
)->nested
.part
->body
.type
== TYPETEXT
6173 && (F_ON(F_COMPOSE_ALWAYS_DOWNGRADE
, ps_global
)
6174 || !((*b
)->nested
.part
->body
.encoding
== ENC8BIT
6175 || (*b
)->nested
.part
->body
.encoding
== ENCBINARY
))){
6176 /* Clone the interesting body part */
6177 tmp_body
= mail_newbody();
6178 *tmp_body
= (*b
)->nested
.part
->body
;
6179 /* and rub out what we don't want cleaned up when it's free'd */
6180 mail_initbody(&(*b
)->nested
.part
->body
);
6186 TIME_STAMP("create_body end.", 1);
6191 * Fill in text BODY part's structure
6195 create_message_body_text(struct mail_bodystruct
*b
, int flow_it
)
6197 set_mime_type_by_grope(b
);
6198 if(F_OFF(F_QUELL_FLOWED_TEXT
, ps_global
)
6199 && F_OFF(F_STRIP_WS_BEFORE_SEND
, ps_global
)
6201 set_parameter(b
? &b
->parameter
: NULL
, "format", "flowed");
6208 * free_attachment_list - free attachments in given list
6211 free_attachment_list(PATMT
**alist
)
6215 while(alist
&& *alist
){ /* pointer pointing to something */
6216 leading
= (*alist
)->next
;
6217 if((*alist
)->description
)
6218 fs_give((void **)&(*alist
)->description
);
6220 if((*alist
)->filename
){
6221 if((*alist
)->flags
& A_TMP
)
6222 if(our_unlink((*alist
)->filename
) < 0)
6223 dprint((1, "-- Can't unlink(%s): %s\n",
6224 (*alist
)->filename
? (*alist
)->filename
: "?",
6225 error_description(errno
)));
6227 fs_give((void **)&(*alist
)->filename
);
6231 fs_give((void **)&(*alist
)->size
);
6234 fs_give((void **)&(*alist
)->id
);
6236 fs_give((void **)alist
);
6244 set_body_size(struct mail_bodystruct
*b
)
6249 we_cancel
= busy_cue(NULL
, NULL
, 1);
6250 so_seek((STORE_S
*)b
->contents
.text
.data
, 0L, 0);
6252 while(so_readc(&c
, (STORE_S
*)b
->contents
.text
.data
))
6256 cancel_busy_cue(-1);
6261 * view_as_rich - set the rich_header flag
6263 * name - name of the header field
6264 * deflt - default value to return if user didn't set it
6266 * Note: if the user tries to turn them all off with "", then
6267 * we take that to mean default, since otherwise there is no
6268 * way to get to the headers.
6271 view_as_rich(char *name
, int deflt
)
6276 p
= ps_global
->VAR_COMP_HDRS
;
6279 for(; (q
= *p
) != NULL
; p
++){
6280 if(!struncmp(q
, name
, strlen(name
)))
6281 return 0; /* 0 means we *do* view it by default */
6284 return 1; /* 1 means it starts out hidden */
6291 * background_posting - return whether or not we're already in the process
6295 background_posting(int gripe
)
6297 if(ps_global
->post
){
6299 q_status_message(SM_ORDER
|SM_DING
, 3, 3,
6300 _("Can't post while posting!"));
6308 /*----------------------------------------------------------------------
6309 Validate the given subject relative to any news groups.
6313 Returns: always returns 1, but also returns error if
6316 valid_subject(char *given
, char **expanded
, char **error
, BUILDER_ARG
*fcc
, int *mangled
)
6318 struct headerentry
*hp
;
6321 *expanded
= cpystr(given
);
6325 * Now look for any header entry we passed to pico that has to do
6326 * with news. If there's no subject, gripe.
6328 for(hp
= pbf
->headents
; hp
->prompt
; hp
++)
6329 if(hp
->help
== h_composer_news
){
6330 if(hp
->hd_text
->text
[0] && !*given
)
6332 _("News postings MUST have a subject! Please add one!"));
6343 * This is the build_address used by the composer to check for an address
6346 * Args: to -- the passed in line to parse
6347 * full_to -- Address of a pointer to return the full address in.
6348 * This will be allocated here and freed by the caller.
6349 * error -- Address of a pointer to return an error message in.
6350 * This will be allocated here and freed by the caller.
6351 * barg -- Address of a pointer to return the fcc in is in
6352 * fcc->tptr. It will have already been allocated by the
6353 * caller but we may free it and reallocate if we wish.
6354 * Caller will free it.
6356 * Result: 0 is returned if address was OK,
6357 * -1 if address wasn't OK.
6359 * Side effect: Can flush addrbook entry cache entries so they need to be
6360 * re-fetched afterwords.
6363 build_address(char *to
, char **full_to
, char **error
, BUILDER_ARG
*barg
, int *mangled
)
6366 int ret_val
, no_repo
= 0, *save_nesting_level
;
6368 PrivateTop
*pt
= NULL
;
6369 PrivateAffector
*af
= NULL
;
6370 char *fcc_local
= NULL
;
6371 jmp_buf save_jmp_buf
;
6373 dprint((5, "- build_address - (%s)\n", to
? to
: "nul"));
6375 /* check to see if to string is empty to avoid work */
6376 for(p
= to
; p
&& *p
&& isspace((unsigned char)*p
); p
++)
6381 *full_to
= cpystr(to
? to
: ""); /* because pico does a strcmp() */
6387 *full_to
= (char *)NULL
;
6390 *error
= (char *)NULL
;
6392 /* No guarantee cursor or status line is how we saved it */
6394 mark_status_unknown();
6396 if(ps_global
->remote_abook_validity
> 0 &&
6397 adrbk_check_and_fix_all(ab_nesting_level
== 0, 0, 0) && mangled
)
6398 *mangled
|= BUILDER_SCREEN_MANGLED
;
6401 * If we end up jumping back here because somebody else changed one of
6402 * our addrbooks out from underneath us, we may well leak some memory.
6403 * That's probably ok since this will be very rare.
6405 * The reason for the memcpy of the jmp_buf is that we may actually
6406 * be indirectly calling this function from within the address book.
6407 * For example, we may be in the address book screen and then run
6408 * the ComposeTo command which puts us in the composer, then we call
6409 * build_address from there which resets addrbook_changed_unexpectedly.
6410 * Once we leave build_address we need to reset addrbook_changed_un...
6411 * because this position on the stack will no longer be valid.
6412 * Same is true of the other setjmp's in this file which are wrapped
6415 save_nesting_level
= cpyint(ab_nesting_level
);
6416 memcpy(save_jmp_buf
, addrbook_changed_unexpectedly
, sizeof(jmp_buf));
6417 if(setjmp(addrbook_changed_unexpectedly
)){
6423 *error
= (char *)NULL
;
6425 if(full_to
&& *full_to
)
6426 fs_give((void **)full_to
);
6428 q_status_message(SM_ORDER
, 3, 5, "Resetting address book...");
6430 "RESETTING address book... build_address(%s)!\n", to
? to
: "?"));
6432 ab_nesting_level
= *save_nesting_level
;
6438 ret_val
= build_address_internal(bldto
, full_to
, error
,
6439 barg
? &fcc_local
: NULL
,
6440 &no_repo
, NULL
, save_and_restore
,
6443 if(save_nesting_level
)
6444 fs_give((void **)&save_nesting_level
);
6447 * Have to rfc1522_decode the full_to string before sending it back.
6449 if(full_to
&& *full_to
){
6453 len
= 4*strlen(*full_to
)+1;
6454 q
= (char *)fs_get(len
* sizeof(char));
6455 p
= (char *)rfc1522_decode_to_utf8((unsigned char *)q
, len
, *full_to
);
6457 /* p == q means that decoding happened, p is decoded *full_to */
6459 fs_give((void **)full_to
);
6463 fs_give((void **)&q
);
6469 /* Pt will point to headents[Fcc].bldr_private */
6471 if(barg
&& barg
->aff
)
6472 pt
= (PrivateTop
*)(*barg
->aff
);
6475 * If *barg->aff is set, that means fcc was set from a list
6476 * during some previous builder call.
6477 * If the current To line contains the old expansion as a prefix, then
6478 * we should leave things as they are. In order to decide that,
6479 * we look at a hash value computed from the strings.
6481 if(pt
&& (af
=pt
->affector
) && af
->who
== BP_To
){
6485 if(len
>= af
->cksumlen
){
6488 save
= to
[af
->cksumlen
];
6489 to
[af
->cksumlen
] = '\0';
6490 csum
= line_hash(to
);
6491 to
[af
->cksumlen
] = save
;
6494 csum
= af
->cksumval
+ 1; /* something not equal to cksumval */
6499 (pt
->affector
->who
== BP_To
&& csum
!= pt
->affector
->cksumval
)){
6501 /* replace fcc value */
6503 fs_give((void **)&barg
->tptr
);
6505 barg
->tptr
= fcc_local
;
6509 *barg
->aff
= (void *)fs_get(sizeof(PrivateTop
));
6510 pt
= (PrivateTop
*)(*barg
->aff
);
6511 memset((void *)pt
, 0, sizeof(PrivateTop
));
6517 (PrivateAffector
*)fs_get(sizeof(PrivateAffector
));
6521 af
->cksumlen
= strlen(((full_to
&& *full_to
)
6523 af
->cksumval
= line_hash(((full_to
&& *full_to
)
6528 * If result is reproducible, we don't keep track here.
6531 fs_give((void **)&pt
->affector
);
6536 fs_give((void **)&fcc_local
); /* unused in this case */
6539 /* This is so pico will erase the old message */
6540 if(error
!= NULL
&& *error
== NULL
)
6541 *error
= cpystr("");
6543 memcpy(addrbook_changed_unexpectedly
, save_jmp_buf
, sizeof(jmp_buf));
6544 flush_status_messages(1);
6550 * This is the builder used by the composer for the Lcc line.
6552 * Args: lcc -- the passed in Lcc line to parse
6553 * full_lcc -- Address of a pointer to return the full address in.
6554 * This will be allocated here and freed by the caller.
6555 * error -- Address of a pointer to return an error message in.
6556 * This is not allocated so should not be freed by the caller.
6557 * barg -- This is a pointer to text for affected entries which
6558 * we may be changing. The first one in the list is the
6559 * To entry. We may put the name of the list in empty
6560 * group syntax form there (like List Name: ;).
6561 * The second one in the list is the fcc field.
6562 * The tptr members already point to text allocated in the
6563 * caller. We may free and reallocate here, caller will
6564 * free the result in any case.
6566 * Result: 0 is returned if address was OK,
6567 * -1 if address wasn't OK.
6569 * Side effect: Can flush addrbook entry cache entries so they need to be
6570 * re-fetched afterwords.
6573 build_addr_lcc(char *lcc
, char **full_lcc
, char **error
, BUILDER_ARG
*barg
, int *mangled
)
6576 no_repo
= 0; /* fcc or lcc not reproducible */
6577 int *save_nesting_level
;
6579 PrivateTop
*pt
= NULL
;
6580 PrivateAffector
*af
= NULL
;
6585 jmp_buf save_jmp_buf
;
6587 dprint((5, "- build_addr_lcc - (%s)\n", lcc
? lcc
: "nul"));
6589 /* check to see if to string is empty to avoid work */
6590 for(p
= lcc
; p
&& *p
&& isspace((unsigned char)*p
); p
++)
6595 *full_lcc
= cpystr(lcc
? lcc
: ""); /* because pico does a strcmp() */
6601 *error
= (char *)NULL
;
6603 if(ps_global
->remote_abook_validity
> 0 &&
6604 adrbk_check_and_fix_all(ab_nesting_level
== 0, 0, 0) && mangled
)
6605 *mangled
|= BUILDER_SCREEN_MANGLED
;
6608 * If we end up jumping back here because somebody else changed one of
6609 * our addrbooks out from underneath us, we may well leak some memory.
6610 * That's probably ok since this will be very rare.
6612 save_nesting_level
= cpyint(ab_nesting_level
);
6613 memcpy(save_jmp_buf
, addrbook_changed_unexpectedly
, sizeof(jmp_buf));
6614 if(setjmp(addrbook_changed_unexpectedly
)){
6621 *error
= (char *)NULL
;
6623 if(full_lcc
&& *full_lcc
)
6624 fs_give((void **)full_lcc
);
6626 q_status_message(SM_ORDER
, 3, 5, "Resetting address book...");
6628 "RESETTING address book... build_address(%s)!\n", lcc
? lcc
: "?"));
6630 ab_nesting_level
= *save_nesting_level
;
6635 bldlcc
.arg
.str
= lcc
;
6638 * To is first affected_entry and Fcc is second.
6639 * The conditional stuff for the fcc argument says to only change the
6640 * fcc if the fcc pointer is passed in non-null, and the To pointer
6641 * is also non-null. If they are null, that means they've already been
6642 * entered (are sticky). We don't affect fcc if either fcc or To has
6645 ret_val
= build_address_internal(bldlcc
,
6648 (barg
&& barg
->next
&& barg
->next
->tptr
&& barg
->tptr
)
6649 ? &fcc_local
: NULL
,
6651 (barg
&& barg
->tptr
) ? &to
: NULL
,
6652 save_and_restore
, 0, mangled
);
6655 if(save_nesting_level
)
6656 fs_give((void **)&save_nesting_level
);
6658 /* full_lcc is what ends up in the Lcc: line */
6659 if(full_lcc
&& *full_lcc
){
6663 * Have to rfc1522_decode the full_lcc string before sending it back.
6665 len
= 4*strlen(*full_lcc
)+1;
6666 p
= (char *)fs_get(len
* sizeof(char));
6667 if(rfc1522_decode_to_utf8((unsigned char *)p
, len
, *full_lcc
) == (unsigned char *)p
){
6668 fs_give((void **)full_lcc
);
6672 fs_give((void **)&p
);
6675 /* to is what ends up in the To: line */
6681 * Have to rfc1522_decode the full_to string before sending it back.
6683 len
= 4*strlen(to
)+1;
6684 p
= (char *)fs_get(len
* sizeof(char));
6686 if(rfc1522_decode_to_utf8((unsigned char *)p
, len
, to
) == (unsigned char *)p
){
6688 * If the caller wants us to try to preserve the charset
6689 * information (they set aff) we copy it into encoded->etext.
6690 * We don't have to worry about pasting together pieces of
6691 * etext like we do in build_address because whenever the
6692 * Lcc line is setting the To line it will be setting the
6693 * whole line, not modifying it.
6694 * Pt will point to headents[To].bldr_private.
6696 if(barg
&& barg
->aff
){
6697 pt
= (PrivateTop
*)(*barg
->aff
);
6700 *barg
->aff
= (void *)fs_get(sizeof(PrivateTop
));
6701 pt
= (PrivateTop
*)(*barg
->aff
);
6702 memset((void *)pt
, 0, sizeof(PrivateTop
));
6706 fs_give((void **)&to
);
6710 fs_give((void **)&p
);
6713 fs_give((void **)&dummy
);
6717 * This part is recording the fact that the To line was set to
6718 * what it is by entering something on the Lcc line. In particular,
6719 * if a list alias was entered here then the fullname of the list
6720 * goes in the To line. We save this affector information so that
6721 * we can tell it shouldn't be modified if we call build_addr_lcc
6722 * again unless we actually modified what's in the Lcc line so that
6723 * it doesn't start with the same thing. The problem we're solving
6724 * is that the contents of the Lcc line no longer look like the
6725 * list they were derived from.
6726 * Pt will point to headents[To].bldr_private.
6728 if(barg
&& barg
->aff
)
6729 pt
= (PrivateTop
*)(*barg
->aff
);
6731 if(pt
&& (af
=pt
->affector
) && af
->who
== BP_Lcc
){
6735 if(len
>= af
->cksumlen
){
6738 save
= lcc
[af
->cksumlen
];
6739 lcc
[af
->cksumlen
] = '\0';
6740 csum
= line_hash(lcc
);
6741 lcc
[af
->cksumlen
] = save
;
6744 csum
= af
->cksumval
+ 1; /* so they aren't equal */
6749 pt
->affector
->who
!= BP_Lcc
||
6750 (pt
->affector
->who
== BP_Lcc
&& csum
!= pt
->affector
->cksumval
)){
6752 /* replace to value */
6753 if(barg
->tptr
&& barg
->tptr
[0]){
6757 l
= strlen(barg
->tptr
) + strlen(to
? to
: "") + 2;
6758 t
= (char *)fs_get((l
+1) * sizeof(char));
6759 snprintf(t
, l
+1, "%s%s%s",
6761 (to
&& *to
) ? ", " : "",
6762 (to
&& *to
) ? to
: "");
6763 fs_give((void **)&barg
->tptr
);
6765 fs_give((void **)&to
);
6771 fs_give((void **)&barg
->tptr
);
6778 *barg
->aff
= (void *)fs_get(sizeof(PrivateTop
));
6779 pt
= (PrivateTop
*)(*barg
->aff
);
6780 memset((void *)pt
, 0, sizeof(PrivateTop
));
6786 (PrivateAffector
*)fs_get(sizeof(PrivateAffector
));
6790 af
->cksumlen
= strlen(((full_lcc
&& *full_lcc
)
6792 af
->cksumval
= line_hash(((full_lcc
&& *full_lcc
)
6797 * If result is reproducible, we don't keep track here.
6800 fs_give((void **)&pt
->affector
);
6805 fs_give((void **)&to
); /* unused in this case */
6812 * If *barg->next->aff is set, that means fcc was set from a list
6813 * during some previous builder call. If the current Lcc line
6814 * contains the old expansion as a prefix, then we should leave
6815 * things as they are. In order to decide that we look at a hash
6816 * value computed from the strings.
6817 * Pt will point to headents[Fcc].bldr_private
6820 if(barg
&& barg
->next
&& barg
->next
->aff
)
6821 pt
= (PrivateTop
*)(*barg
->next
->aff
);
6823 if(pt
&& (af
=pt
->affector
) && af
->who
== BP_Lcc
){
6827 if(len
>= af
->cksumlen
){
6830 save
= lcc
[af
->cksumlen
];
6831 lcc
[af
->cksumlen
] = '\0';
6832 csum
= line_hash(lcc
);
6833 lcc
[af
->cksumlen
] = save
;
6836 csum
= af
->cksumval
+ 1; /* something not equal to cksumval */
6841 pt
->affector
->who
!= BP_Lcc
||
6842 (pt
->affector
->who
== BP_Lcc
&& csum
!= pt
->affector
->cksumval
)){
6844 /* replace fcc value */
6845 if(barg
->next
->tptr
)
6846 fs_give((void **)&barg
->next
->tptr
);
6848 barg
->next
->tptr
= fcc_local
;
6850 if(barg
->next
->aff
){
6852 *barg
->next
->aff
= (void *)fs_get(sizeof(PrivateTop
));
6853 pt
= (PrivateTop
*)(*barg
->next
->aff
);
6854 memset((void *)pt
, 0, sizeof(PrivateTop
));
6860 (PrivateAffector
*)fs_get(sizeof(PrivateAffector
));
6864 af
->cksumlen
= strlen(((full_lcc
&& *full_lcc
)
6866 af
->cksumval
= line_hash(((full_lcc
&& *full_lcc
)
6871 * If result is reproducible, we don't keep track here.
6874 fs_give((void **)&pt
->affector
);
6879 fs_give((void **)&fcc_local
); /* unused in this case */
6883 if(error
!= NULL
&& *error
== NULL
)
6884 *error
= cpystr("");
6886 memcpy(addrbook_changed_unexpectedly
, save_jmp_buf
, sizeof(jmp_buf));
6887 flush_status_messages(0);
6892 /*----------------------------------------------------------------------
6893 Verify and canonicalize news groups names.
6894 Called from the message composer
6896 Args: given_group -- List of groups typed by user
6897 expanded_group -- pointer to point to expanded list, which will be
6898 allocated here and freed in caller. If this is
6899 NULL, don't attempt to validate.
6900 error -- pointer to store error message
6901 fcc -- pointer to point to fcc, which will be
6902 allocated here and freed in caller
6904 Returns: 0 if all is OK
6905 -1 if addresses weren't valid
6907 Test the given list of newstroups against those recognized by our nntp
6908 servers. Testing by actually trying to open the list is much cheaper, both
6909 in bandwidth and memory, than yanking the whole list across the wire.
6912 news_build(char *given_group
, char **expanded_group
, char **error
, BUILDER_ARG
*fcc
, int *mangled
)
6915 char *fccptr
= NULL
;
6917 if(fcc
&& fcc
->tptr
)
6918 fccptr
= cpystr(fcc
->tptr
);
6922 rv
= news_grouper(given_group
, expanded_group
, error
, &fccptr
, news_build_busy
);
6924 /* assign any new fcc to the BUILDER_ARG */
6928 if(fcc
->tptr
&& strcmp(fcc
->tptr
, fccptr
)){
6929 fs_give((void **) &fcc
->tptr
);
6936 fs_give((void **) &fccptr
);
6939 /* deal with any busy indicator */
6943 mark_status_dirty();
6944 display_message('x');
6946 *mangled
|= BUILDER_MESSAGE_DISPLAYED
;
6955 news_build_busy(void)
6957 news_busy_cue
= busy_cue("Validating newsgroup(s)", NULL
, 0);
6961 #if defined(DOS) || defined(OS2)
6963 /*----------------------------------------------------------------------
6964 Verify that the necessary pieces are around to allow for
6965 message sending under DOS
6967 Args: strict -- tells us if a remote stream is required before
6968 sending is permitted.
6970 The idea is to make sure pine knows enough to put together a valid
6971 from line. The things we MUST know are a user-id, user-domain and
6972 smtp server to dump the message off on. Typically these are
6973 provided in pine's configuration file, but if not, the user is
6979 char prompt
[100], answer
[80];
6984 * query for user name portion of address, use IMAP login
6987 if(!ps_global
->VAR_USER_ID
|| ps_global
->VAR_USER_ID
[0] == '\0'){
6989 int no_prompt_user_id
= 0;
6991 if(ps_global
->mail_stream
&& ps_global
->mail_stream
->mailbox
6992 && mail_valid_net_parse(ps_global
->mail_stream
->mailbox
, &mb
)
6994 strncpy(answer
, mb
.user
, sizeof(answer
)-1);
6995 answer
[sizeof(answer
)-1] = '\0';
6997 else if(F_ON(F_QUELL_USER_ID_PROMPT
, ps_global
)){
6998 /* no user-id prompting if set */
6999 no_prompt_user_id
= 1;
7001 if(!ps_global
->mail_stream
)
7002 do_broach_folder(ps_global
->inbox_name
,
7003 ps_global
->context_list
, NULL
, DB_INBOXWOCNTXT
);
7004 if(ps_global
->mail_stream
&& ps_global
->mail_stream
->mailbox
7005 && mail_valid_net_parse(ps_global
->mail_stream
->mailbox
, &mb
)
7007 strncpy(answer
, mb
.user
, sizeof(answer
)-1);
7008 answer
[sizeof(answer
)-1] = '\0';
7016 if(F_ON(F_QUELL_USER_ID_PROMPT
, ps_global
) && answer
[0]){
7017 /* No prompt, just assume mailbox login is user-id */
7018 no_prompt_user_id
= 1;
7022 snprintf(prompt
,sizeof(prompt
),_("User-id for From address : "));
7023 prompt
[sizeof(prompt
)-1] = '\0';
7026 while(!no_prompt_user_id
) {
7027 flags
= OE_APPEND_CURRENT
;
7028 rc
= optionally_enter(answer
,-FOOTER_ROWS(ps_global
),0,
7029 sizeof(answer
),prompt
,NULL
,help
,&flags
);
7034 help
= (help
== NO_HELP
) ? h_sticky_user_id
: NO_HELP
;
7042 if(rc
== 1 || (rc
== 0 && !answer
[0])) {
7043 q_status_message(SM_ORDER
, 3, 4,
7044 _("Send cancelled (User-id must be provided before sending)"));
7049 snprintf(prompt
, sizeof(prompt
), _("Preserve %.*s as \"user-id\" in PINERC"),
7050 sizeof(prompt
)-50, answer
);
7051 prompt
[sizeof(prompt
)-1] = '\0';
7052 if(ps_global
->blank_user_id
7053 && !no_prompt_user_id
7054 && want_to(prompt
, 'y', 'n', NO_HELP
, WT_NORM
) == 'y'){
7055 set_variable(V_USER_ID
, answer
, 1, 1, Main
);
7058 fs_give((void **)&(ps_global
->VAR_USER_ID
));
7059 ps_global
->VAR_USER_ID
= cpystr(answer
);
7063 /* query for personal name */
7064 if(!ps_global
->VAR_PERSONAL_NAME
|| ps_global
->VAR_PERSONAL_NAME
[0]=='\0'
7065 && F_OFF(F_QUELL_PERSONAL_NAME_PROMPT
, ps_global
)){
7067 snprintf(prompt
, sizeof(prompt
), _("Personal name for From address : "));
7068 prompt
[sizeof(prompt
)-1] = '\0';
7072 flags
= OE_APPEND_CURRENT
;
7073 rc
= optionally_enter(answer
,-FOOTER_ROWS(ps_global
),0,
7074 sizeof(answer
),prompt
,NULL
,help
,&flags
);
7079 help
= (help
== NO_HELP
) ? h_sticky_personal_name
: NO_HELP
;
7087 if(rc
== 0 && answer
){ /* save the name */
7088 snprintf(prompt
, sizeof(prompt
), _("Preserve %.*s as \"personal-name\" in PINERC"),
7089 sizeof(prompt
)-50, answer
);
7090 prompt
[sizeof(prompt
)-1] = '\0';
7091 if(ps_global
->blank_personal_name
7092 && want_to(prompt
, 'y', 'n', NO_HELP
, WT_NORM
) == 'y'){
7093 set_variable(V_PERSONAL_NAME
, answer
, 1, 1, Main
);
7096 fs_give((void **)&(ps_global
->VAR_PERSONAL_NAME
));
7097 ps_global
->VAR_PERSONAL_NAME
= cpystr(answer
);
7103 * query for host/domain portion of address, using IMAP
7106 if(ps_global
->blank_user_domain
7107 || ps_global
->maildomain
== ps_global
->localdomain
7108 || ps_global
->maildomain
== ps_global
->hostname
){
7109 if(ps_global
->inbox_name
[0] == '{'){
7111 i
< sizeof(answer
)-1 && ps_global
->inbox_name
[i
+1] != '}'; i
++)
7112 answer
[i
] = ps_global
->inbox_name
[i
+1];
7119 snprintf(prompt
,sizeof(prompt
),_("Host/domain for From address : "));
7120 prompt
[sizeof(prompt
)-1] = '\0';
7124 flags
= OE_APPEND_CURRENT
;
7125 rc
= optionally_enter(answer
,-FOOTER_ROWS(ps_global
),0,
7126 sizeof(answer
),prompt
,NULL
,help
,&flags
);
7131 help
= (help
== NO_HELP
) ? h_sticky_domain
: NO_HELP
;
7139 if(rc
== 1 || (rc
== 0 && !answer
[0])) {
7140 q_status_message(SM_ORDER
, 3, 4,
7141 _("Send cancelled (Host/domain name must be provided before sending)"));
7146 snprintf(prompt
, sizeof(prompt
), _("Preserve %.*s as \"user-domain\" in PINERC"),
7147 sizeof(prompt
)-50, answer
);
7148 prompt
[sizeof(prompt
)-1] = '\0';
7149 if(!ps_global
->userdomain
&& !ps_global
->blank_user_domain
7150 && want_to(prompt
, 'y', 'n', NO_HELP
, WT_NORM
) == 'y'){
7151 set_variable(V_USER_DOMAIN
, answer
, 1, 1, Main
);
7152 fs_give((void **)&(ps_global
->maildomain
)); /* blast old val */
7153 ps_global
->userdomain
= cpystr(answer
);
7154 ps_global
->maildomain
= ps_global
->userdomain
;
7157 fs_give((void **)&(ps_global
->maildomain
));
7158 ps_global
->userdomain
= cpystr(answer
);
7159 ps_global
->maildomain
= ps_global
->userdomain
;
7163 /* check for smtp server */
7164 if(!ps_global
->VAR_SMTP_SERVER
||
7165 !ps_global
->VAR_SMTP_SERVER
[0] ||
7166 !ps_global
->VAR_SMTP_SERVER
[0][0]){
7169 if(ps_global
->inbox_name
[0] == '{'){
7171 i
< sizeof(answer
)-1 && ps_global
->inbox_name
[i
+1] != '}'; i
++)
7172 answer
[i
] = ps_global
->inbox_name
[i
+1];
7179 snprintf(prompt
,sizeof(prompt
),_("SMTP server to forward message : "));
7180 prompt
[sizeof(prompt
)-1] = '\0';
7184 flags
= OE_APPEND_CURRENT
;
7185 rc
= optionally_enter(answer
,-FOOTER_ROWS(ps_global
),0,
7186 sizeof(answer
),prompt
,NULL
,help
,&flags
);
7191 help
= (help
== NO_HELP
) ? h_sticky_smtp
: NO_HELP
;
7199 if(rc
== 1 || (rc
== 0 && answer
[0] == '\0')) {
7200 q_status_message(SM_ORDER
, 3, 4,
7201 _("Send cancelled (SMTP server must be provided before sending)"));
7206 list
= (char **) fs_get(2 * sizeof(char *));
7207 list
[0] = cpystr(answer
);
7209 set_variable_list(V_SMTP_SERVER
, list
, TRUE
, Main
);
7210 fs_give((void *)&list
[0]);
7211 fs_give((void *)list
);
7217 #endif /* defined(DOS) || defined(OS2) */