2 * ========================================================================
3 * Copyright 2013-2022 Eduardo Chappa
4 * Copyright 2006-2008 University of Washington
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * ========================================================================
15 /*======================================================================
16 Functions for composing and sending mail
38 #include "../pith/debug.h"
39 #include "../pith/state.h"
40 #include "../pith/conf.h"
41 #include "../pith/flag.h"
42 #include "../pith/bldaddr.h"
43 #include "../pith/copyaddr.h"
44 #include "../pith/detach.h"
45 #include "../pith/mimedesc.h"
46 #include "../pith/pipe.h"
47 #include "../pith/addrstring.h"
48 #include "../pith/news.h"
49 #include "../pith/detoken.h"
50 #include "../pith/util.h"
51 #include "../pith/init.h"
52 #include "../pith/mailcmd.h"
53 #include "../pith/ablookup.h"
54 #include "../pith/reply.h"
55 #include "../pith/hist.h"
56 #include "../pith/list.h"
57 #include "../pith/icache.h"
58 #include "../pith/busy.h"
59 #include "../pith/mimetype.h"
60 #include "../pith/send.h"
61 #include "../pith/smime.h"
64 typedef struct body_particulars
{
65 unsigned short type
, encoding
, had_csp
;
66 char *subtype
, *charset
;
71 * macro to bind pico's headerentry pointer to PINEFIELD "extdata" hook
73 #define HE(PF) ((struct headerentry *)((PF)->extdata))
79 int redraft(MAILSTREAM
**, ENVELOPE
**, BODY
**, char **, char **, REPLY_S
**,
80 REDRAFT_POS_S
**, PINEFIELD
**, ACTION_S
**, int);
81 int redraft_prompt(char *, char *, int);
82 int check_for_subject(METAENV
*);
83 int check_for_fcc(char *);
84 void free_prompts(PINEFIELD
*);
85 int postpone_prompt(void);
86 METAENV
*pine_simple_send_header(ENVELOPE
*, char **, char ***);
87 void call_mailer_file_result(char *, int);
88 void mark_address_failure_for_pico(METAENV
*);
90 *save_body_particulars(BODY
*);
91 void reset_body_particulars(BODY_PARTICULARS_S
*, BODY
*);
92 void free_body_particulars(BODY_PARTICULARS_S
*);
93 long message_format_for_pico(long, int (*)(int));
94 int send_exit_for_pico(struct headerentry
*, void (*)(void), int, char **);
95 void new_thread_on_blank_subject(void);
96 char *choose_a_priority(char *);
97 int dont_flow_this_time(void);
98 int mime_type_for_pico(char *);
99 char *cancel_for_pico(void (*)(void));
100 int filter_message_text(char *, ENVELOPE
*, BODY
*, STORE_S
**, METAENV
*);
101 void pine_send_newsgroup_name(char *, char*, size_t);
102 void outgoing2strings(METAENV
*, BODY
*, void **, PATMT
**, int);
103 void strings2outgoing(METAENV
*, BODY
**, PATMT
*, int);
104 void create_message_body_text(BODY
*, int);
105 void set_body_size(BODY
*);
106 int view_as_rich(char *, int);
107 int background_posting(int);
108 int valid_subject(char *, char **, char **,BUILDER_ARG
*,int *);
109 int build_addr_lcc(char *, char **, char **, BUILDER_ARG
*, int *);
110 int news_build(char *, char **, char **, BUILDER_ARG
*, int *);
111 void news_build_busy(void);
112 #if defined(DOS) || defined(OS2)
113 int dos_valid_from(void);
114 #endif /* defined(DOS) || defined(OS2) */
118 * Pointer to buffer to hold pointers into pine data that's needed by pico.
123 static char *g_rolenick
= NULL
;
126 static char *sending_filter_requested
;
127 static char background_requested
, flowing_requested
;
128 static unsigned call_mailer_flags
;
129 static char *priority_requested
;
131 /* local global to save busy_cue state */
132 static int news_busy_cue
= 0;
136 * Various useful strings
139 _("Continue INTERRUPTED composition (answering \"n\" won't erase it)")
141 _("Continue postponed composition (answering \"No\" won't erase it)")
143 _("Start composition from Form Letter Folder")
144 #define PSTPN_FORM_PMT \
145 _("Save to Postponed or Form letter folder? ")
147 _("Posted message may go to thousands of readers. Really post")
148 #define INTR_DEL_PMT \
149 _("Deleted messages will be removed from folder after use. Proceed")
153 * Macros to help sort out posting results
155 #define P_MAIL_WIN 0x01
156 #define P_MAIL_LOSE 0x02
157 #define P_MAIL_BITS 0x03
158 #define P_NEWS_WIN 0x04
159 #define P_NEWS_LOSE 0x08
160 #define P_NEWS_BITS 0x0C
161 #define P_FCC_WIN 0x10
162 #define P_FCC_LOSE 0x20
163 #define P_FCC_BITS 0x30
166 #define COMPOSE_MAIL_TITLE "COMPOSE MESSAGE"
170 * For check_for_subject and check_for_fcc
173 #define CF_MISSING 0x2
176 /*----------------------------------------------------------------------
177 Compose screen (not forward or reply). Set up envelope, call composer
179 Args: pine_state -- The usual pine structure
181 Little front end for the compose screen
184 compose_screen(struct pine
*pine_state
)
186 void (*prev_screen
)(struct pine
*) = pine_state
->prev_screen
,
187 (*redraw
)(void) = pine_state
->redrawer
;
189 pine_state
->redrawer
= NULL
;
190 ps_global
->next_screen
= SCREEN_FUN_NULL
;
191 mailcap_free(); /* free resources we won't be using for a while */
192 compose_mail(NULL
, NULL
, NULL
, NULL
, NULL
);
193 pine_state
->next_screen
= prev_screen
;
194 pine_state
->redrawer
= redraw
;
198 /*----------------------------------------------------------------------
199 Alternate compose screen. Set up role and call regular compose.
201 Args: pine_state -- The usual pine structure
204 alt_compose_screen(struct pine
*pine_state
)
206 ACTION_S
*role
= NULL
;
207 void (*prev_screen
)(struct pine
*) = pine_state
->prev_screen
,
208 (*redraw
)(void) = pine_state
->redrawer
;
210 pine_state
->redrawer
= NULL
;
211 ps_global
->next_screen
= SCREEN_FUN_NULL
;
212 mailcap_free(); /* free resources we won't be using for a while */
215 if(role_select_screen(pine_state
, &role
, MC_COMPOSE
) < 0){
216 cmd_cancelled("Composition");
217 pine_state
->next_screen
= prev_screen
;
218 pine_state
->redrawer
= redraw
;
223 * If default role was selected (NULL) we need to make up a role which
224 * won't do anything, but will cause compose_mail to think there's
225 * already a role so that it won't try to confirm the default.
228 role
= combine_inherited_role(role
);
230 role
= (ACTION_S
*)fs_get(sizeof(*role
));
231 memset((void *)role
, 0, sizeof(*role
));
232 role
->nick
= cpystr("Default Role");
235 pine_state
->redrawer
= NULL
;
236 compose_mail(NULL
, NULL
, role
, NULL
, NULL
);
238 pine_state
->next_screen
= prev_screen
;
239 pine_state
->redrawer
= redraw
;
243 /*----------------------------------------------------------------------
244 Format envelope for outgoing message and call editor
246 Args: given_to -- An address to send mail to (usually from command line
248 fcc_arg -- The fcc that goes with this address.
250 If a "To" line is given format that into the envelope and get ready to call
252 If there's a message postponed, offer to continue it, and set it up,
253 otherwise just fill in the outgoing envelope as blank.
255 NOTE: we ignore postponed and interrupted messages in nr mode
258 compose_mail(char *given_to
, char *fcc_arg
, ACTION_S
*role_arg
,
259 PATMT
*attach
, gf_io_t inc_text_getc
)
262 ENVELOPE
*outgoing
= NULL
;
263 PINEFIELD
*custom
= NULL
;
264 REPLY_S
*reply
= NULL
;
265 REDRAFT_POS_S
*redraft_pos
= NULL
;
266 ACTION_S
*role
= NULL
;
272 int fcc_is_sticky
= 0,
279 "\n\n ---- COMPOSE SCREEN (not in pico yet) ----\n"));
281 /*-- Check for INTERRUPTED mail --*/
282 if(!role_arg
&& !(given_to
|| attach
)){
283 char file_path
[MAXPATH
+1];
285 /* build filename and see if it exists. build_path creates
286 * an explicit local path name, so all c-client access is thru
290 build_path(file_path
,
291 ps_global
->VAR_OPER_DIR
? ps_global
->VAR_OPER_DIR
292 : ps_global
->home_dir
,
293 INTERRUPTED_MAIL
, sizeof(file_path
));
295 /* check to see if the folder exists, the user wants to continue
296 * and that we can actually read something in...
298 if(folder_exists(NULL
, file_path
) & FEX_ISFILE
)
302 /*-- Check for postponed mail --*/
304 && !outgoing
/* not replying/forwarding */
305 && !(given_to
|| attach
) /* not command line send */
306 && ps_global
->VAR_POSTPONED_FOLDER
/* folder to look in */
307 && ps_global
->VAR_POSTPONED_FOLDER
[0])
310 /*-- Check for form letter folder --*/
312 && !outgoing
/* not replying/forwarding */
313 && !(given_to
|| attach
) /* not command line send */
314 && ps_global
->VAR_FORM_FOLDER
/* folder to look in */
315 && ps_global
->VAR_FORM_FOLDER
[0])
318 if(!outgoing
&& !(given_to
|| attach
)
319 && !role_arg
&& F_ON(F_ALT_COMPOSE_MENU
, ps_global
)){
324 char *intrpt
= "Interrupted";
325 char *postpnd
= "Postponed";
326 char *formltr
= "FormLetter";
327 char *roles
= "setRole";
328 HelpType help
= h_composer_browse
;
329 ESCKEY_S compose_style
[6];
334 compose_style
[ekey_num
].ch
= 'n';
335 compose_style
[ekey_num
].rval
= 'n';
336 compose_style
[ekey_num
].name
= "N";
337 compose_style
[ekey_num
++].label
= new;
340 compose_style
[ekey_num
].ch
= 'i';
341 compose_style
[ekey_num
].rval
= 'i';
342 compose_style
[ekey_num
].name
= "I";
343 compose_style
[ekey_num
++].label
= intrpt
;
347 compose_style
[ekey_num
].ch
= 'p';
348 compose_style
[ekey_num
].rval
= 'p';
349 compose_style
[ekey_num
].name
= "P";
350 compose_style
[ekey_num
++].label
= postpnd
;
354 compose_style
[ekey_num
].ch
= 'f';
355 compose_style
[ekey_num
].rval
= 'f';
356 compose_style
[ekey_num
].name
= "F";
357 compose_style
[ekey_num
++].label
= formltr
;
360 compose_style
[ekey_num
].ch
= 'r';
361 compose_style
[ekey_num
].rval
= 'r';
362 compose_style
[ekey_num
].name
= "R";
363 compose_style
[ekey_num
++].label
= roles
;
365 compose_style
[ekey_num
].ch
= -1;
367 if(F_ON(F_BLANK_KEYMENU
,ps_global
)){
372 for(ekey_num
= 0; compose_style
[ekey_num
].ch
!= -1; ekey_num
++){
373 if(p
- letters
< sizeof(letters
))
374 *p
++ = (char) compose_style
[ekey_num
].ch
;
376 if(compose_style
[ekey_num
+ 1].ch
!= -1 && p
- letters
< sizeof(letters
))
380 if(p
- letters
< sizeof(letters
))
384 which_help
= intrptd
+ 2 * postponed
+ 4 * form
;
387 help
= h_compose_intrptd
;
390 help
= h_compose_postponed
;
393 help
= h_compose_intrptd_postponed
;
396 help
= h_compose_form
;
399 help
= h_compose_intrptd_form
;
402 help
= h_compose_postponed_form
;
405 help
= h_compose_intrptd_postponed_form
;
408 help
= h_compose_default
;
412 snprintf(prompt
, sizeof(prompt
),
413 "Choose a compose method from %s : ",
414 F_ON(F_BLANK_KEYMENU
,ps_global
) ? letters
: "the menu below");
415 prompt
[sizeof(prompt
)-1] = '\0';
417 chosen_task
= radio_buttons(prompt
, -FOOTER_ROWS(ps_global
),
418 compose_style
, 'n', 'x', help
, RB_NORM
);
419 intrptd
= postponed
= form
= 0;
430 void (*prev_screen
)(struct pine
*) = ps_global
->prev_screen
,
431 (*redraw
)(void) = ps_global
->redrawer
;
433 ps_global
->redrawer
= NULL
;
434 ps_global
->next_screen
= SCREEN_FUN_NULL
;
435 if(role_select_screen(ps_global
, &role
, MC_COMPOSE
) < 0){
436 cmd_cancelled("Composition");
437 ps_global
->next_screen
= prev_screen
;
438 ps_global
->redrawer
= redraw
;
442 ps_global
->next_screen
= prev_screen
;
443 ps_global
->redrawer
= redraw
;
445 role
= combine_inherited_role(role
);
454 q_status_message(SM_ORDER
, 0, 3,
455 "Composition cancelled");
464 if(intrptd
&& !outgoing
){
465 char file_path
[MAXPATH
+1];
469 build_path(file_path
,
470 ps_global
->VAR_OPER_DIR
? ps_global
->VAR_OPER_DIR
471 : ps_global
->home_dir
,
472 INTERRUPTED_MAIL
, sizeof(file_path
));
473 if(folder_exists(NULL
, file_path
) & FEX_ISFILE
){
474 if((stream
= pine_mail_open(NULL
, file_path
,
475 SP_USEPOOL
|SP_TEMPUSE
, NULL
))
476 && !stream
->halfopen
){
478 if(F_ON(F_ALT_COMPOSE_MENU
, ps_global
) ||
479 (ret
= redraft_prompt("Interrupted",INTRPT_PMT
,'n')) =='y'){
480 if(!redraft(&stream
, &outgoing
, &body
, &fcc
, &lcc
, &reply
,
481 &redraft_pos
, &custom
, &role
, REDRAFT_DEL
)){
483 pine_mail_close(stream
);
490 /* redraft() may or may not have closed stream */
492 pine_mail_close(stream
);
494 postponed
= form
= 0;
497 pine_mail_close(stream
);
499 q_status_message(SM_ORDER
, 0, 3,
500 _("Composition cancelled"));
506 q_status_message1(SM_ORDER
| SM_DING
, 3, 3,
507 _("Can't open Interrupted mailbox: %s"),
510 pine_mail_close(stream
);
515 if(postponed
&& !outgoing
){
516 int ret
= 'n', done
= 0;
519 if((exists
=postponed_stream(&stream
,
520 ps_global
->VAR_POSTPONED_FOLDER
,
521 "Postponed", 1)) & FEX_ISFILE
){
522 if(F_ON(F_ALT_COMPOSE_MENU
, ps_global
) ||
523 (ret
= redraft_prompt("Postponed",PSTPND_PMT
,'n')) == 'y'){
524 if(!redraft(&stream
, &outgoing
, &body
, &fcc
, &lcc
, &reply
,
525 &redraft_pos
, &custom
, &role
,
526 REDRAFT_DEL
| REDRAFT_PPND
))
529 /* stream may or may not be closed in redraft() */
530 if(stream
&& (stream
!= ps_global
->mail_stream
))
531 pine_mail_close(stream
);
537 if(stream
!= ps_global
->mail_stream
)
538 pine_mail_close(stream
);
541 q_status_message(SM_ORDER
, 0, 3,
542 _("Composition cancelled"));
547 else if(F_ON(F_ALT_COMPOSE_MENU
, ps_global
)){
548 q_status_message(SM_ORDER
, 3, 3,
549 _("No postponed messages found!"));
557 if(form
&& !outgoing
){
558 int ret
= 'n', done
= 0;
561 if((exists
=postponed_stream(&stream
,
562 ps_global
->VAR_FORM_FOLDER
,
563 "Form letter", 1)) & FEX_ISFILE
){
564 if(F_ON(F_ALT_COMPOSE_MENU
, ps_global
) ||
565 (ret
= want_to(FORM_PMT
,'y','x',NO_HELP
,WT_NORM
))=='y'){
566 if(!redraft(&stream
, &outgoing
, &body
, &fcc
, &lcc
, &reply
,
567 &redraft_pos
, &custom
, &role
, REDRAFT_NONE
))
570 /* stream may or may not be closed in redraft() */
571 if(stream
&& (stream
!= ps_global
->mail_stream
))
572 pine_mail_close(stream
);
575 intrptd
= postponed
= 0;
578 if(stream
!= ps_global
->mail_stream
)
579 pine_mail_close(stream
);
582 q_status_message(SM_ORDER
, 0, 3,
583 _("Composition cancelled"));
589 if(F_ON(F_ALT_COMPOSE_MENU
, ps_global
)){
590 q_status_message(SM_ORDER
| SM_DING
, 3, 3,
591 _("Form letter folder doesn't exist!"));
600 /*-- normal composition --*/
602 int impl
, template_len
= 0;
603 long rflags
= ROLE_COMPOSE
;
606 /*================= Compose new message ===============*/
607 body
= mail_newbody();
608 outgoing
= mail_newenvelope();
611 rfc822_parse_adrlist(&outgoing
->to
, given_to
, ps_global
->maildomain
);
614 * Setup possible role
617 role
= copy_action(role_arg
);
620 /* Setup possible compose role */
621 if(nonempty_patterns(rflags
, &dummy
)){
624 * Msgno = -1 means there is no msg.
625 * This will match roles which have the Compose Use turned
626 * on, and have no patterns set, and match the Current
629 role
= set_role_from_msg(ps_global
, rflags
, -1L, NULL
);
631 if(confirm_role(rflags
, &role
))
632 role
= combine_inherited_role(role
);
633 else{ /* cancel reply */
635 cmd_cancelled("Composition");
642 q_status_message1(SM_ORDER
, 3, 4, _("Composing using role \"%s\""),
645 outgoing
->message_id
= generate_message_id(role
);
647 * The type of storage object allocated below is vitally
648 * important. See SIMPLIFYING ASSUMPTION #37
650 if((body
->contents
.text
.data
= (void *) so_get(PicoText
,
651 NULL
, EDIT_ACCESS
)) != NULL
){
655 while((*inc_text_getc
)(&ch
))
656 if(!so_writec(ch
, (STORE_S
*)body
->contents
.text
.data
)){
662 q_status_message(SM_ORDER
| SM_DING
, 3, 4,
663 _("Problem creating space for message text."));
667 if(role
&& role
->template){
670 impl
= 1; /* leave cursor in header if not explicit */
671 filtered
= detoken(role
, NULL
, 0, 0, 0, &redraft_pos
, &impl
);
674 so_puts((STORE_S
*)body
->contents
.text
.data
, filtered
);
676 template_len
= strlen(filtered
);
679 fs_give((void **)&filtered
);
685 if((sig
= detoken(role
, NULL
, 2, 0, 1, &redraft_pos
, &impl
)) != NULL
){
687 redraft_pos
->offset
+= template_len
;
690 so_puts((STORE_S
*)body
->contents
.text
.data
, sig
);
692 fs_give((void **)&sig
);
695 body
->type
= TYPETEXT
;
698 create_message_body(&body
, attach
, 0);
701 ps_global
->prev_screen
= compose_screen
;
702 if(!(fcc_to_free
= fcc
) && !(role
&& role
->fcc
))
703 fcc
= fcc_arg
; /* Didn't pick up fcc, use given */
706 * check whether a build_address-produced fcc is different from
707 * fcc. If same, do nothing, if different, set sticky bit in pine_send.
710 char *tmp_fcc
= NULL
;
713 tmp_fcc
= get_fcc_based_on_to(outgoing
->to
);
714 if(strcmp(fcc
, tmp_fcc
? tmp_fcc
: ""))
715 fcc_is_sticky
++; /* cause sticky bit to get set */
718 else if((tmp_fcc
= get_fcc(NULL
)) != NULL
&&
719 !strcmp(fcc
, tmp_fcc
)){
726 fs_give((void **)&tmp_fcc
);
729 pine_send(outgoing
, &body
, COMPOSE_MAIL_TITLE
, role
, fcc
,
730 reply
, redraft_pos
, lcc
, custom
,
731 (fcc_is_sticky
? PS_STICKY_FCC
: 0) | (to_is_sticky
? PS_STICKY_TO
: 0));
735 fs_give((void **) &reply
->mailbox
);
737 fs_give((void **) &reply
->origmbox
);
739 fs_give((void **) &reply
->prefix
);
740 if(reply
->data
.uid
.msgs
)
741 fs_give((void **) &reply
->data
.uid
.msgs
);
742 fs_give((void **) &reply
);
746 fs_give((void **)&fcc_to_free
);
749 fs_give((void **)&lcc
);
751 mail_free_envelope(&outgoing
);
752 pine_free_body(&body
);
753 free_redraft_pos(&redraft_pos
);
758 /*----------------------------------------------------------------------
759 Args: stream -- This is where we get the postponed messages from
760 We'll expunge and close it here unless it is mail_stream.
762 These are all return values:
778 redraft(MAILSTREAM
**streamp
, ENVELOPE
**outgoing
, struct mail_bodystruct
**body
,
779 char **fcc
, char **lcc
, REPLY_S
**reply
, REDRAFT_POS_S
**redraft_pos
,
780 PINEFIELD
**custom
, ACTION_S
**role
, int flags
)
786 if(!(streamp
&& *streamp
))
792 * If we're manipulating the current folder, don't bother
796 if(REDRAFT_PPND
&flags
)
797 q_status_message(SM_ORDER
| SM_DING
, 3, 5, _("Empty folder! No messages really postponed!"));
799 q_status_message(SM_ORDER
| SM_DING
, 3, 5, _("Empty folder! No messages really interrupted!"));
801 return(redraft_cleanup(streamp
, FALSE
, flags
));
803 else if(stream
== ps_global
->mail_stream
804 && ps_global
->prev_screen
== mail_index_screen
){
806 * Since the user's got this folder already opened and they're
807 * on a selected message, pick that one rather than rebuild
808 * another index screen...
810 cont_msg
= mn_m2raw(ps_global
->msgmap
, mn_get_cur(ps_global
->msgmap
));
812 else if(stream
->nmsgs
> 1L){ /* offer browser ? */
815 if(REDRAFT_PPND
&flags
){ /* set to last message postponed */
816 mn_set_cur(sp_msgmap(stream
),
817 mn_get_revsort(sp_msgmap(stream
))
818 ? 1L : mn_get_total(sp_msgmap(stream
)));
820 else{ /* set to top form letter */
821 mn_set_cur(sp_msgmap(stream
), 1L);
824 clear_index_cache(stream
, 0);
828 ti
= stop_threading_temporarily();
829 rv
= index_lister(ps_global
, NULL
, stream
->mailbox
,
830 stream
, sp_msgmap(stream
));
831 restore_threading(&ti
);
833 cont_msg
= mn_m2raw(sp_msgmap(stream
), mn_get_cur(sp_msgmap(stream
)));
834 if(count_flagged(stream
, F_DEL
)
835 && want_to(INTR_DEL_PMT
, 'n', 0, NO_HELP
, WT_NORM
) == 'n'){
836 if(REDRAFT_PPND
&flags
)
837 q_status_message(SM_ORDER
, 3, 3, _("Undelete messages to remain postponed, and then continue message"));
839 q_status_message(SM_ORDER
, 3, 3, _("Undelete form letters you want to keep, and then continue message"));
847 clear_index_cache(stream
, 0);
850 q_status_message(SM_ORDER
, 0, 3, _("Composition cancelled"));
851 (void) redraft_cleanup(streamp
, FALSE
, flags
);
853 if(!*streamp
&& !ps_global
->mail_stream
){
854 q_status_message2(SM_ORDER
, 3, 7,
855 "No more %.200s, returning to \"%.200s\"",
856 (REDRAFT_PPND
&flags
) ? "postponed messages"
858 ps_global
->inbox_name
);
859 if(ps_global
&& ps_global
->ttyo
){
860 blank_keymenu(ps_global
->ttyo
->screen_rows
- 2, 0);
861 ps_global
->mangled_footer
= 1;
864 do_broach_folder(ps_global
->inbox_name
,
865 ps_global
->context_list
, NULL
, DB_INBOXWOCNTXT
);
867 ps_global
->next_screen
= mail_index_screen
;
870 return(0); /* special case */
874 if((so
= (void *) so_get(PicoText
, NULL
, EDIT_ACCESS
)) != NULL
)
875 return(redraft_work(streamp
, cont_msg
, outgoing
, body
,
876 fcc
, lcc
, reply
, redraft_pos
, custom
,
884 redraft_prompt(char *type
, char *prompt
, int failure
)
886 if(background_posting(FALSE
)){
887 q_status_message1(SM_ORDER
, 0, 3,
888 _("%s folder unavailable while background posting"),
893 return(want_to(prompt
, 'y', 'x', NO_HELP
, WT_NORM
));
897 /* this is for initializing the fixed header elements in pine_send() */
899 prompt::name::help::prwid::maxlen::realaddr::
900 builder::affected_entry::next_affected::selector::key_label::fileedit::
901 display_it::break_on_comma::is_attach::rich_header::only_file_chars::
902 single_space::sticky::dirty::start_here::blank::sticky_special::KS_ODATAVAR
904 static struct headerentry he_template
[]={
905 {"", "X-Auth-Received", NO_HELP
, 10, 0, NULL
,
906 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
907 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KS_NONE
},
908 {"From : ", "From", h_composer_from
, 10, 0, NULL
,
909 build_address
, NULL
, NULL
, addr_book_compose
, "To AddrBk", NULL
, abook_nickname_complete
,
910 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, KS_TOADDRBOOK
},
911 {"Reply-To: ", "Reply To", h_composer_reply_to
, 10, 0, NULL
,
912 build_address
, NULL
, NULL
, addr_book_compose
, "To AddrBk", NULL
, abook_nickname_complete
,
913 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, KS_TOADDRBOOK
},
914 {"To : ", "To", h_composer_to
, 10, 0, NULL
,
915 build_address
, NULL
, NULL
, addr_book_compose
, "To AddrBk", NULL
, abook_nickname_complete
,
916 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, KS_TOADDRBOOK
},
917 {"Cc : ", "Cc", h_composer_cc
, 10, 0, NULL
,
918 build_address
, NULL
, NULL
, addr_book_compose
, "To AddrBk", NULL
, abook_nickname_complete
,
919 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, KS_TOADDRBOOK
},
920 {"Bcc : ", "Bcc", h_composer_bcc
, 10, 0, NULL
,
921 build_address
, NULL
, NULL
, addr_book_compose
, "To AddrBk", NULL
, abook_nickname_complete
,
922 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, KS_TOADDRBOOK
},
923 {"Newsgrps: ", "Newsgroups", h_composer_news
, 10, 0, NULL
,
924 news_build
, NULL
, NULL
, news_group_selector
, "To NwsGrps", NULL
, NULL
,
925 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, KS_NONE
},
926 {"Fcc : ", "Fcc", h_composer_fcc
, 10, 0, NULL
,
927 NULL
, NULL
, NULL
, folders_for_fcc
, "To Fldrs", NULL
, fcc_tab_complete
,
928 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, KS_NONE
},
929 {"Lcc : ", "Lcc", h_composer_lcc
, 10, 0, NULL
,
930 build_addr_lcc
, NULL
, NULL
, addr_book_compose_lcc
,"To AddrBk", NULL
, abook_nickname_complete
,
931 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, KS_NONE
},
932 {"Attchmnt: ", "Attchmnt", h_composer_attachment
, 10, 0, NULL
,
933 NULL
, NULL
, NULL
, NULL
, "To Files", NULL
, NULL
,
934 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, KS_NONE
},
935 {"Subject : ", "Subject", h_composer_subject
, 10, 0, NULL
,
936 valid_subject
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
937 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KS_NONE
},
938 {"", "References", NO_HELP
, 10, 0, NULL
,
939 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
940 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KS_NONE
},
941 {"", "Date", NO_HELP
, 10, 0, NULL
,
942 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
943 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KS_NONE
},
944 {"", "In-Reply-To", 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 {"", "Message-ID", 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 {"", "X-Priority", 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 {"", "User-Agent", 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 {"", "To", 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 {"", "X-Post-Error",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 {"", "X-Reply-UID", 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-Reply-Mbox", 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-SMTP-Server", 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-Cursor-Pos", 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-Our-ReplyTo", 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 {"", OUR_HDRS_LIST
, 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-Auth-Received", 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 #if !(defined(DOS) || defined(OS2)) || defined(NOAUTH)
984 {"", "Sender", NO_HELP
, 10, 0, NULL
,
985 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
986 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KS_NONE
}
991 static struct headerentry he_custom_addr_templ
={
992 NULL
, NULL
, h_composer_custom_addr
,10, 0, NULL
,
993 build_address
, NULL
, NULL
, addr_book_compose
, "To AddrBk", NULL
, abook_nickname_complete
,
994 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, KS_TOADDRBOOK
};
996 static struct headerentry he_custom_free_templ
={
997 NULL
, NULL
, h_composer_custom_free
,10, 0, NULL
,
998 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
999 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, KS_NONE
};
1002 /*----------------------------------------------------------------------
1003 Get addressee for message, then post message
1005 Args: outgoing -- Partially formatted outgoing ENVELOPE
1006 body -- Body of outgoing message
1007 prmpt_who -- Optional prompt for optionally_enter call
1008 prmpt_cnf -- Optional prompt for confirmation call
1009 used_tobufval -- The string that the to was eventually set equal to.
1010 This gets passed back if non-NULL on entry.
1011 flagsarg -- SS_PROMPTFORTO - Allow user to change recipient
1012 SS_NULLRP - Use null return-path so we'll send an
1015 Result: message "To: " field is provided and message is sent or cancelled.
1024 subject passed in, NOT edited but maybe canonized here
1025 to possibly passed in, edited and canonized here
1031 Can only deal with message bodies that are either TYPETEXT or TYPEMULTIPART
1032 with the first part TYPETEXT! All newlines in the text here also end with
1035 Returns 0 on success, -1 on failure.
1038 pine_simple_send(ENVELOPE
*outgoing
, /* envelope for outgoing message */
1039 struct mail_bodystruct
**body
,
1043 char **used_tobufval
,
1046 char **tobufp
, *p
, tmp
[MAILTMPLEN
];
1048 int done
= 0, retval
= 0, x
;
1049 int lastrc
, rc
= 0, ku
, i
, resize_len
, result
, fcc_result
= 0;
1052 static HISTORY_S
*history
= NULL
;
1056 ACTION_S
*role
= rolep
? *rolep
: NULL
;
1059 dprint((1,"\n === simple send called === \n"));
1061 memset(&ba_fcc
, 0, sizeof(BUILDER_ARG
));
1063 init_hist(&history
, HISTSIZE
);
1065 header
= pine_simple_send_header(outgoing
, &ba_fcc
.tptr
, &tobufp
);
1067 /*----- Fill in a few general parts of the envelope ----*/
1068 if(!outgoing
->date
){
1069 if(F_ON(F_QUELL_TIMEZONE
, ps_global
))
1070 mail_parameters(NULL
, SET_DISABLE822TZTEXT
, (void *) TRUE
);
1072 rfc822_date(tmp_20k_buf
); /* format and copy new date */
1073 if(F_ON(F_QUELL_TIMEZONE
, ps_global
))
1074 mail_parameters(NULL
, SET_DISABLE822TZTEXT
, (void *) FALSE
);
1076 outgoing
->date
= (unsigned char *) cpystr(tmp_20k_buf
);
1079 if(!outgoing
->from
){
1080 if(role
&& role
->from
){
1081 if(ps_global
->never_allow_changing_from
)
1082 q_status_message(SM_ORDER
, 3, 3, _("Site policy doesn't allow changing From address so role's From has no effect"));
1084 outgoing
->from
= copyaddrlist(role
->from
);
1087 outgoing
->from
= generate_from();
1090 if(!(flagsarg
& SS_NULLRP
))
1091 outgoing
->return_path
= rfc822_cpy_adr(outgoing
->from
);
1093 ekey
[i
= 0].ch
= ctrl('T');
1095 ekey
[i
].name
= "^T";
1096 ekey
[i
++].label
= N_("To AddrBk");
1098 if(F_ON(F_ENABLE_TAB_COMPLETE
,ps_global
)){
1099 ekey
[i
].ch
= ctrl('I');
1101 ekey
[i
].name
= "TAB";
1102 ekey
[i
++].label
= N_("Complete");
1105 if(nonempty_patterns(ROLE_DO_ROLES
, &pstate
) && first_pattern(&pstate
)){
1106 ekey
[i
].ch
= ctrl('R');
1108 ekey
[i
].name
= "^R";
1109 ekey
[i
++].label
= "Set Role";
1112 ekey
[i
].ch
= KEY_UP
;
1116 ekey
[i
++].label
= "";
1118 ekey
[i
].ch
= KEY_DOWN
;
1121 ekey
[i
++].label
= "";
1125 if(outgoing
->remail
== NULL
)
1126 strcpy(tmp
, _("FORWARD (as e-mail) to : "));
1128 /*----------------------------------------------------------------------
1129 Loop editing the "To: " field until everything goes well
1136 if(outgoing
->message_id
)
1137 fs_give((void **) &outgoing
->message_id
);
1139 outgoing
->message_id
= generate_message_id(role
);
1141 if(outgoing
->remail
){
1143 snprintf(tmp
, sizeof(tmp
), _("BOUNCE (redirect) message using role \"%s\" to : "), role
->nick
);
1145 strncpy(tmp
, _("BOUNCE (redirect) message to : "), sizeof(tmp
));
1146 tmp
[sizeof(tmp
)-1] = '\0';
1151 outgoing2strings(header
, *body
, &messagebuf
, NULL
, 1);
1155 if(flagsarg
& SS_PROMPTFORTO
){
1157 *tobufp
= cpystr("");
1159 resize_len
= MAX(MAXPATH
, strlen(*tobufp
));
1160 fs_resize((void **) tobufp
, resize_len
+1);
1162 if(items_in_hist(history
) > 0){
1163 ekey
[ku
].name
= HISTORY_UP_KEYNAME
;
1164 ekey
[ku
].label
= HISTORY_KEYLABEL
;
1165 ekey
[ku
+1].name
= HISTORY_DOWN_KEYNAME
;
1166 ekey
[ku
+1].label
= HISTORY_KEYLABEL
;
1170 ekey
[ku
].label
= "";
1171 ekey
[ku
+1].name
= "";
1172 ekey
[ku
+1].label
= "";
1175 flags
= OE_APPEND_CURRENT
;
1177 rc
= optionally_enter(*tobufp
, -FOOTER_ROWS(ps_global
),
1182 ekey
, help
, &flags
);
1189 q_status_message(SM_ORDER
| SM_DING
, 3, 4,
1190 "Internal problem encountered");
1195 case 15 : /* set a role */
1196 {void (*prev_screen
)(struct pine
*) = NULL
, (*redraw
)(void) = NULL
;
1198 redraw
= ps_global
->redrawer
;
1199 ps_global
->redrawer
= NULL
;
1200 prev_screen
= ps_global
->prev_screen
;
1202 ps_global
->next_screen
= SCREEN_FUN_NULL
;
1204 if(role_select_screen(ps_global
, &role
,
1205 outgoing
->remail
? MC_BOUNCE
: MC_FORWARD
) < 0)
1206 cmd_cancelled(_("Set Role"));
1209 role
= combine_inherited_role(role
);
1211 role
= (ACTION_S
*) fs_get(sizeof(*role
));
1212 memset((void *) role
, 0, sizeof(*role
));
1213 role
->nick
= cpystr("Default Role");
1220 ps_global
->next_screen
= prev_screen
;
1221 ps_global
->redrawer
= redraw
;
1222 ps_global
->mangled_screen
= 1;
1224 if(role
&& role
->from
&& !ps_global
->never_allow_changing_from
){
1225 mail_free_address (&outgoing
->from
);
1226 outgoing
->from
= copyaddrlist(role
->from
);
1227 if(!(flagsarg
& SS_NULLRP
)){
1228 fs_give((void **) &outgoing
->return_path
);
1229 outgoing
->return_path
= rfc822_cpy_adr(outgoing
->from
);
1232 if(rolep
) *rolep
= role
;
1237 if((p
= get_prev_hist(history
, *tobufp
, 0, NULL
)) != NULL
){
1238 strncpy(*tobufp
, p
, resize_len
);
1239 (*tobufp
)[resize_len
-1] = '\0';
1247 if((p
= get_next_hist(history
, *tobufp
, 0, NULL
)) != NULL
){
1248 strncpy(*tobufp
, p
, resize_len
);
1249 (*tobufp
)[resize_len
-1] = '\0';
1258 {void (*redraw
) (void) = ps_global
->redrawer
;
1259 char *returned_addr
= NULL
;
1263 int got_something
= 0;
1265 push_titlebar_state();
1266 returned_addr
= addr_book_bounce();
1269 * Just make it look like user typed this list in.
1273 if((l
=resize_len
) < (len
= strlen(returned_addr
)) + 1){
1275 fs_resize((void **) tobufp
, (size_t) (l
+1));
1278 strncpy(*tobufp
, returned_addr
, l
);
1279 (*tobufp
)[l
] = '\0';
1280 fs_give((void **)&returned_addr
);
1284 pop_titlebar_state();
1286 if((ps_global
->redrawer
= redraw
) != NULL
) /* reset old value, and test */
1287 (*ps_global
->redrawer
)();
1293 if(*tobufp
&& **tobufp
!= '\0'){
1294 char *errbuf
, *addr
;
1297 save_hist(history
, *tobufp
, 0, NULL
);
1302 * If role has an fcc, use it instead of what build_address
1305 if(role
&& role
->fcc
){
1307 fs_give((void **) &ba_fcc
.tptr
);
1309 ba_fcc
.tptr
= cpystr(role
->fcc
);
1312 if(build_address(*tobufp
, &addr
, &errbuf
,
1313 (role
&& role
->fcc
) ? NULL
: &ba_fcc
, NULL
) >= 0){
1317 fs_give((void **)&errbuf
);
1319 if((l
=strlen(*tobufp
)) < (tolen
= strlen(addr
)) + 1){
1321 fs_resize((void **) tobufp
, (size_t) (l
+1));
1324 strncpy(*tobufp
, addr
, l
);
1325 (*tobufp
)[l
] = '\0';
1327 *used_tobufval
= cpystr(addr
);
1329 /* confirm address */
1330 if(flagsarg
& SS_PROMPTFORTO
){
1331 char dsn_string
[30];
1332 int dsn_label
= 0, dsn_show
, i
;
1333 int verbose_label
= 0;
1336 strings2outgoing(header
, body
, NULL
, 0);
1338 if((flagsarg
& SS_PROMPTFORTO
)
1339 && ((x
= check_addresses(header
)) == CA_BAD
1340 || (x
== CA_EMPTY
&& F_OFF(F_FCC_ON_BOUNCE
,
1342 /*--- Addresses didn't check out---*/
1349 opts
[i
++].label
= N_("Yes");
1354 opts
[i
++].label
= N_("No");
1356 call_mailer_flags
&= ~CM_VERBOSE
; /* clear verbose */
1357 if(F_ON(F_VERBOSE_POST
, ps_global
)){
1358 /* setup keymenu slot to toggle verbose mode */
1359 opts
[i
].ch
= ctrl('W');
1361 opts
[i
].name
= "^W";
1362 verbose_label
= i
++;
1363 if(F_ON(F_DSN
, ps_global
)){
1367 opts
[i
++].label
= "";
1371 /* clear DSN flags */
1372 call_mailer_flags
&= ~(CM_DSN_NEVER
| CM_DSN_DELAY
| CM_DSN_SUCCESS
| CM_DSN_FULL
);
1373 if(F_ON(F_DSN
, ps_global
)){
1374 /* setup keymenu slots to toggle dsn bits */
1378 opts
[i
].label
= "DSNOpts";
1383 opts
[i
++].label
= "";
1387 opts
[i
++].label
= "";
1391 opts
[i
++].label
= "";
1399 dsn_show
= (call_mailer_flags
& CM_DSN_SHOW
);
1400 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
,
1401 "%s%s%s%s%s%sto \"%s\" ? ",
1402 prmpt_cnf
? prmpt_cnf
: "Send message ",
1403 ((call_mailer_flags
& CM_VERBOSE
)
1406 (call_mailer_flags
& CM_VERBOSE
)
1407 ? "in verbose mode" : "",
1408 (dsn_show
&& (call_mailer_flags
& CM_VERBOSE
))
1410 (dsn_show
) ? dsn_string
: "",
1411 ((call_mailer_flags
& CM_VERBOSE
) || dsn_show
)
1415 : (F_ON(F_FCC_ON_BOUNCE
, ps_global
)
1416 && ba_fcc
.tptr
&& ba_fcc
.tptr
[0])
1419 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
1421 if((strlen(tmp_20k_buf
) >
1422 ps_global
->ttyo
->screen_cols
- 2) &&
1423 ps_global
->ttyo
->screen_cols
>= 7)
1424 strncpy(tmp_20k_buf
+ps_global
->ttyo
->screen_cols
-7,
1425 "...? ", SIZEOF_20KBUF
-ps_global
->ttyo
->screen_cols
-7);
1427 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
1430 opts
[verbose_label
].label
=
1431 /* TRANSLATORS: several possible key labels follow */
1432 (call_mailer_flags
& CM_VERBOSE
) ? N_("Normal") : N_("Verbose");
1434 if(F_ON(F_DSN
, ps_global
)){
1435 if(call_mailer_flags
& CM_DSN_SHOW
){
1436 opts
[dsn_label
].label
=
1437 (call_mailer_flags
& CM_DSN_DELAY
)
1438 ? N_("NoDelay") : N_("Delay");
1439 opts
[dsn_label
+1].ch
= 's';
1440 opts
[dsn_label
+1].label
=
1441 (call_mailer_flags
& CM_DSN_SUCCESS
)
1442 ? N_("NoSuccess") : N_("Success");
1443 opts
[dsn_label
+2].ch
= 'x';
1444 opts
[dsn_label
+2].label
=
1445 (call_mailer_flags
& CM_DSN_NEVER
)
1446 ? N_("ErrRets") : N_("NoErrRets");
1447 opts
[dsn_label
+3].ch
= 'h';
1448 opts
[dsn_label
+3].label
=
1449 (call_mailer_flags
& CM_DSN_FULL
)
1450 ? N_("RetHdrs") : N_("RetFull");
1454 rv
= radio_buttons(tmp_20k_buf
,
1455 -FOOTER_ROWS(ps_global
), opts
,
1456 'y', 'z', NO_HELP
, RB_NORM
);
1457 if(rv
== 'y'){ /* user ACCEPTS! */
1461 else if(rv
== 'n'){ /* Declined! */
1464 else if(rv
== 'z'){ /* Cancelled! */
1467 else if(rv
== 12){ /* flip verbose bit */
1468 if(call_mailer_flags
& CM_VERBOSE
)
1469 call_mailer_flags
&= ~CM_VERBOSE
;
1471 call_mailer_flags
|= CM_VERBOSE
;
1473 else if(call_mailer_flags
& CM_DSN_SHOW
){
1474 if(rv
== 's'){ /* flip success bit */
1475 call_mailer_flags
^= CM_DSN_SUCCESS
;
1476 /* turn off related bits */
1477 if(call_mailer_flags
& CM_DSN_SUCCESS
)
1478 call_mailer_flags
&= ~(CM_DSN_NEVER
);
1480 else if(rv
== 'd'){ /* flip delay bit */
1481 call_mailer_flags
^= CM_DSN_DELAY
;
1482 /* turn off related bits */
1483 if(call_mailer_flags
& CM_DSN_DELAY
)
1484 call_mailer_flags
&= ~(CM_DSN_NEVER
);
1486 else if(rv
== 'x'){ /* flip never bit */
1487 call_mailer_flags
^= CM_DSN_NEVER
;
1488 /* turn off related bits */
1489 if(call_mailer_flags
& CM_DSN_NEVER
)
1490 call_mailer_flags
&= ~(CM_DSN_SUCCESS
| CM_DSN_DELAY
);
1492 else if(rv
== 'h'){ /* flip full bit */
1493 call_mailer_flags
^= CM_DSN_FULL
;
1496 else if(rv
== 'd'){ /* show dsn options */
1497 call_mailer_flags
|= (CM_DSN_SHOW
| CM_DSN_SUCCESS
| CM_DSN_DELAY
| CM_DSN_FULL
);
1500 snprintf(dsn_string
, sizeof(dsn_string
), _("DSN requested[%s%s%s%s]"),
1501 (call_mailer_flags
& CM_DSN_NEVER
)
1503 (call_mailer_flags
& CM_DSN_DELAY
)
1505 (call_mailer_flags
& CM_DSN_SUCCESS
)
1507 (call_mailer_flags
& CM_DSN_NEVER
)
1509 : (call_mailer_flags
& CM_DSN_FULL
) ? "-Full"
1511 dsn_string
[sizeof(dsn_string
)-1] = '\0';
1516 fs_give((void **)&addr
);
1518 if(!(flagsarg
& SS_PROMPTFORTO
) || sendit
){
1520 CONTEXT_S
*fcc_cntxt
= NULL
;
1522 if(F_ON(F_FCC_ON_BOUNCE
, ps_global
)){
1524 fcc
= cpystr(ba_fcc
.tptr
);
1529 * If special name "inbox" then replace it with the
1532 if(ps_global
->VAR_INBOX_PATH
1533 && strucmp(fcc
, ps_global
->inbox_name
) == 0){
1536 replace_fcc
= cpystr(ps_global
->VAR_INBOX_PATH
);
1537 fs_give((void **) &fcc
);
1542 /*---- Check out fcc -----*/
1544 (void) commence_fcc(fcc
, &fcc_cntxt
, FALSE
);
1546 dprint((4,"can't open fcc, cont\n"));
1547 if(!(flagsarg
& SS_PROMPTFORTO
)){
1549 fs_give((void **)&fcc
);
1557 so_truncate(lmc
.so
, fcc_size_guess(*body
) + 2048);
1562 if(!(outgoing
->to
|| outgoing
->cc
|| outgoing
->bcc
1564 q_status_message(SM_ORDER
, 3, 5, _("No recipients specified!"));
1568 if(outgoing
->to
|| outgoing
->cc
|| outgoing
->bcc
){
1569 char **alt_smtp
= NULL
;
1571 if(role
&& role
->smtp
){
1572 if(ps_global
->FIX_SMTP_SERVER
1573 && ps_global
->FIX_SMTP_SERVER
[0])
1574 q_status_message(SM_ORDER
| SM_DING
, 5, 5, _("Use of a role-defined smtp-server is administratively prohibited"));
1576 alt_smtp
= role
->smtp
;
1579 result
= call_mailer(header
, *body
, alt_smtp
,
1581 call_mailer_file_result
,
1583 mark_address_failure_for_pico(header
);
1588 if(result
== 1 && !lmc
.so
)
1589 q_status_message(SM_ORDER
, 0, 3, _("Message sent"));
1591 /*----- Was there an fcc involved? -----*/
1595 && pine_rfc822_output(header
, *body
, NULL
, NULL
))){
1598 strncpy(label
, "Fcc", sizeof(label
));
1599 label
[sizeof(label
)-1] = '\0';
1600 if(strcmp(fcc
, ps_global
->VAR_DEFAULT_FCC
)){
1601 snprintf(label
+ 3, sizeof(label
)-3, " to %s", fcc
);
1602 label
[sizeof(label
)-1] = '\0';
1605 /* Now actually copy to fcc folder and close */
1607 write_fcc(fcc
, fcc_cntxt
, lmc
.so
, NULL
,
1609 F_ON(F_MARK_FCC_SEEN
, ps_global
)
1612 else if(result
== 0){
1613 q_status_message(SM_ORDER
,3,5,
1614 _("Fcc Failed!. No message saved."));
1616 dprint((1, "explicit fcc write failed!\n"));
1623 dprint((1, "Bounce failed\n"));
1624 if(!(flagsarg
& SS_PROMPTFORTO
))
1629 else if(result
== 1){
1631 q_status_message(SM_ORDER
, 0, 3,
1634 int avail
= ps_global
->ttyo
->screen_cols
-2;
1636 char *part1
= "Message sent and ";
1637 char *part2
= fcc_result
? "" : "NOT ";
1638 char *part3
= "copied to ";
1639 fcclen
= strlen(fcc
);
1641 need
= 2 + strlen(part1
) + strlen(part2
) +
1642 strlen(part3
) + fcclen
;
1644 if(need
> avail
&& fcclen
> 6)
1645 fcclen
-= MIN(fcclen
-6, need
-avail
);
1647 q_status_message4(SM_ORDER
, 0, 3,
1649 part1
, part2
, part3
,
1651 (char *)tmp_20k_buf
,
1653 fcclen
, FrontDots
));
1658 fs_give((void **)&fcc
);
1661 q_status_message(SM_ORDER
, 0, 3, _("Send cancelled"));
1666 q_status_message1(SM_ORDER
| SM_DING
, 3, 5,
1667 _("Error in address: %s"), errbuf
);
1669 fs_give((void **)&errbuf
);
1671 if(!(flagsarg
& SS_PROMPTFORTO
))
1679 q_status_message(SM_ORDER
| SM_DING
, 3, 5,
1680 _("No addressee! No e-mail sent."));
1689 q_status_message(SM_ORDER
, 0, 3, _("Send cancelled"));
1695 help
= (help
== NO_HELP
)
1696 ? (outgoing
->remail
== NULL
1704 char *new_nickname
= NULL
;
1708 ambiguity
= abook_nickname_complete(*tobufp
, &new_nickname
,
1709 (lastrc
==rc
&& !(flags
& OE_USER_MODIFIED
)), ANC_AFTERCOMMA
);
1712 if((l
=strlen(new_nickname
)) > resize_len
){
1714 fs_resize((void **) tobufp
, resize_len
+1);
1717 strncpy(*tobufp
, new_nickname
, l
);
1718 (*tobufp
)[l
] = '\0';
1721 fs_give((void **) &new_nickname
);
1730 case 4: /* can't suspend */
1738 fs_give((void **)&ba_fcc
.tptr
);
1740 pine_free_env(&header
);
1747 * pine_simple_send_header - generate header suitable for simple_sending
1750 pine_simple_send_header(ENVELOPE
*outgoing
, char **fccp
, char ***tobufpp
)
1754 static struct headerentry he_dummy
;
1756 header
= pine_new_env(outgoing
, fccp
, tobufpp
, NULL
);
1758 /* assign he_dummy to "To:" field "he" for strings2outgoing */
1759 for(pf
= header
->local
; pf
&& pf
->name
; pf
= pf
->next
)
1760 if(pf
->type
== Address
&& !strucmp(pf
->name
, "to")){
1761 memset((void *) &he_dummy
, 0, sizeof(he_dummy
));
1762 pf
->extdata
= (void *) &he_dummy
;
1772 /*----------------------------------------------------------------------
1773 Prepare data structures for pico, call pico, then post message
1775 Args: outgoing -- Partially formatted outgoing ENVELOPE
1776 body -- Body of outgoing message
1777 editor_title -- Title for anchor line in composer
1778 fcc_arg -- The file carbon copy field
1779 reply -- Struct describing set of msgs being replied-to
1781 custom -- custom header list.
1784 Result: message is edited, then postponed, cancelled or sent.
1793 subject passed in, edited and cannonized here
1794 to possibly passed in, edited and cannonized here
1795 cc possibly passed in, edited and cannonized here
1796 bcc edited and cannonized here
1797 in_reply_to generated in reply() and passed in
1800 Storage for these fields comes from anywhere outside. It is remalloced
1801 here so the composer can realloc them if needed. The copies here are also
1804 Can only deal with message bodies that are either TYPETEXT or TYPEMULTIPART
1805 with the first part TYPETEXT! All newlines in the text here also end with
1808 There's a further assumption that the text in the TYPETEXT part is
1809 stored in a storage object (see filter.c).
1812 pine_send(ENVELOPE
*outgoing
, struct mail_bodystruct
**body
,
1813 char *editor_title
, ACTION_S
*role
, char *fcc_arg
,
1814 REPLY_S
*reply
, REDRAFT_POS_S
*redraft_pos
, char *lcc_arg
,
1815 PINEFIELD
*custom
, int flags
)
1817 int i
, fixed_cnt
, total_cnt
, index
,
1818 editor_result
= 0, body_start
= 0, use_news_order
= 0;
1819 char *p
, *addr
, *fcc
, *fcc_to_free
= NULL
;
1820 char *start_here_name
= NULL
;
1821 char *suggested_nntp_server
= NULL
;
1823 struct headerentry
*he
, *headents
, *he_to
= NULL
, *he_fcc
= NULL
, *he_news
= NULL
, *he_lcc
= NULL
,
1825 PINEFIELD
*pfields
, *pf
, *pf_nobody
= NULL
, *pf_to
= NULL
,
1826 *pf_smtp_server
= NULL
, *pf_nntp_server
= NULL
,
1827 *pf_fcc
= NULL
, *pf_err
= NULL
, *pf_uid
= NULL
, *pf_mbox
= NULL
, *pf_curpos
= NULL
,
1828 *pf_ourrep
= NULL
, *pf_ourhdrs
= NULL
, **sending_order
;
1830 ADDRESS
*lcc_addr
= NULL
;
1831 ADDRESS
*nobody_addr
= NULL
;
1832 BODY_PARTICULARS_S
*bp
;
1833 STORE_S
*orig_so
= NULL
;
1834 PICO pbuf1
, *save_previous_pbuf
;
1836 REDRAFT_POS_S
*local_redraft_pos
= NULL
;
1838 dprint((1,"\n=== send called ===\n"));
1840 save_previous_pbuf
= pbf
;
1842 standard_picobuf_setup(pbf
);
1845 * Cancel any pending initial commands since pico uses a different
1846 * input routine. If we didn't cancel them, they would happen after
1847 * we returned from the editor, which would be confusing.
1849 if(ps_global
->in_init_seq
){
1850 ps_global
->in_init_seq
= 0;
1851 ps_global
->save_in_init_seq
= 0;
1853 if(ps_global
->initial_cmds
){
1854 if(ps_global
->free_initial_cmds
)
1855 fs_give((void **)&(ps_global
->free_initial_cmds
));
1857 ps_global
->initial_cmds
= 0;
1860 F_SET(F_USE_FK
,ps_global
,ps_global
->orig_use_fkeys
);
1863 #if defined(DOS) || defined(OS2)
1864 if(!dos_valid_from()){
1865 pbf
= save_previous_pbuf
;
1871 pbf
->upload
= (ps_global
->VAR_UPLOAD_CMD
1872 && ps_global
->VAR_UPLOAD_CMD
[0])
1873 ? upload_msg_to_pico
: NULL
;
1876 pbf
->msgntext
= message_format_for_pico
;
1877 pbf
->mimetype
= mime_type_for_pico
;
1878 pbf
->exittest
= send_exit_for_pico
;
1879 pbf
->user_says_noflow
= dont_flow_this_time
;
1880 pbf
->newthread
= new_thread_on_blank_subject
;
1881 ps_global
->newthread
= 0; /* reset this value */
1882 if(F_OFF(F_CANCEL_CONFIRM
, ps_global
))
1883 pbf
->canceltest
= cancel_for_pico
;
1885 pbf
->dict
= (ps_global
->VAR_DICTIONARY
1886 && ps_global
->VAR_DICTIONARY
[0]
1887 && ps_global
->VAR_DICTIONARY
[0][0])
1888 ? ps_global
->VAR_DICTIONARY
: NULL
;
1889 pbf
->chosen_dict
= -1; /* not chosen yet */
1890 #endif /* _WINDOWS */
1891 pbf
->alt_ed
= (ps_global
->VAR_EDITOR
&& ps_global
->VAR_EDITOR
[0] &&
1892 ps_global
->VAR_EDITOR
[0][0])
1893 ? ps_global
->VAR_EDITOR
: NULL
;
1894 pbf
->alt_spell
= (ps_global
->VAR_SPELLER
&& ps_global
->VAR_SPELLER
[0])
1895 ? ps_global
->VAR_SPELLER
: NULL
;
1896 pbf
->always_spell_check
= F_ON(F_ALWAYS_SPELL_CHECK
, ps_global
);
1897 pbf
->quote_str
= reply
&& reply
->prefix
? reply
->prefix
: "> ";
1898 /* We actually want to set this only if message we're sending is flowed */
1899 pbf
->strip_ws_before_send
= F_ON(F_STRIP_WS_BEFORE_SEND
, ps_global
);
1900 pbf
->allow_flowed_text
= (F_OFF(F_QUELL_FLOWED_TEXT
, ps_global
)
1901 && F_OFF(F_STRIP_WS_BEFORE_SEND
, ps_global
)
1902 && (strcmp(pbf
->quote_str
, "> ") == 0
1903 || strcmp(pbf
->quote_str
, ">") == 0));
1904 pbf
->edit_offset
= 0;
1905 title
= cpystr(set_titlebar(editor_title
,
1906 ps_global
->mail_stream
,
1907 ps_global
->context_current
,
1908 ps_global
->cur_folder
,ps_global
->msgmap
,
1909 0, FolderName
, 0, 0, NULL
));
1910 pbf
->pine_anchor
= title
;
1912 #if defined(DOS) || defined(OS2)
1913 if(!pbf
->oper_dir
&& ps_global
->VAR_FILE_DIR
){
1914 pbf
->oper_dir
= ps_global
->VAR_FILE_DIR
;
1918 if(redraft_pos
&& editor_title
&& !strcmp(editor_title
, COMPOSE_MAIL_TITLE
))
1919 pbf
->pine_flags
|= P_CHKPTNOW
;
1921 /* NOTE: initial cursor position set below */
1923 dprint((9, "flags: %x\n", pbf
->pine_flags
));
1926 * When user runs compose and the current folder is a newsgroup,
1927 * offer to post to the current newsgroup.
1929 if(!(outgoing
->to
|| (outgoing
->newsgroups
&& *outgoing
->newsgroups
))
1930 && IS_NEWS(ps_global
->mail_stream
)){
1931 char prompt
[200], news_group
[MAILTMPLEN
];
1933 pine_send_newsgroup_name(ps_global
->mail_stream
->mailbox
, news_group
,
1934 sizeof(news_group
));
1937 * Replies don't get this far because To or Newsgroups will already
1938 * be filled in. So must be either ordinary compose or forward.
1939 * Forward sets subject, so use that to tell the difference.
1941 if(news_group
[0] && !outgoing
->subject
){
1944 char *errmsg
= NULL
;
1945 BUILDER_ARG
*fcc_build
= NULL
;
1947 if(F_OFF(F_COMPOSE_TO_NEWSGRP
,ps_global
)){
1948 snprintf(prompt
, sizeof(prompt
),
1949 _("Post to current newsgroup (%s)"), news_group
);
1950 prompt
[sizeof(prompt
)-1] = '\0';
1951 ch
= want_to(prompt
, 'y', 'x', NO_HELP
, WT_NORM
);
1956 if(outgoing
->newsgroups
)
1957 fs_give((void **)&outgoing
->newsgroups
);
1959 if(!fcc_arg
&& !(role
&& role
->fcc
)){
1960 fcc_build
= (BUILDER_ARG
*)fs_get(sizeof(BUILDER_ARG
));
1961 memset((void *)fcc_build
, 0, sizeof(BUILDER_ARG
));
1962 fcc_build
->tptr
= fcc_to_free
;
1965 ret_val
= news_build(news_group
, &outgoing
->newsgroups
,
1966 &errmsg
, fcc_build
, NULL
);
1969 if(outgoing
->newsgroups
)
1970 fs_give((void **)&outgoing
->newsgroups
);
1972 outgoing
->newsgroups
= cpystr(news_group
);
1975 if(!fcc_arg
&& !(role
&& role
->fcc
)){
1976 fcc_arg
= fcc_to_free
= fcc_build
->tptr
;
1977 fs_give((void **)&fcc_build
);
1982 q_status_message(SM_ORDER
, 3, 3, errmsg
);
1983 display_message(NO_OP_COMMAND
);
1986 fs_give((void **)&errmsg
);
1992 q_status_message(SM_ORDER
, 0, 3, _("Message cancelled"));
1993 dprint((4, "=== send: cancelled\n"));
1994 pbf
= save_previous_pbuf
;
2005 if(F_ON(F_PREDICT_NNTP_SERVER
, ps_global
)
2006 && outgoing
->newsgroups
&& *outgoing
->newsgroups
2007 && IS_NEWS(ps_global
->mail_stream
)){
2010 if(mail_valid_net_parse(ps_global
->mail_stream
->original_mailbox
,
2012 if(!strucmp(news_mb
.service
, "nntp")){
2013 if(*ps_global
->mail_stream
->original_mailbox
== '{'){
2014 char *svcp
= NULL
, *psvcp
;
2016 suggested_nntp_server
=
2017 cpystr(ps_global
->mail_stream
->original_mailbox
+ 1);
2018 if((p
= strindex(suggested_nntp_server
, '}')) != NULL
)
2020 for(p
= strindex(suggested_nntp_server
, '/'); p
&& *p
;
2021 p
= strindex(p
, '/')){
2022 /* take out /nntp, which gets added in nntp_open */
2023 if(!struncmp(p
, "/nntp", 5))
2025 else if(!struncmp(p
, "/service=nntp", 13))
2027 else if(!struncmp(p
, "/service=\"nntp\"", 15))
2034 else if(*svcp
== '/' || *svcp
== ':'){
2035 for(psvcp
= p
; *svcp
; svcp
++, psvcp
++)
2044 suggested_nntp_server
= cpystr(news_mb
.orighost
);
2049 * If we don't already have custom headers set and the role has custom
2050 * headers, then incorporate those custom headers into "custom".
2053 PINEFIELD
*dflthdrs
= NULL
, *rolehdrs
= NULL
;
2055 dflthdrs
= parse_custom_hdrs(ps_global
->VAR_CUSTOM_HDRS
, UseAsDef
);
2057 * If we allow the Combine argument here, we're saying that we want to
2058 * combine the values from the envelope and the role for the fields To,
2059 * Cc, Bcc, and Newsgroups. For example, if we are replying to a message
2060 * we'll have a To in the envelope because we're replying. If our role also
2061 * has a To action, then Combine would combine those two and offer both
2062 * to the user. We've decided against doing this. Instead, we always use
2063 * Replace, and the role's header value replaces the value from the
2064 * envelope. It might also make sense in some cases to do the opposite,
2065 * which would be treating the role headers as defaults, just like
2068 #ifdef WANT_TO_COMBINE_ADDRESSES
2069 if(role
&& role
->cstm
)
2070 rolehdrs
= parse_custom_hdrs(role
->cstm
, Combine
);
2072 if(role
&& role
->cstm
)
2073 rolehdrs
= parse_custom_hdrs(role
->cstm
, Replace
);
2077 custom
= combine_custom_headers(dflthdrs
, rolehdrs
);
2079 free_prompts(dflthdrs
);
2080 free_customs(dflthdrs
);
2084 free_prompts(rolehdrs
);
2085 free_customs(rolehdrs
);
2092 g_rolenick
= role
? role
->nick
: NULL
;
2094 /* how many fixed fields are there? */
2095 for(fixed_cnt
= 0; pf_template
&& pf_template
[fixed_cnt
].name
; fixed_cnt
++)
2098 total_cnt
= fixed_cnt
+ count_custom_hdrs_pf(custom
,1);
2100 /* the fixed part of the PINEFIELDs */
2101 i
= fixed_cnt
* sizeof(PINEFIELD
);
2102 pfields
= (PINEFIELD
*)fs_get((size_t) i
);
2103 memset(pfields
, 0, (size_t) i
);
2105 /* temporary headerentry array for pico */
2106 i
= (total_cnt
+ 1) * sizeof(struct headerentry
);
2107 headents
= (struct headerentry
*)fs_get((size_t) i
);
2108 memset(headents
, 0, (size_t) i
);
2110 i
= total_cnt
* sizeof(PINEFIELD
*);
2111 sending_order
= (PINEFIELD
**)fs_get((size_t) i
);
2112 memset(sending_order
, 0, (size_t) i
);
2114 pbf
->headents
= headents
;
2115 header
.env
= outgoing
;
2116 header
.local
= pfields
;
2117 header
.sending_order
= sending_order
;
2119 /* custom part of PINEFIELDs */
2120 header
.custom
= custom
;
2126 * For Address types, pf->addr points to an ADDRESS *.
2127 * If that address is in the "outgoing" envelope, it will
2128 * be freed by the caller, otherwise, it should be freed here.
2129 * Pf->textbuf for an Address is used a little to set up a default,
2130 * but then is freed right away below. Pf->scratch is used for a
2131 * pointer to some alloced space for pico to edit in. Addresses in
2132 * the custom area are freed by free_customs().
2134 * For FreeText types, pf->addr is not used. Pf->text points to a
2135 * pointer that points to the text. Pf->textbuf points to a copy of
2136 * the text that must be freed before we leave, otherwise, it is
2137 * probably a pointer into the envelope and that gets freed by the
2140 * He->realaddr is the pointer to the text that pico actually edits.
2143 #if !(defined(DOS) || defined(OS2)) || defined(NOAUTH)
2149 if(outgoing
->newsgroups
&& *outgoing
->newsgroups
)
2152 /* initialize the fixed header elements of the two temp arrays */
2153 for(i
=0; i
< fixed_cnt
; i
++, pf
++){
2154 static int news_order
[] = {
2155 N_AUTHRCVD
,N_FROM
, N_REPLYTO
, N_NEWS
, N_TO
, N_CC
, N_BCC
,
2156 N_FCC
, N_LCC
, N_ATTCH
, N_SUBJ
, N_REF
, N_DATE
, N_INREPLY
,
2157 N_MSGID
, N_PRIORITY
, N_USERAGENT
, N_NOBODY
, N_POSTERR
, N_RPLUID
, N_RPLMBOX
,
2158 N_SMTP
, N_NNTP
, N_CURPOS
, N_OURREPLYTO
, N_OURHDRS
2159 #if !(defined(DOS) || defined(OS2)) || defined(NOAUTH)
2165 /* slightly different editing order if sending to news */
2166 if(use_news_order
&&
2167 index
>= 0 && index
< sizeof(news_order
)/sizeof(news_order
[0]))
2168 index
= news_order
[i
];
2170 /* copy the templates */
2171 *he
= he_template
[index
];
2173 pf
->name
= cpystr(pf_template
[index
].name
);
2174 if(index
== N_SENDER
&& F_ON(F_USE_SENDER_NOT_X
, ps_global
)){
2175 /* slide string over so it is Sender instead of X-X-Sender */
2176 for(p
= pf
->name
+4; *p
!= '\0'; p
++)
2180 pf
->type
= pf_template
[index
].type
;
2181 pf
->canedit
= pf_template
[index
].canedit
;
2182 pf
->rcptto
= pf_template
[index
].rcptto
;
2183 pf
->writehdr
= pf_template
[index
].writehdr
;
2184 pf
->localcopy
= pf_template
[index
].localcopy
;
2188 he
->rich_header
= view_as_rich(pf
->name
, he
->rich_header
);
2189 if(F_OFF(F_ENABLE_TAB_COMPLETE
,ps_global
))
2190 he
->nickcmpl
= NULL
;
2193 case FreeText
: /* realaddr points to c-client env */
2194 if(index
== N_NEWS
){
2195 sending_order
[1] = pf
;
2196 he
->realaddr
= &outgoing
->newsgroups
;
2199 switch(set_default_hdrval(pf
, custom
)){
2202 fs_give((void **)he
->realaddr
);
2204 *he
->realaddr
= pf
->textbuf
;
2210 if(*he
->realaddr
){ /* combine values */
2211 if(pf
->textbuf
&& *pf
->textbuf
){
2215 l
= strlen(*he
->realaddr
) + strlen(pf
->textbuf
) + 1;
2216 combined_hdr
= (char *) fs_get((l
+1) * sizeof(char));
2217 strncpy(combined_hdr
, *he
->realaddr
, l
);
2218 combined_hdr
[l
] = '\0';
2219 strncat(combined_hdr
, ",", l
+1-1-strlen(combined_hdr
));
2220 combined_hdr
[l
] = '\0';
2221 strncat(combined_hdr
, pf
->textbuf
, l
+1-1-strlen(combined_hdr
));
2222 combined_hdr
[l
] = '\0';
2224 fs_give((void **)he
->realaddr
);
2225 *he
->realaddr
= combined_hdr
;
2226 q_status_message(SM_ORDER
, 3, 3,
2227 "Adding newsgroup from role");
2232 *he
->realaddr
= pf
->textbuf
;
2239 /* if no value, use default */
2241 *he
->realaddr
= pf
->textbuf
;
2251 /* If there is a newsgroup, we'd better show it */
2252 if(outgoing
->newsgroups
&& *outgoing
->newsgroups
)
2253 he
->rich_header
= 0; /* force on by default */
2256 fs_give((void **)&pf
->textbuf
);
2258 pf
->text
= he
->realaddr
;
2260 else if(index
== N_DATE
){
2261 sending_order
[2] = pf
;
2262 pf
->text
= (char **) &outgoing
->date
;
2265 else if(index
== N_INREPLY
){
2266 sending_order
[NN
+9] = pf
;
2267 pf
->text
= &outgoing
->in_reply_to
;
2270 else if(index
== N_MSGID
){
2271 sending_order
[NN
+10] = pf
;
2272 pf
->text
= &outgoing
->message_id
;
2275 else if(index
== N_REF
){
2276 sending_order
[NN
+11] = pf
;
2277 pf
->text
= &outgoing
->references
;
2280 else if(index
== N_PRIORITY
){
2281 sending_order
[NN
+12] = pf
;
2282 pf
->text
= &pf
->textbuf
;
2285 else if(index
== N_USERAGENT
){
2286 sending_order
[NN
+13] = pf
;
2287 pf
->text
= &pf
->textbuf
;
2288 pf
->textbuf
= generate_user_agent();
2291 else if(index
== N_POSTERR
){
2292 sending_order
[NN
+14] = pf
;
2294 pf
->text
= &pf
->textbuf
;
2297 else if(index
== N_RPLUID
){
2298 sending_order
[NN
+15] = pf
;
2300 pf
->text
= &pf
->textbuf
;
2303 else if(index
== N_RPLMBOX
){
2304 sending_order
[NN
+16] = pf
;
2306 pf
->text
= &pf
->textbuf
;
2309 else if(index
== N_SMTP
){
2310 sending_order
[NN
+17] = pf
;
2311 pf_smtp_server
= pf
;
2312 pf
->text
= &pf
->textbuf
;
2315 else if(index
== N_NNTP
){
2316 sending_order
[NN
+18] = pf
;
2317 pf_nntp_server
= pf
;
2318 pf
->text
= &pf
->textbuf
;
2321 else if(index
== N_CURPOS
){
2322 sending_order
[NN
+19] = pf
;
2324 pf
->text
= &pf
->textbuf
;
2327 else if(index
== N_OURREPLYTO
){
2328 sending_order
[NN
+20] = pf
;
2330 pf
->text
= &pf
->textbuf
;
2333 else if(index
== N_OURHDRS
){
2334 sending_order
[NN
+21] = pf
;
2336 pf
->text
= &pf
->textbuf
;
2339 else if(index
== N_AUTHRCVD
){
2340 sending_order
[0] = pf
;
2342 pf
->text
= &pf
->textbuf
;
2346 q_status_message(SM_ORDER
| SM_DING
, 3, 7,
2347 "Botched: Unmatched FreeText header in pine_send");
2352 /* can't do a default for this one */
2354 /* If there is an attachment already, we'd better show them */
2355 if(body
&& *body
&& (*body
)->type
!= TYPETEXT
)
2356 he
->rich_header
= 0; /* force on by default */
2363 sending_order
[3] = pf
;
2364 pf
->addr
= &outgoing
->from
;
2365 if(role
&& role
->from
){
2366 if(ps_global
->never_allow_changing_from
)
2367 q_status_message(SM_ORDER
, 3, 3, _("Site policy doesn't allow changing From address so role's From has no effect"));
2369 outgoing
->from
= copyaddrlist(role
->from
);
2370 he
->display_it
= 1; /* show it */
2371 he
->rich_header
= 0;
2379 sending_order
[NN
+2] = pf
;
2380 pf
->addr
= &outgoing
->to
;
2381 /* If already set, make it act like we typed it in */
2383 && outgoing
->to
->mailbox
2384 && outgoing
->to
->mailbox
[0]
2385 && flags
& PS_STICKY_TO
)
2393 sending_order
[NN
+5] = pf
;
2395 if(ps_global
->VAR_EMPTY_HDR_MSG
2396 && !ps_global
->VAR_EMPTY_HDR_MSG
[0]){
2400 nobody_addr
= mail_newaddr();
2401 nobody_addr
->next
= mail_newaddr();
2402 nobody_addr
->mailbox
= cpystr(rfc1522_encode(tmp_20k_buf
,
2404 (unsigned char *)(ps_global
->VAR_EMPTY_HDR_MSG
2405 ? ps_global
->VAR_EMPTY_HDR_MSG
2406 : "undisclosed-recipients"),
2407 ps_global
->posting_charmap
));
2408 pf
->addr
= &nobody_addr
;
2414 sending_order
[NN
+3] = pf
;
2415 pf
->addr
= &outgoing
->cc
;
2419 sending_order
[NN
+4] = pf
;
2420 pf
->addr
= &outgoing
->bcc
;
2421 /* if bcc exists, make sure it's exposed so nothing's
2422 * sent by mistake...
2430 sending_order
[NN
+1] = pf
;
2431 pf
->addr
= &outgoing
->reply_to
;
2432 if(role
&& role
->replyto
){
2433 if(outgoing
->reply_to
)
2434 mail_free_address(&outgoing
->reply_to
);
2436 outgoing
->reply_to
= copyaddrlist(role
->replyto
);
2437 he
->display_it
= 1; /* show it */
2438 he
->rich_header
= 0;
2444 sending_order
[NN
+7] = pf
;
2445 pf
->addr
= &lcc_addr
;
2448 build_address(lcc_arg
, &addr
, NULL
, NULL
, NULL
);
2449 rfc822_parse_adrlist(&lcc_addr
, addr
,
2450 ps_global
->maildomain
);
2451 fs_give((void **)&addr
);
2457 #if !(defined(DOS) || defined(OS2)) || defined(NOAUTH)
2459 sending_order
[4] = pf
;
2460 pf
->addr
= &outgoing
->sender
;
2465 q_status_message1(SM_ORDER
,3,7,
2466 "Internal error: Address header %s", comatose(index
));
2471 * If this is a reply to news, don't show the regular email
2472 * recipient headers (unless they are non-empty).
2474 if((outgoing
->newsgroups
&& *outgoing
->newsgroups
)
2475 && (index
== N_TO
|| index
== N_CC
2476 || index
== N_BCC
|| index
== N_LCC
)
2477 && (pf
->addr
&& !*pf
->addr
)){
2478 if((ct
=set_default_hdrval(pf
, custom
)) >= UseAsDef
&&
2479 pf
->textbuf
&& *pf
->textbuf
){
2480 removing_trailing_white_space(pf
->textbuf
);
2481 (void)removing_double_quotes(pf
->textbuf
);
2482 build_address(pf
->textbuf
, &addr
, NULL
, NULL
, NULL
);
2483 rfc822_parse_adrlist(pf
->addr
, addr
,
2484 ps_global
->maildomain
);
2485 fs_give((void **)&addr
);
2490 he
->rich_header
= 1; /* hide */
2494 * If this address doesn't already have a value, then we check
2495 * for a default value assigned by the user.
2497 else if(pf
->addr
&& !*pf
->addr
){
2498 if((ct
=set_default_hdrval(pf
, custom
)) >= UseAsDef
&&
2500 (!ps_global
->never_allow_changing_from
&&
2501 F_ON(F_ALLOW_CHANGING_FROM
, ps_global
))) &&
2502 pf
->textbuf
&& *pf
->textbuf
){
2504 removing_trailing_white_space(pf
->textbuf
);
2505 (void)removing_double_quotes(pf
->textbuf
);
2508 * Try to set To based on Lcc. Don't attempt Fcc.
2510 if(index
== N_LCC
&& !he_to
->sticky
&& pf_to
&& pf_to
->addr
){
2511 BUILDER_ARG
*barg
= NULL
;
2515 ppp
= addr_list_string(*pf_to
->addr
, NULL
, 1);
2520 barg
= (BUILDER_ARG
*) fs_get(sizeof(*barg
));
2521 memset(barg
, 0, sizeof(*barg
));
2522 barg
->me
= &(he
->bldr_private
);
2523 barg
->aff
= &(he_to
->bldr_private
);
2524 barg
->tptr
= cpystr(ppp
);
2526 build_addr_lcc(pf
->textbuf
, &addr
, NULL
, barg
, NULL
);
2529 rfc822_parse_adrlist(pf
->addr
, addr
,
2530 ps_global
->maildomain
);
2532 fs_give((void **) &addr
);
2537 if(barg
&& barg
->tptr
&& strcmp(ppp
, barg
->tptr
)){
2540 rfc822_parse_adrlist(&a
, barg
->tptr
,
2541 ps_global
->maildomain
);
2544 mail_free_address(pf_to
->addr
);
2552 fs_give((void **) &barg
->tptr
);
2554 fs_give((void **) &barg
);
2558 fs_give((void **) &ppp
);
2561 build_address(pf
->textbuf
, &addr
, NULL
, NULL
, NULL
);
2562 rfc822_parse_adrlist(pf
->addr
, addr
,
2563 ps_global
->maildomain
);
2565 fs_give((void **) &addr
);
2572 /* if we still don't have a from */
2573 if(index
== N_FROM
&& !*pf
->addr
)
2574 *pf
->addr
= generate_from();
2578 * Addr is already set in the rest of the cases.
2580 else if((index
== N_FROM
|| index
== N_REPLYTO
) && pf
->addr
){
2581 ADDRESS
*adr
= NULL
;
2584 * We get to this case of the ifelse if the from or reply-to
2585 * addr was set by a role above.
2588 /* figure out the default value */
2589 (void)set_default_hdrval(pf
, custom
);
2590 if(pf
->textbuf
&& *pf
->textbuf
){
2591 removing_trailing_white_space(pf
->textbuf
);
2592 (void)removing_double_quotes(pf
->textbuf
);
2593 build_address(pf
->textbuf
, &addr
, NULL
, NULL
, NULL
);
2594 rfc822_parse_adrlist(&adr
, addr
,
2595 ps_global
->maildomain
);
2596 fs_give((void **)&addr
);
2599 /* if value set by role is different from default, show it */
2600 if(adr
&& !address_is_same(*pf
->addr
, adr
))
2601 he
->display_it
= 1; /* start this off showing */
2604 if(!(*pf
->addr
)->mailbox
){
2605 fs_give((void **)pf
->addr
);
2610 mail_free_address(&adr
);
2612 else if((index
== N_TO
|| index
== N_CC
|| index
== N_BCC
)
2614 ADDRESS
*a
= NULL
, **tail
;
2617 * These three are different from the others because we
2618 * might add the addresses to what is already there instead
2622 switch(set_default_hdrval(pf
, custom
)){
2625 mail_free_address(pf
->addr
);
2627 removing_trailing_white_space(pf
->textbuf
);
2628 (void)removing_double_quotes(pf
->textbuf
);
2629 build_address(pf
->textbuf
, &addr
, NULL
, NULL
, NULL
);
2630 rfc822_parse_adrlist(pf
->addr
, addr
, ps_global
->maildomain
);
2631 fs_give((void **)&addr
);
2636 removing_trailing_white_space(pf
->textbuf
);
2637 (void)removing_double_quotes(pf
->textbuf
);
2638 build_address(pf
->textbuf
, &addr
, NULL
, NULL
, NULL
);
2639 rfc822_parse_adrlist(&a
, addr
, ps_global
->maildomain
);
2640 fs_give((void **)&addr
);
2643 for(tail
= pf
->addr
; *tail
; tail
= &(*tail
)->next
)
2645 *tail
= reply_cp_addr(ps_global
, 0, NULL
, NULL
,
2646 *pf
->addr
, NULL
, a
, RCA_ALL
);
2647 q_status_message(SM_ORDER
, 3, 3,
2648 "Adding addresses from role");
2649 mail_free_address(&a
);
2659 he
->display_it
= 1; /* start this off showing */
2662 switch(set_default_hdrval(pf
, custom
)){
2666 mail_free_address(pf
->addr
);
2668 removing_trailing_white_space(pf
->textbuf
);
2669 (void)removing_double_quotes(pf
->textbuf
);
2670 build_address(pf
->textbuf
, &addr
, NULL
, NULL
, NULL
);
2671 rfc822_parse_adrlist(pf
->addr
, addr
, ps_global
->maildomain
);
2672 fs_give((void **)&addr
);
2684 if(pf
->addr
&& *pf
->addr
&& !(*pf
->addr
)->mailbox
){
2685 mail_free_address(pf
->addr
);
2686 he
->display_it
= 1; /* start this off showing */
2689 if(pf
->textbuf
) /* free default value in any case */
2690 fs_give((void **)&pf
->textbuf
);
2692 /* outgoing2strings will alloc the string pf->scratch below */
2693 he
->realaddr
= &pf
->scratch
;
2697 sending_order
[NN
+8] = pf
;
2699 if(role
&& role
->fcc
)
2702 fcc
= get_fcc(fcc_arg
);
2705 fs_give((void **)&fcc_to_free
);
2709 if(((flags
& PS_STICKY_FCC
) && fcc
[0]) || (role
&& role
->fcc
))
2715 if(strcmp(fcc
, ps_global
->VAR_DEFAULT_FCC
) != 0)
2716 he
->display_it
= 1; /* start this off showing */
2718 he
->realaddr
= &fcc
;
2724 sending_order
[NN
+6] = pf
;
2726 switch(set_default_hdrval(pf
, custom
)){
2729 pf
->scratch
= pf
->textbuf
;
2732 if(outgoing
->subject
)
2733 fs_give((void **)&outgoing
->subject
);
2739 /* if no value, use default */
2740 if(outgoing
->subject
){
2741 pf
->scratch
= cpystr(outgoing
->subject
);
2744 pf
->scratch
= pf
->textbuf
;
2751 he
->realaddr
= &pf
->scratch
;
2752 pf
->text
= &outgoing
->subject
;
2756 q_status_message1(SM_ORDER
,3,7,
2757 "Unknown header type %d in pine_send",
2763 * We may or may not want to give the user the chance to edit
2764 * the From and Reply-To lines. If they are listed in either
2765 * Default-composer-hdrs or Customized-hdrs, then they can edit
2767 * If canedit is not set, that means that this header is not in
2768 * the user's customized-hdrs. If rich_header is set, that
2769 * means that this header is not in the user's
2770 * default-composer-hdrs (since From and Reply-To are rich
2771 * by default). So, don't give it an he to edit with in that case.
2773 * For other types, just not setting canedit will cause it to be
2774 * uneditable, regardless of what the user does.
2778 /* to allow it, we let this fall through to the reply-to case below */
2779 if(ps_global
->never_allow_changing_from
||
2780 (F_OFF(F_ALLOW_CHANGING_FROM
, ps_global
) &&
2781 !(role
&& role
->from
))){
2782 if(pf
->canedit
|| !he
->rich_header
)
2783 q_status_message(SM_ORDER
, 3, 3,
2784 _("Not allowed to change header \"From\""));
2786 memset(he
, 0, (size_t)sizeof(*he
));
2792 if(!pf
->canedit
&& he
->rich_header
){
2793 memset(he
, 0, (size_t)sizeof(*he
));
2805 memset(he
, 0, (size_t)sizeof(*he
));
2816 * This is so the builder can tell the composer to fill the affected
2817 * field based on the value in the field on the left.
2819 * Note that this mechanism isn't completely general. Each entry has
2820 * only a single next_affected, so if some other entry points an
2821 * affected entry at an entry with a next_affected, they all inherit
2822 * that next_affected. Since this isn't used much a careful ordering
2823 * of the affected fields should make it a sufficient mechanism.
2825 he_to
->affected_entry
= he_fcc
;
2826 he_news
->affected_entry
= he_fcc
;
2827 he_lcc
->affected_entry
= he_to
;
2828 he_to
->next_affected
= he_fcc
;
2830 (--pf
)->next
= (total_cnt
!= fixed_cnt
) ? header
.custom
: NULL
;
2832 i
--; /* subtract one because N_ATTCH doesn't get a sending_order slot */
2834 * Set up headerentries for custom fields.
2835 * NOTE: "i" is assumed to now index first custom field in sending
2838 for(pf
= pf
->next
; pf
&& pf
->name
; pf
= pf
->next
){
2852 if(pf
->addr
){ /* better be set */
2853 sending_order
[i
++] = pf
;
2854 *he
= he_custom_addr_templ
;
2855 /* change default text into an ADDRESS */
2856 /* strip quotes around whole default */
2857 removing_trailing_white_space(pf
->textbuf
);
2858 (void)removing_double_quotes(pf
->textbuf
);
2859 build_address(pf
->textbuf
, &addr
, NULL
, NULL
, NULL
);
2860 rfc822_parse_adrlist(pf
->addr
, addr
, ps_global
->maildomain
);
2861 fs_give((void **)&addr
);
2863 fs_give((void **)&pf
->textbuf
);
2865 he
->realaddr
= &pf
->scratch
;
2866 if(F_OFF(F_ENABLE_TAB_COMPLETE
,ps_global
))
2867 he
->nickcmpl
= NULL
;
2873 sending_order
[i
++] = pf
;
2874 *he
= he_custom_free_templ
;
2875 he
->realaddr
= &pf
->textbuf
;
2876 pf
->text
= &pf
->textbuf
;
2877 if(((!pf
->val
|| !pf
->val
[0]) && pf
->textbuf
&& pf
->textbuf
[0]) ||
2878 (pf
->val
&& (!pf
->textbuf
|| strcmp(pf
->textbuf
, pf
->val
))))
2879 he
->display_it
= 1; /* show it */
2884 q_status_message1(SM_ORDER
,0,7,"Unknown custom header type %d",
2889 he
->name
= pf
->name
;
2891 /* use first 8 characters for prompt */
2892 he
->prompt
= cpystr(" : ");
2893 strncpy(he
->prompt
, he
->name
, MIN(strlen(he
->name
), he
->prwid
- 2));
2895 he
->rich_header
= view_as_rich(he
->name
, he
->rich_header
);
2900 * Make sure at least *one* field is displayable...
2902 for(index
= -1, i
=0, pf
=header
.local
; pf
&& pf
->name
; pf
=pf
->next
, i
++)
2903 if(HE(pf
) && !HE(pf
)->rich_header
){
2909 * None displayable!!! Warn and display defaults.
2912 q_status_message(SM_ORDER
,0,5,
2913 "No default-composer-hdrs matched, displaying defaults");
2914 for(i
= 0, pf
= header
.local
; pf
; pf
= pf
->next
, i
++)
2915 if((i
== N_TO
|| i
== N_CC
|| i
== N_SUBJ
|| i
== N_ATTCH
)
2917 HE(pf
)->rich_header
= 0;
2921 * Save information about body which set_mime_type_by_grope might change.
2922 * Then, if we get an error sending, we reset these things so that
2923 * grope can do it's thing again after we edit some more.
2925 if ((*body
)->type
== TYPEMULTIPART
)
2926 bp
= save_body_particulars(&(*body
)->nested
.part
->body
);
2928 bp
= save_body_particulars(*body
);
2931 local_redraft_pos
= redraft_pos
;
2933 /*----------------------------------------------------------------------
2934 Loop calling the editor until everything goes well
2937 int saved_user_timeout
;
2939 /* Reset body to what it was when we started. */
2940 if ((*body
)->type
== TYPEMULTIPART
)
2941 reset_body_particulars(bp
, &(*body
)->nested
.part
->body
);
2943 reset_body_particulars(bp
,*body
);
2945 * set initial cursor position based on how many times we've been
2948 if(reply
&& reply
->pseudo
){
2949 pbf
->pine_flags
|= reply
->data
.pico_flags
;
2951 else if(body_start
){
2952 pbf
->pine_flags
|= P_BODY
;
2953 body_start
= 0; /* maybe not next time */
2955 else if(local_redraft_pos
){
2956 pbf
->edit_offset
= local_redraft_pos
->offset
;
2957 /* set the start_here bit in correct header */
2958 for(pf
= header
.local
; pf
&& pf
->name
; pf
= pf
->next
)
2959 if(strcmp(pf
->name
, local_redraft_pos
->hdrname
) == 0
2961 HE(pf
)->start_here
= 1;
2965 /* If didn't find it, we start in body. */
2966 if(!pf
|| !pf
->name
)
2967 pbf
->pine_flags
|= P_BODY
;
2969 else if(reply
&& (!reply
->forw
&& !reply
->forwarded
)){
2970 pbf
->pine_flags
|= P_BODY
;
2973 /* in case these were turned on in previous pass through loop */
2975 pf_nobody
->writehdr
= 0;
2976 pf_nobody
->localcopy
= 0;
2980 pf_fcc
->localcopy
= 0;
2983 * If a sending attempt failed after we passed the message text
2984 * thru a user-defined filter, "orig_so" points to the original
2985 * text. Replace the body's encoded data with the original...
2988 STORE_S
**so
= (STORE_S
**)(((*body
)->type
== TYPEMULTIPART
)
2989 ? &(*body
)->nested
.part
->body
.contents
.text
.data
2990 : &(*body
)->contents
.text
.data
);
2997 * Convert the envelope and body to the string format that
3000 outgoing2strings(&header
, *body
, &pbf
->msgtext
, &pbf
->attachments
, 0);
3002 for(pf
= header
.local
; pf
&& pf
->name
; pf
= pf
->next
){
3004 * If this isn't the first time through this loop, we may have
3005 * freed some of the FreeText headers below so that they wouldn't
3006 * show up as empty headers in the finished message. Need to
3007 * alloc them again here so they can be edited.
3009 if(pf
->type
== FreeText
&& HE(pf
) && !*HE(pf
)->realaddr
)
3010 *HE(pf
)->realaddr
= cpystr("");
3012 if(pf
->type
!= Attachment
&& HE(pf
) && *HE(pf
)->realaddr
)
3013 HE(pf
)->maxlen
= strlen(*HE(pf
)->realaddr
);
3017 * If From is exposed, probably by a role, then start the cursor
3018 * on the first line which isn't filled in. If it isn't, then we
3019 * don't move the cursor, mostly for back-compat.
3021 if((!reply
|| reply
->forw
|| reply
->forwarded
) &&
3022 !local_redraft_pos
&& !(pbf
->pine_flags
& P_BODY
) && he_from
&&
3023 (he_from
->display_it
|| !he_from
->rich_header
)){
3024 for(pf
= header
.local
; pf
&& pf
->name
; pf
= pf
->next
)
3026 (HE(pf
)->display_it
|| !HE(pf
)->rich_header
) &&
3028 (!*HE(pf
)->realaddr
|| !**HE(pf
)->realaddr
)){
3029 HE(pf
)->start_here
= 1;
3035 mswin_setwindowmenu (MENU_COMPOSER
);
3038 cancel_busy_cue(-1);
3039 flush_status_messages(1);
3041 /* turn off user input timeout when in composer */
3042 saved_user_timeout
= ps_global
->hours_to_timeout
;
3043 ps_global
->hours_to_timeout
= 0;
3044 dprint((1, "\n ---- COMPOSER ----\n"));
3045 editor_result
= pico(pbf
);
3046 dprint((4, "... composer returns (0x%x)\n", editor_result
));
3047 ps_global
->hours_to_timeout
= saved_user_timeout
;
3050 mswin_setwindowmenu (MENU_DEFAULT
);
3052 fix_windsize(ps_global
);
3055 * Only reinitialize signals if we didn't receive an interesting
3056 * one while in pico, since pico's return is part of processing that
3057 * signal and it should continue to be ignored.
3059 if(!(editor_result
& COMP_GOTHUP
))
3060 init_signals(); /* Pico has it's own signal stuff */
3063 * We're going to save in DEADLETTER. Dump attachments first.
3065 if(editor_result
& COMP_CANCEL
)
3066 free_attachment_list(&pbf
->attachments
);
3068 /* Turn strings back into structures */
3069 strings2outgoing(&header
, body
, pbf
->attachments
, flowing_requested
);
3071 /* Make newsgroups NULL if it is "" (so won't show up in headers) */
3072 if(outgoing
->newsgroups
){
3073 sqzspaces(outgoing
->newsgroups
);
3074 if(!outgoing
->newsgroups
[0])
3075 fs_give((void **)&(outgoing
->newsgroups
));
3078 /* Make subject NULL if it is "" (so won't show up in headers) */
3079 if(outgoing
->subject
&& !outgoing
->subject
[0])
3080 fs_give((void **)&(outgoing
->subject
));
3082 /* remove custom fields that are empty */
3083 for(pf
= header
.local
; pf
&& pf
->name
; pf
= pf
->next
){
3084 if(pf
->type
== FreeText
&& pf
->textbuf
){
3085 if(pf
->textbuf
[0] == '\0'){
3086 fs_give((void **)&pf
->textbuf
);
3092 removing_trailing_white_space(fcc
);
3094 /*-------- Stamp it with a current date -------*/
3095 if(outgoing
->date
) /* update old date */
3096 fs_give((void **)&(outgoing
->date
));
3098 if(F_ON(F_QUELL_TIMEZONE
, ps_global
))
3099 mail_parameters(NULL
, SET_DISABLE822TZTEXT
, (void *) TRUE
);
3101 rfc822_date(tmp_20k_buf
); /* format and copy new date */
3102 if(F_ON(F_QUELL_TIMEZONE
, ps_global
))
3103 mail_parameters(NULL
, SET_DISABLE822TZTEXT
, (void *) FALSE
);
3105 outgoing
->date
= (unsigned char *) cpystr(tmp_20k_buf
);
3107 /* Set return_path based on From which is going to be used */
3108 if(outgoing
->return_path
)
3109 mail_free_address(&outgoing
->return_path
);
3111 outgoing
->return_path
= rfc822_cpy_adr(outgoing
->from
);
3114 * Don't ever believe the sender that is there.
3115 * If From doesn't look quite right, generate our own sender.
3117 if(outgoing
->sender
)
3118 mail_free_address(&outgoing
->sender
);
3121 * If the LHS of the address doesn't match, or the RHS
3122 * doesn't match one of localdomain or hostname,
3123 * then add a sender line (really X-X-Sender).
3125 * Don't add a personal_name since the user can change that.
3127 if(F_OFF(F_DISABLE_SENDER
, ps_global
)
3130 || !outgoing
->from
->mailbox
3131 || strucmp(outgoing
->from
->mailbox
, ps_global
->VAR_USER_ID
) != 0
3132 || !outgoing
->from
->host
3133 || !(strucmp(outgoing
->from
->host
, ps_global
->localdomain
) == 0
3134 || strucmp(outgoing
->from
->host
, ps_global
->hostname
) == 0))){
3136 outgoing
->sender
= mail_newaddr();
3137 outgoing
->sender
->mailbox
= cpystr(ps_global
->VAR_USER_ID
);
3138 outgoing
->sender
->host
= cpystr(ps_global
->hostname
);
3141 /* To protect the privacy of the user, make sure that the domain
3142 * part in the message id matches the domain in the from, so that
3143 * the user does not disclose more than they are already willing
3147 if(outgoing
->message_id
&& outgoing
->from
&& !role
){
3148 fs_give((void **) &outgoing
->message_id
);
3149 role
= (ACTION_S
*) fs_get(sizeof(ACTION_S
)); /* create fake role */
3150 memset((void *) role
, 0, sizeof(ACTION_S
));
3151 role
->from
= outgoing
->from
; /* and fill the from field only */
3152 outgoing
->message_id
= generate_message_id(role
); /* new message id */
3153 role
->from
= NULL
; /* disconnect the from part */
3154 fs_give((void **) &role
); /* the fake role can be discarded */
3157 if(ps_global
->newthread
){
3158 if(outgoing
->in_reply_to
) fs_give((void **)&outgoing
->in_reply_to
);
3159 if(outgoing
->references
) fs_give((void **)&outgoing
->references
);
3162 /*----- Message is edited, now decide what to do with it ----*/
3163 if(editor_result
& (COMP_SUSPEND
| COMP_GOTHUP
| COMP_CANCEL
)){
3164 /*=========== Postpone or Interrupted message ============*/
3165 CONTEXT_S
*fcc_cntxt
= NULL
;
3166 char folder
[MAXPATH
+1];
3170 dprint((4, "pine_send:%s handling\n",
3171 (editor_result
& COMP_SUSPEND
)
3173 : (editor_result
& COMP_GOTHUP
)
3175 : (editor_result
& COMP_CANCEL
)
3176 ? "CANCEL" : "HUH?"));
3177 if((editor_result
& COMP_CANCEL
)
3178 && (F_ON(F_QUELL_DEAD_LETTER
, ps_global
)
3179 || ps_global
->deadlets
== 0)){
3180 q_status_message(SM_ORDER
, 0, 3, "Message cancelled");
3185 * The idea here is to use the Fcc: writing facility
3186 * to append to the special postponed message folder...
3188 * NOTE: the strategy now is to write the message and
3189 * all attachments as they exist at composition time.
3190 * In other words, attachments are postponed by value
3191 * and not reference. This may change later, but we'll
3192 * need a local "message/external-body" type that
3193 * outgoing2strings knows how to properly set up for
3194 * the composer. Maybe later...
3199 if(F_ON(F_COMPOSE_REJECTS_UNQUAL
, ps_global
)
3200 && (editor_result
& COMP_SUSPEND
)
3201 && (check_addresses(&header
) == CA_BAD
)){
3202 /*--- Addresses didn't check out---*/
3203 q_status_message(SM_ORDER
, 7, 7,
3204 _("Not allowed to postpone message until addresses are qualified"));
3209 * Build the local message copy so.
3211 * In the HUP case, we'll write the bezerk delimiter by
3212 * hand and output the message directly into the folder.
3213 * It's not only faster, we don't have to worry about
3214 * c-client reentrance and less hands paw over the data so
3215 * there's less chance of a problem.
3217 * In the Postpone case, just create it if the user wants to
3218 * and create a temporary storage object to write into. */
3221 lmc
.all_written
= lmc
.text_only
= lmc
.text_written
= 0;
3222 if(editor_result
& (COMP_GOTHUP
| COMP_CANCEL
)){
3224 time_t now
= time((time_t *)0);
3226 #if defined(DOS) || defined(OS2)
3228 * we can't assume anything about root or home dirs, so
3229 * just plunk it down in the same place as the pinerc
3231 if(!getenv("HOME")){
3232 char *lc
= last_cmpnt(ps_global
->pinerc
);
3235 strncpy(folder
,ps_global
->pinerc
,
3236 MIN(lc
-ps_global
->pinerc
,sizeof(folder
)-1));
3237 folder
[MIN(lc
-ps_global
->pinerc
,sizeof(folder
)-1)]='\0';
3240 strncat(folder
, (editor_result
& COMP_GOTHUP
)
3241 ? INTERRUPTED_MAIL
: DEADLETTER
,
3242 sizeof(folder
)-strlen(folder
)-1);
3247 ps_global
->VAR_OPER_DIR
3248 ? ps_global
->VAR_OPER_DIR
: ps_global
->home_dir
,
3249 (editor_result
& COMP_GOTHUP
)
3250 ? INTERRUPTED_MAIL
: DEADLETTER
,
3253 if(editor_result
& COMP_CANCEL
){
3254 char filename
[MAXPATH
+1], newfname
[MAXPATH
+1], nbuf
[5];
3256 if(strlen(folder
) + 1 < sizeof(filename
))
3257 for(i
= ps_global
->deadlets
- 1; i
> 0 && i
< 9; i
--){
3258 strncpy(filename
, folder
, sizeof(filename
));
3259 filename
[sizeof(filename
)-1] = '\0';
3260 strncpy(newfname
, filename
, sizeof(newfname
));
3261 newfname
[sizeof(newfname
)-1] = '\0';
3264 snprintf(nbuf
, sizeof(nbuf
), "%d", i
);
3265 nbuf
[sizeof(nbuf
)-1] = '\0';
3266 strncat(filename
, nbuf
,
3267 sizeof(filename
)-strlen(filename
)-1);
3268 filename
[sizeof(filename
)-1] = '\0';
3271 snprintf(nbuf
, sizeof(nbuf
), "%d", i
+1);
3272 nbuf
[sizeof(nbuf
)-1] = '\0';
3273 strncat(newfname
, nbuf
,
3274 sizeof(newfname
)-strlen(newfname
)-1);
3275 newfname
[sizeof(newfname
)-1] = '\0';
3276 (void) rename_file(filename
, newfname
);
3282 newfile
= can_access(folder
, ACCESS_EXISTS
);
3284 if((lmc
.so
= so_get(FCC_SOURCE
, NULL
, WRITE_ACCESS
)) != NULL
){
3285 if (outgoing
->from
){
3286 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, "%sFrom %s@%s %.24s\015\012",
3287 newfile
? "" : "\015\012",
3288 outgoing
->from
->mailbox
,
3289 outgoing
->from
->host
, ctime(&now
));
3290 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
3291 if(!so_puts(lmc
.so
, tmp_20k_buf
)){
3292 if(editor_result
& COMP_CANCEL
)
3293 q_status_message2(SM_ORDER
| SM_DING
, 3, 3,
3294 "Can't write \"%s\": %s",
3295 folder
, error_description(errno
));
3297 dprint((1, "* * * CAN'T WRITE %s: %s\n",
3298 folder
? folder
: "?",
3299 error_description(errno
)));
3304 else{ /* Must be COMP_SUSPEND */
3305 if(!ps_global
->VAR_POSTPONED_FOLDER
3306 || !ps_global
->VAR_POSTPONED_FOLDER
[0]){
3307 q_status_message(SM_ORDER
| SM_DING
, 3, 3,
3308 _("No postponed file defined"));
3313 * Store the cursor position
3315 * First find the header entry with the start_here
3316 * bit set, if any. This means the editor is telling
3317 * us to start on this header field next time.
3319 start_here_name
= NULL
;
3320 for(pf
= header
.local
; pf
&& pf
->name
; pf
= pf
->next
)
3321 if(HE(pf
) && HE(pf
)->start_here
){
3322 start_here_name
= pf
->name
;
3326 /* If there wasn't one, ":" means we start in the body. */
3327 if(!start_here_name
|| !*start_here_name
)
3328 start_here_name
= ":";
3330 if(ps_global
->VAR_FORM_FOLDER
3331 && ps_global
->VAR_FORM_FOLDER
[0]
3332 && postpone_prompt() == 'f'){
3333 strncpy(folder
, ps_global
->VAR_FORM_FOLDER
,
3335 folder
[sizeof(folder
)-1] = '\0';
3336 strncpy(label
, "form letter", sizeof(label
));
3337 label
[sizeof(label
)-1] = '\0';
3340 strncpy(folder
, ps_global
->VAR_POSTPONED_FOLDER
,
3342 folder
[sizeof(folder
)-1] = '\0';
3343 strncpy(label
, "postponed message", sizeof(label
));
3344 label
[sizeof(label
)-1] = '\0';
3347 lmc
.so
= open_fcc(folder
,&fcc_cntxt
, 1, NULL
, NULL
);
3354 /* copy fcc line to postponed or interrupted folder */
3356 pf_fcc
->localcopy
= 1;
3358 /* plug error into header for later display to user */
3359 if((editor_result
& ~0xff) && (lmq
= last_message_queued()) != NULL
){
3360 pf_err
->writehdr
= 1;
3361 pf_err
->localcopy
= 1;
3362 pf_err
->textbuf
= lmq
;
3366 * if reply, write (UID)folder header field so we can
3367 * later flag the replied-to message \\ANSWERED
3368 * DON'T save MSGNO's.
3370 if(reply
&& reply
->uid
){
3371 char uidbuf
[MAILTMPLEN
], *p
;
3374 for(i
= 0L, p
= tmp_20k_buf
; reply
->data
.uid
.msgs
[i
]; i
++){
3376 sstrncpy(&p
, ",", SIZEOF_20KBUF
-(p
-tmp_20k_buf
));
3378 sstrncpy(&p
,ulong2string(reply
->data
.uid
.msgs
[i
]),SIZEOF_20KBUF
-(p
-tmp_20k_buf
));
3381 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
3383 pf_uid
->writehdr
= 1;
3384 pf_uid
->localcopy
= 1;
3385 snprintf(uidbuf
, sizeof(uidbuf
), "(%s%s%s)(%ld %lu %s)%s",
3386 reply
->prefix
? int2string(strlen(reply
->prefix
))
3387 : (reply
->forwarded
) ? "": "0 ",
3388 reply
->prefix
? " " : "",
3389 reply
->prefix
? reply
->prefix
: "",
3390 i
, reply
->data
.uid
.validity
,
3391 tmp_20k_buf
, reply
->mailbox
);
3392 uidbuf
[sizeof(uidbuf
)-1] = '\0';
3393 pf_uid
->textbuf
= cpystr(uidbuf
);
3396 * Logically, this ought to be part of pf_uid, but this
3397 * was added later and so had to be in a separate header
3398 * for backwards compatibility.
3400 pf_mbox
->writehdr
= 1;
3401 pf_mbox
->localcopy
= 1;
3402 pf_mbox
->textbuf
= cpystr(reply
->origmbox
3407 /* Save cursor position */
3408 if(start_here_name
&& *start_here_name
){
3409 char curposbuf
[MAILTMPLEN
];
3411 pf_curpos
->writehdr
= 1;
3412 pf_curpos
->localcopy
= 1;
3413 snprintf(curposbuf
, sizeof(curposbuf
), "%s %ld", start_here_name
,
3415 curposbuf
[sizeof(curposbuf
)-1] = '\0';
3416 pf_curpos
->textbuf
= cpystr(curposbuf
);
3420 * Work around c-client reply-to bug. C-client will
3421 * return a reply_to in an envelope even if there is
3422 * no reply-to header field. We want to note here whether
3423 * the reply-to is real or not.
3425 if(outgoing
->reply_to
|| hdr_is_in_list("reply-to", custom
)){
3426 pf_ourrep
->writehdr
= 1;
3427 pf_ourrep
->localcopy
= 1;
3428 if(outgoing
->reply_to
)
3429 pf_ourrep
->textbuf
= cpystr("Full");
3431 pf_ourrep
->textbuf
= cpystr("Empty");
3434 /* Save the role-specific smtp server */
3435 if(role
&& role
->smtp
&& role
->smtp
[0]){
3436 char *q
, *smtp
= NULL
;
3441 * Turn the list of smtp servers into a space-
3442 * delimited list in a single string.
3444 for(lp
= role
->smtp
; (q
= *lp
) != NULL
; lp
++)
3445 len
+= (strlen(q
) + 1);
3448 smtp
= (char *) fs_get(len
* sizeof(char));
3450 for(lp
= role
->smtp
; (q
= *lp
) != NULL
; lp
++){
3451 if(lp
!= role
->smtp
)
3452 strncat(smtp
, " ", len
-strlen(smtp
)-1);
3454 strncat(smtp
, q
, len
-strlen(smtp
)-1);
3460 pf_smtp_server
->writehdr
= 1;
3461 pf_smtp_server
->localcopy
= 1;
3463 pf_smtp_server
->textbuf
= smtp
;
3465 pf_smtp_server
->textbuf
= cpystr("");
3468 /* Save the role-specific nntp server */
3469 if(suggested_nntp_server
||
3470 (role
&& role
->nntp
&& role
->nntp
[0])){
3471 char *q
, *nntp
= NULL
;
3475 if(role
&& role
->nntp
&& role
->nntp
[0]){
3477 * Turn the list of nntp servers into a space-
3478 * delimited list in a single string.
3480 for(lp
= role
->nntp
; (q
= *lp
) != NULL
; lp
++)
3481 len
+= (strlen(q
) + 1);
3484 nntp
= (char *) fs_get(len
* sizeof(char));
3486 for(lp
= role
->nntp
; (q
= *lp
) != NULL
; lp
++){
3487 if(lp
!= role
->nntp
)
3488 strncat(nntp
, " ", len
-strlen(nntp
)-1);
3490 strncat(nntp
, q
, len
-strlen(nntp
)-1);
3497 nntp
= cpystr(suggested_nntp_server
);
3499 pf_nntp_server
->writehdr
= 1;
3500 pf_nntp_server
->localcopy
= 1;
3502 pf_nntp_server
->textbuf
= nntp
;
3504 pf_nntp_server
->textbuf
= cpystr("");
3508 * Write the list of custom headers to the
3509 * X-Our-Headers header so that we can recover the
3513 for(pf
= header
.custom
; pf
&& pf
->name
; pf
= pf
->next
)
3514 sz
+= strlen(pf
->name
) + 1;
3519 pf_ourhdrs
->writehdr
= 1;
3520 pf_ourhdrs
->localcopy
= 1;
3521 pf_ourhdrs
->textbuf
= (char *)fs_get(sz
);
3522 memset(pf_ourhdrs
->textbuf
, 0, sz
);
3523 q
= pf_ourhdrs
->textbuf
;
3524 for(pf
= header
.custom
; pf
&& pf
->name
; pf
= pf
->next
){
3525 if(pf
!= header
.custom
)
3526 sstrncpy(&q
, ",", sz
-(q
-pf_ourhdrs
->textbuf
));
3528 sstrncpy(&q
, pf
->name
, sz
-(q
-pf_ourhdrs
->textbuf
));
3531 pf_ourhdrs
->textbuf
[sz
-1] = '\0';;
3535 * We need to make sure any header values that got cleared
3536 * get written to the postponed message (they won't if
3537 * pf->text is NULL). Otherwise, we can't tell previously
3538 * non-existent custom headers or default values from
3539 * custom (or other) headers that got blanked in the
3542 for(pf
= header
.local
; pf
&& pf
->name
; pf
= pf
->next
)
3543 if(pf
->type
== FreeText
&& HE(pf
) && !*(HE(pf
)->realaddr
))
3544 *(HE(pf
)->realaddr
) = cpystr("");
3547 * We're saving the message for use later. It may be that the
3548 * characters in the message are not all convertible to the
3549 * user's posting_charmap. We'll save it as UTF-8 instead
3550 * and worry about that the next time they try to send it.
3551 * Use a different save pointer just to be sure we don't
3552 * mess up the other stuff. We should probably make the
3553 * charset an argument.
3555 * We also need to fix the charset of the body part
3556 * the user is editing so that we can read it back
3557 * successfully when we resume the composition.
3559 ps_global
->post_utf8
= 1;
3564 if((*body
)->type
== TYPEMULTIPART
)
3565 bp
= &(*body
)->nested
.part
->body
;
3569 for(pm
= bp
->parameter
;
3570 pm
&& strucmp(pm
->attribute
, "charset") != 0;
3576 fs_give((void **) &pm
->value
);
3578 pm
->value
= cpystr("UTF-8");
3582 if(pine_rfc822_output(&header
,*body
,NULL
,NULL
) >= 0L){
3583 if(editor_result
& (COMP_GOTHUP
| COMP_CANCEL
)){
3589 if(editor_result
& COMP_CANCEL
){
3590 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
,
3591 "Saving to \"%s\"", folder
);
3592 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
3593 we_cancel
= busy_cue((char *)tmp_20k_buf
, NULL
, 1);
3597 so_get(FileStar
, folder
, WRITE_ACCESS
|OWNER_ONLY
)) != NULL
){
3598 gf_set_so_readc(&gc
, lmc
.so
);
3599 gf_set_so_writec(&pc
, hup_so
);
3600 so_seek(lmc
.so
, 0L, 0); /* read msg copy and */
3601 so_seek(hup_so
, 0L, 2); /* append to folder */
3603 gf_link_filter(gf_nvtnl_local
, NULL
);
3604 if(!(fcc_result
= !(err
= gf_pipe(gc
, pc
))))
3605 dprint((1, "*** PIPE FAILED: %s\n",
3608 gf_clear_so_readc(lmc
.so
);
3609 gf_clear_so_writec(hup_so
);
3613 dprint((1, "*** CAN'T CREATE %s: %s\n",
3614 folder
? folder
: "?",
3615 error_description(errno
)));
3618 cancel_busy_cue(-1);
3621 fcc_result
= write_fcc(folder
, fcc_cntxt
,
3622 lmc
.so
, NULL
, label
, NULL
);
3625 /* discontinue coerced UTF-8 posting */
3626 ps_global
->post_utf8
= 0;
3631 dprint((1, "***CAN'T ALLOCATE temp store: %s ",
3632 error_description(errno
)));
3634 if(editor_result
& COMP_GOTHUP
){
3636 * Special Hack #291: if any hi-byte bits are set in
3637 * editor's result, we put them there.
3639 if(editor_result
& 0xff00)
3640 exit(editor_result
>> 8);
3642 dprint((1, "Save composition on HUP %sED\n",
3643 fcc_result
? "SUCCEED" : "FAIL"));
3644 hup_signal(); /* Do what we normally do on SIGHUP */
3646 else if((editor_result
& COMP_SUSPEND
) && fcc_result
){
3647 if(ps_global
->VAR_FORM_FOLDER
3648 && ps_global
->VAR_FORM_FOLDER
[0]
3649 && !strcmp(folder
, ps_global
->VAR_FORM_FOLDER
))
3650 q_status_message(SM_ORDER
, 0, 3,
3651 _("Composition saved to Form Letter Folder. Select Compose to send."));
3653 q_status_message(SM_ORDER
, 0, 3,
3654 _("Composition postponed. Select Compose to resume."));
3656 break; /* postpone went OK, get out of here */
3658 else if(editor_result
& COMP_CANCEL
){
3661 if(fcc_result
&& folder
)
3662 lc
= last_cmpnt(folder
);
3664 q_status_message3(SM_ORDER
, 0, 3,
3665 _("Message cancelled%s%s%s"),
3666 (lc
&& *lc
) ? " and copied to \"" : "",
3667 (lc
&& *lc
) ? lc
: "",
3668 (lc
&& *lc
) ? "\" file" : "");
3672 q_status_message(SM_ORDER
, 0, 4,
3673 _("Continuing composition. Message not postponed or sent"));
3675 continue; /* postpone failed, jump back in to composer */
3679 /*------ Must be sending mail or posting ! -----*/
3680 int result
, valid_addr
, continue_with_only_fcc
= 0;
3681 CONTEXT_S
*fcc_cntxt
= NULL
;
3684 dprint((4, "=== sending: "));
3686 /* --- If posting, confirm with user ----*/
3687 if(outgoing
->newsgroups
&& *outgoing
->newsgroups
3688 && F_OFF(F_QUELL_EXTRA_POST_PROMPT
, ps_global
)
3689 && want_to(POST_PMT
, 'n', 'n', NO_HELP
, WT_NORM
) == 'n'){
3690 q_status_message(SM_ORDER
, 0, 3, _("Message not posted"));
3691 dprint((4, "no post, continuing\n"));
3695 if(!(outgoing
->to
|| outgoing
->cc
|| outgoing
->bcc
|| lcc_addr
3696 || outgoing
->newsgroups
)){
3698 if(F_OFF(F_AUTO_FCC_ONLY
, ps_global
) &&
3699 want_to(_("No recipients, really copy only to Fcc "),
3700 'n', 'n', h_send_fcc_only
, WT_NORM
) != 'y')
3703 continue_with_only_fcc
++;
3706 q_status_message(SM_ORDER
, 3, 4,
3707 _("No recipients specified!"));
3708 dprint((4, "no recip, continuing\n"));
3713 if((valid_addr
= check_addresses(&header
)) == CA_BAD
){
3714 /*--- Addresses didn't check out---*/
3715 dprint((4, "addrs failed, continuing\n"));
3719 if(F_ON(F_WARN_ABOUT_NO_TO_OR_CC
, ps_global
)
3720 && !continue_with_only_fcc
3721 && !(outgoing
->to
|| outgoing
->cc
|| lcc_addr
3722 || outgoing
->newsgroups
)
3723 && (want_to(_("No To, Cc, or Newsgroup specified, send anyway "),
3724 'n', 'n', h_send_check_to_cc
, WT_NORM
) != 'y')){
3725 dprint((4, "No To or CC or Newsgroup, continuing\n"));
3726 if(local_redraft_pos
&& local_redraft_pos
!= redraft_pos
)
3727 free_redraft_pos(&local_redraft_pos
);
3730 = (REDRAFT_POS_S
*) fs_get(sizeof(*local_redraft_pos
));
3731 memset((void *) local_redraft_pos
,0,sizeof(*local_redraft_pos
));
3732 local_redraft_pos
->hdrname
= cpystr(TONAME
);
3736 if(F_ON(F_WARN_ABOUT_NO_SUBJECT
, ps_global
)
3737 && check_for_subject(&header
) == CF_MISSING
){
3738 dprint((4, "No subject, continuing\n"));
3739 if(local_redraft_pos
&& local_redraft_pos
!= redraft_pos
)
3740 free_redraft_pos(&local_redraft_pos
);
3743 = (REDRAFT_POS_S
*) fs_get(sizeof(*local_redraft_pos
));
3744 memset((void *) local_redraft_pos
,0,sizeof(*local_redraft_pos
));
3745 local_redraft_pos
->hdrname
= cpystr(SUBJNAME
);
3749 if(F_ON(F_WARN_ABOUT_NO_FCC
, ps_global
)
3750 && check_for_fcc(fcc
) == CF_MISSING
){
3751 dprint((4, "No fcc, continuing\n"));
3752 if(local_redraft_pos
&& local_redraft_pos
!= redraft_pos
)
3753 free_redraft_pos(&local_redraft_pos
);
3756 = (REDRAFT_POS_S
*) fs_get(sizeof(*local_redraft_pos
));
3757 memset((void *) local_redraft_pos
,0,sizeof(*local_redraft_pos
));
3758 local_redraft_pos
->hdrname
= cpystr("Fcc");
3764 /*---- Check out fcc -----*/
3767 * If special name "inbox" then replace it with the
3770 if(ps_global
->VAR_INBOX_PATH
3771 && strucmp(fcc
, ps_global
->inbox_name
) == 0){
3774 replace_fcc
= cpystr(ps_global
->VAR_INBOX_PATH
);
3775 fs_give((void **)&fcc
);
3779 lmc
.all_written
= lmc
.text_written
= 0;
3780 /* lmc.text_only set on command line */
3781 if(!(lmc
.so
= open_fcc(fcc
, &fcc_cntxt
, 0, NULL
, NULL
))){
3782 /* ---- Open or allocation of fcc failed ----- */
3783 dprint((4,"can't open/allocate fcc, cont'g\n"));
3786 * Find field entry associated with fcc, and start
3789 for(pf
= header
.local
; pf
&& pf
->name
; pf
= pf
->next
)
3790 if(pf
->type
== Fcc
&& HE(pf
))
3791 HE(pf
)->start_here
= 1;
3796 so_truncate(lmc
.so
, fcc_size_guess(*body
) + 2048);
3801 /*---- Take care of any requested prefiltering ----*/
3802 if(sending_filter_requested
3803 && !filter_message_text(sending_filter_requested
, outgoing
,
3804 *body
, &orig_so
, &header
)){
3805 q_status_message1(SM_ORDER
, 3, 3,
3806 _("Problem filtering! Nothing sent%s."),
3807 fcc
? " or saved to fcc" : "");
3811 /*------ Actually post -------*/
3812 if(outgoing
->newsgroups
){
3813 char **alt_nntp
= NULL
, *alt_nntp_p
[2];
3814 if(((role
&& role
->nntp
)
3815 || suggested_nntp_server
)){
3816 if(ps_global
->FIX_NNTP_SERVER
3817 && ps_global
->FIX_NNTP_SERVER
[0])
3818 q_status_message(SM_ORDER
| SM_DING
, 5, 5,
3819 "Using nntp-server that is administratively fixed");
3820 else if(role
&& role
->nntp
)
3821 alt_nntp
= role
->nntp
;
3823 alt_nntp_p
[0] = suggested_nntp_server
;
3824 alt_nntp_p
[1] = NULL
;
3825 alt_nntp
= alt_nntp_p
;
3828 if(news_poster(&header
, *body
, alt_nntp
, pipe_callback
) < 0){
3829 dprint((1, "Post failed, continuing\n"));
3830 if(outgoing
->message_id
)
3831 fs_give((void **) &outgoing
->message_id
);
3833 outgoing
->message_id
= generate_message_id(role
);
3838 result
|= P_NEWS_WIN
;
3842 * BUG: IF we've posted the message *and* an fcc was specified
3843 * then we've already got a neatly formatted message in the
3844 * lmc.so. It'd be nice not to have to re-encode everything
3845 * to insert it into the smtp slot...
3849 * Turn on "undisclosed recipients" header if no To or cc.
3851 if(!(outgoing
->to
|| outgoing
->cc
)
3852 && (outgoing
->bcc
|| lcc_addr
) && pf_nobody
&& pf_nobody
->addr
){
3853 pf_nobody
->writehdr
= 1;
3854 pf_nobody
->localcopy
= 1;
3857 if(priority_requested
){
3858 (void) set_priority_header(&header
, priority_requested
);
3859 fs_give((void **) &priority_requested
);
3862 #if defined(BACKGROUND_POST) && defined(SIGCHLD)
3864 * If requested, launch background posting...
3866 if(background_requested
&& !(call_mailer_flags
& CM_VERBOSE
)){
3867 ps_global
->post
= (POST_S
*)fs_get(sizeof(POST_S
));
3868 memset(ps_global
->post
, 0, sizeof(POST_S
));
3870 ps_global
->post
->fcc
= cpystr(fcc
);
3872 if((ps_global
->post
->pid
= fork()) == 0){
3874 * Put us in new process group...
3876 setpgrp(0, ps_global
->post
->pid
);
3878 /* BUG: should fix argv[0] to indicate what we're up to */
3881 * If there are any live streams, pretend we never
3882 * knew them. Problem is two processes writing
3883 * same server process.
3884 * This is not clean but we're just going to exit
3885 * right away anyway. We just want to be sure to leave
3886 * the stuff that the parent is going to use alone.
3887 * The next three lines will disable the re-use of the
3888 * existing streams and cause us to open a new one if
3891 ps_global
->mail_stream
= NULL
;
3892 ps_global
->s_pool
.streams
= NULL
;
3893 ps_global
->s_pool
.nstream
= 0;
3895 /* quell any display output */
3896 ps_global
->in_init_seq
= 1;
3898 /*------- Actually mail the message ------*/
3899 if(valid_addr
== CA_OK
3900 && (outgoing
->to
|| outgoing
->cc
3901 || outgoing
->bcc
|| lcc_addr
)){
3902 char **alt_smtp
= NULL
;
3904 if(role
&& role
->smtp
){
3905 if(ps_global
->FIX_SMTP_SERVER
3906 && ps_global
->FIX_SMTP_SERVER
[0])
3907 q_status_message(SM_ORDER
| SM_DING
, 5, 5, "Use of a role-defined smtp-server is administratively prohibited");
3909 alt_smtp
= role
->smtp
;
3912 result
|= (call_mailer(&header
, *body
, alt_smtp
,
3914 call_mailer_file_result
,
3916 ? P_MAIL_WIN
: P_MAIL_LOSE
;
3918 if(result
& P_MAIL_LOSE
)
3919 mark_address_failure_for_pico(&header
);
3922 /*----- Was there an fcc involved? -----*/
3924 /*------ Write it if at least something worked ------*/
3925 if((result
& (P_MAIL_WIN
| P_NEWS_WIN
))
3926 || (!(result
& (P_MAIL_BITS
| P_NEWS_BITS
))
3927 && pine_rfc822_output(&header
, *body
,
3931 strncpy(label
, "Fcc", sizeof(label
));
3932 label
[sizeof(label
)-1] = '\0';
3933 if(strcmp(fcc
, ps_global
->VAR_DEFAULT_FCC
)){
3934 snprintf(label
+ 3, sizeof(label
)-3, " to %s", fcc
);
3935 label
[sizeof(label
)-1] = '\0';
3938 /*-- Now actually copy to fcc folder and close --*/
3939 result
|= (write_fcc(fcc
, fcc_cntxt
, lmc
.so
,
3941 F_ON(F_MARK_FCC_SEEN
, ps_global
)
3943 ? P_FCC_WIN
: P_FCC_LOSE
;
3945 else if(!(result
& (P_MAIL_BITS
| P_NEWS_BITS
))){
3946 q_status_message(SM_ORDER
, 3, 5,
3947 _("Fcc Failed!. No message saved."));
3949 "explicit fcc write failed!\n"));
3950 result
|= P_FCC_LOSE
;
3956 if(result
& (P_MAIL_LOSE
| P_NEWS_LOSE
| P_FCC_LOSE
)){
3958 * Encode child's result in hi-byte of
3961 editor_result
= ((result
<< 8) | COMP_GOTHUP
);
3968 if(ps_global
->post
->pid
> 0){
3969 q_status_message(SM_ORDER
, 3, 3,
3970 _("Message handed off for posting"));
3971 break; /* up to our child now */
3974 q_status_message1(SM_ORDER
| SM_DING
, 3, 3,
3975 "Can't fork for send: %s",
3976 error_description(errno
));
3977 if(ps_global
->post
->fcc
)
3978 fs_give((void **) &ps_global
->post
->fcc
);
3980 fs_give((void **) &ps_global
->post
);
3983 if(lmc
.so
) /* throw away unused store obj */
3986 if(outgoing
->message_id
)
3987 fs_give((void **) &outgoing
->message_id
);
3989 outgoing
->message_id
= generate_message_id(role
);
3991 continue; /* if we got here, there was a prob */
3993 #endif /* BACKGROUND_POST */
3995 /*------- Actually mail the message ------*/
3996 if(valid_addr
== CA_OK
3997 && (outgoing
->to
|| outgoing
->cc
|| outgoing
->bcc
|| lcc_addr
)){
3998 char **alt_smtp
= NULL
;
4000 if(role
&& role
->smtp
){
4001 if(ps_global
->FIX_SMTP_SERVER
4002 && ps_global
->FIX_SMTP_SERVER
[0])
4003 q_status_message(SM_ORDER
| SM_DING
, 5, 5, "Use of a role-defined smtp-server is administratively prohibited");
4005 alt_smtp
= role
->smtp
;
4008 result
|= (call_mailer(&header
, *body
, alt_smtp
,
4010 call_mailer_file_result
,
4012 ? P_MAIL_WIN
: P_MAIL_LOSE
;
4014 if(result
& P_MAIL_LOSE
)
4015 mark_address_failure_for_pico(&header
);
4018 /*----- Was there an fcc involved? -----*/
4020 /*------ Write it if at least something worked ------*/
4021 if((result
& (P_MAIL_WIN
| P_NEWS_WIN
))
4022 || (!(result
& (P_MAIL_BITS
| P_NEWS_BITS
))
4023 && pine_rfc822_output(&header
, *body
, NULL
, NULL
))){
4026 strncpy(label
, "Fcc", sizeof(label
));
4027 label
[sizeof(label
)-1] = '\0';
4028 if(strcmp(fcc
, ps_global
->VAR_DEFAULT_FCC
)){
4029 snprintf(label
+ 3, sizeof(label
)-3, " to %s", fcc
);
4030 label
[sizeof(label
)-1] = '\0';
4033 /*-- Now actually copy to fcc folder and close --*/
4034 result
|= (write_fcc(fcc
, fcc_cntxt
, lmc
.so
, NULL
, label
,
4035 F_ON(F_MARK_FCC_SEEN
, ps_global
)
4037 ? P_FCC_WIN
: P_FCC_LOSE
;
4039 else if(!(result
& (P_MAIL_BITS
| P_NEWS_BITS
))){
4040 q_status_message(SM_ORDER
,3,5,
4041 _("Fcc Failed!. No message saved."));
4042 dprint((1, "explicit fcc write failed!\n"));
4043 result
|= P_FCC_LOSE
;
4049 /*----- Mail Post FAILED, back to composer -----*/
4050 if(result
& (P_MAIL_LOSE
| P_FCC_LOSE
)){
4051 dprint((1, "Send failed, continuing\n"));
4053 if(result
& P_FCC_LOSE
){
4055 * Find field entry associated with fcc, and start
4058 for(pf
= header
.local
; pf
&& pf
->name
; pf
= pf
->next
)
4059 if(pf
->type
== Fcc
&& HE(pf
))
4060 HE(pf
)->start_here
= 1;
4062 q_status_message(SM_ORDER
| SM_DING
, 3, 3,
4063 pine_send_status(result
, fcc
,
4064 tmp_20k_buf
, SIZEOF_20KBUF
, NULL
));
4067 if(outgoing
->message_id
)
4068 fs_give((void **) &outgoing
->message_id
);
4070 outgoing
->message_id
= generate_message_id(role
);
4076 * If message sent *completely* successfully, there's a
4077 * reply struct AND we're allowed to write back state, do it.
4078 * But also protect against shifted message numbers due
4079 * to new mail arrival. Since the number passed is based
4080 * on the real imap msg no, AND we're sure no expunge has
4081 * been done, just fix up the sorted number...
4083 update_answered_flags(reply
);
4085 /*----- Signed, sealed, delivered! ------*/
4086 q_status_message(SM_ORDER
, 0, 3,
4087 pine_send_status(result
, fcc
, tmp_20k_buf
, SIZEOF_20KBUF
, NULL
));
4089 break; /* All's well, pop out of here */
4097 fs_give((void **)&fcc
);
4099 free_body_particulars(bp
);
4101 free_attachment_list(&pbf
->attachments
);
4103 standard_picobuf_teardown(pbf
);
4105 for(i
=0; i
< fixed_cnt
; i
++){
4106 if(pfields
[i
].textbuf
)
4107 fs_give((void **)&pfields
[i
].textbuf
);
4109 fs_give((void **)&pfields
[i
].name
);
4113 mail_free_address(&lcc_addr
);
4116 mail_free_address(&nobody_addr
);
4118 free_prompts(header
.custom
);
4119 free_customs(header
.custom
);
4120 fs_give((void **)&pfields
);
4121 free_headents(&headents
);
4122 fs_give((void **)&sending_order
);
4123 if(suggested_nntp_server
)
4124 fs_give((void **)&suggested_nntp_server
);
4126 fs_give((void **)&title
);
4128 if(local_redraft_pos
&& local_redraft_pos
!= redraft_pos
)
4129 free_redraft_pos(&local_redraft_pos
);
4131 pbf
= save_previous_pbuf
;
4134 dprint((4, "=== send returning ===\n"));
4139 * Check for subject in outgoing message.
4141 * Asks user whether to proceed with no subject.
4144 check_for_subject(METAENV
*header
)
4149 for(pf
= header
->local
; pf
&& pf
->name
; pf
= pf
->next
)
4150 if(pf
->type
== Subject
){
4151 if(pf
->text
&& *pf
->text
&& **pf
->text
)
4154 if(want_to("No Subject, send anyway ",
4155 'n', 'n', h_send_check_subj
, WT_NORM
) == 'y')
4170 * Check for fcc in outgoing message.
4172 * Asks user whether to proceed with no fcc.
4175 check_for_fcc(char *fcc
)
4182 if(want_to("No Fcc, send anyway ", 'n', 'n', h_send_check_fcc
, WT_NORM
) == 'y')
4193 * Confirm that the user wants to send to MAILER-DAEMON
4196 confirm_daemon_send(void)
4198 return(want_to("Really send this message to the MAILER-DAEMON",
4199 'n', 'n', NO_HELP
, WT_NORM
) == 'y');
4204 free_prompts(PINEFIELD
*head
)
4208 for(pf
= head
; pf
&& pf
->name
; pf
= pf
->next
){
4209 if(HE(pf
) && HE(pf
)->prompt
)
4210 fs_give((void **)& HE(pf
)->prompt
);
4216 postpone_prompt(void)
4218 static ESCKEY_S pstpn_form_opt
[] = { {'p', 'p', "P", N_("Postponed Folder")},
4219 {'f', 'f', "F", N_("Form Letter Folder")},
4220 {-1, 0, NULL
, NULL
} };
4222 return(radio_buttons(PSTPN_FORM_PMT
, -FOOTER_ROWS(ps_global
),
4223 pstpn_form_opt
, 'p', 0, NO_HELP
, RB_FLUSH_IN
));
4228 * call__mailer_file_result - some results from call_mailer might be in a file.
4229 * dislplay that file.
4232 call_mailer_file_result(char *filename
, int style
)
4235 if(style
& CM_BR_VERBOSE
){
4236 display_output_file(filename
, "Verbose SMTP Interaction", NULL
, DOF_BRIEF
);
4239 display_output_file(filename
, "POSTING ERRORS", "Posting Error", DOF_EMPTY
);
4245 mark_address_failure_for_pico(METAENV
*header
)
4249 int error_count
= 0;
4250 struct headerentry
*last_he
= NULL
;
4252 for(pf
= header
->local
; pf
&& pf
->name
; pf
= pf
->next
)
4253 if(pf
->type
== Address
&& pf
->rcptto
&& pf
->addr
&& *pf
->addr
)
4254 for(a
= *pf
->addr
; a
!= NULL
; a
= a
->next
)
4256 && error_count
++ < MAX_ADDR_ERROR
4258 if(last_he
) /* start last reported err */
4259 last_he
->start_here
= 0;
4261 (last_he
= HE(pf
))->start_here
= 1;
4268 * This is specialized routine. It assumes that the only things that we
4269 * care about restoring are the body type, subtype, encoding and the
4270 * state of the charset parameter. It also assumes that if the charset
4271 * parameter exists when we save it, it won't be removed later.
4273 BODY_PARTICULARS_S
*
4274 save_body_particulars(struct mail_bodystruct
*body
)
4276 BODY_PARTICULARS_S
*bp
;
4279 bp
= (BODY_PARTICULARS_S
*)fs_get(sizeof(BODY_PARTICULARS_S
));
4281 bp
->type
= body
->type
;
4282 bp
->encoding
= body
->encoding
;
4283 bp
->subtype
= body
->subtype
? cpystr(body
->subtype
) : NULL
;
4284 bp
->parameter
= body
->parameter
;
4285 for(pm
= bp
->parameter
;
4286 pm
&& strucmp(pm
->attribute
, "charset") != 0;
4288 ;/* searching for possible charset parameter */
4290 if(pm
){ /* found one */
4291 bp
->had_csp
= 1; /* saved body had charset parameter */
4292 bp
->charset
= pm
->value
? cpystr(pm
->value
) : NULL
;
4304 reset_body_particulars(BODY_PARTICULARS_S
*bp
, struct mail_bodystruct
*body
)
4306 body
->type
= bp
->type
;
4307 body
->encoding
= bp
->encoding
;
4309 fs_give((void **)&body
->subtype
);
4311 body
->subtype
= bp
->subtype
? cpystr(bp
->subtype
) : NULL
;
4314 PARAMETER
*pm
, *pm_prev
= NULL
;
4316 for(pm
= body
->parameter
;
4317 pm
&& strucmp(pm
->attribute
, "charset") != 0;
4321 if(pm
){ /* body has charset parameter */
4322 if(bp
->had_csp
){ /* reset to what it used to be */
4324 fs_give((void **)&pm
->value
);
4326 pm
->value
= bp
->charset
? cpystr(bp
->charset
) : NULL
;
4328 else{ /* remove charset parameter */
4330 pm_prev
->next
= pm
->next
;
4332 body
->parameter
= pm
->next
;
4334 mail_free_body_parameter(&pm
);
4340 * This can't happen because grope never removes
4341 * the charset parameter.
4343 q_status_message(SM_ORDER
| SM_DING
, 5, 5,
4344 "Programmer error: saved charset but no current charset param in pine_send");
4348 ok, still no parameter
4355 mail_free_body_parameter(&body
->parameter
);
4357 body
->parameter
= NULL
;
4363 free_body_particulars(BODY_PARTICULARS_S
*bp
)
4367 fs_give((void **)&bp
->subtype
);
4370 fs_give((void **)&bp
->charset
);
4372 fs_give((void **)&bp
);
4377 /*----------------------------------------------------------------------
4378 Build a status message suitable for framing
4380 Returns: pointer to resulting buffer
4383 pine_send_status(int result
, char *fcc_name
, char *buf
, size_t buflen
, int *goodorbad
)
4385 int avail
= ps_global
->ttyo
->screen_cols
- 2;
4386 int fixedneed
, need
, lenfcc
;
4387 char *part1
, *part2
, *part3
, *part4
, *part5
;
4388 char fbuf
[MAILTMPLEN
+1];
4390 part1
= (result
& P_NEWS_WIN
)
4392 : (result
& P_NEWS_LOSE
)
4395 part2
= ((result
& P_NEWS_BITS
) && (result
& P_MAIL_BITS
)
4396 && (result
& P_FCC_BITS
))
4398 : ((result
& P_NEWS_BITS
) && (result
& (P_MAIL_BITS
| P_FCC_BITS
)))
4401 part3
= (result
& P_MAIL_WIN
)
4403 : (result
& P_MAIL_LOSE
)
4406 part4
= ((result
& P_MAIL_BITS
) && (result
& P_FCC_BITS
))
4409 part5
= ((result
& P_FCC_WIN
) && !(result
& (P_MAIL_WIN
| P_NEWS_WIN
)))
4411 : (result
& P_FCC_WIN
)
4413 : (result
& P_FCC_LOSE
)
4416 lenfcc
= MIN(sizeof(fbuf
)-1, (result
& P_FCC_BITS
) ? strlen(fcc_name
) : 0);
4418 fixedneed
= 9 + strlen(part1
) + strlen(part2
) + strlen(part3
) +
4419 strlen(part4
) + strlen(part5
);
4420 need
= fixedneed
+ ((result
& P_FCC_BITS
) ? 2 : 0) + lenfcc
;
4422 if(need
> avail
&& fixedneed
+ 3 >= avail
){
4423 /* dots on end of fixed, no fcc */
4424 snprintf(fbuf
, sizeof(fbuf
), "Message %s%s%s%s%s ",
4425 part1
, part2
, part3
, part4
, part5
);
4426 short_str(fbuf
, buf
, buflen
, avail
, EndDots
);
4428 else if(need
> avail
){
4429 /* include whole fixed part, quotes and dots at end of fcc name */
4431 lenfcc
= MAX(1, lenfcc
-(need
-avail
));
4433 snprintf(buf
, buflen
, "Message %s%s%s%s%s%s%s%s.",
4434 part1
, part2
, part3
, part4
, part5
,
4435 (result
& P_FCC_BITS
) ? "\"" : "",
4436 short_str((result
& P_FCC_BITS
) ? fcc_name
: "",
4437 fbuf
, sizeof(fbuf
), lenfcc
, FrontDots
),
4438 (result
& P_FCC_BITS
) ? "\"" : "");
4442 snprintf(buf
, buflen
, "Message %s%s%s%s%s%s%s%s.",
4443 part1
, part2
, part3
, part4
, part5
,
4444 (result
& P_FCC_BITS
) ? "\"" : "",
4445 (result
& P_FCC_BITS
) ? fcc_name
: "",
4446 (result
& P_FCC_BITS
) ? "\"" : "");
4450 *goodorbad
= (result
& (P_MAIL_LOSE
| P_NEWS_LOSE
| P_FCC_LOSE
)) == 0;
4455 /* Callback from Pico to set the conditions for Alpine to start a new thread
4459 new_thread_on_blank_subject(void)
4461 ps_global
->newthread
= F_ON(F_NEW_THREAD_ON_BLANK_SUBJECT
, ps_global
);
4466 /*----------------------------------------------------------------------
4467 Call back for pico to insert the specified message's text
4469 Args: n -- message number to format
4470 f -- function to use to output the formatted message
4473 Returns: returns msg number formatted on success, zero on error.
4476 message_format_for_pico(long int n
, int (*f
) (int))
4480 char *old_quote
= NULL
;
4483 if(!(n
> 0L && n
<= mn_get_total(ps_global
->msgmap
)
4484 && (e
= pine_mail_fetchstructure(ps_global
->mail_stream
,
4485 mn_m2raw(ps_global
->msgmap
, n
), &b
)))){
4486 q_status_message(SM_ORDER
|SM_DING
,3,3,"Error inserting Message");
4487 flush_status_messages(0);
4491 /* temporarily assign a new quote string */
4492 old_quote
= pbf
->quote_str
;
4493 pbf
->quote_str
= reply_quote_str(e
);
4495 /* build separator line */
4496 reply_delimiter(e
, NULL
, f
);
4498 /* actually write message text */
4499 if(!format_message(mn_m2raw(ps_global
->msgmap
, n
), e
, b
, NULL
,
4500 FM_NEW_MESS
| FM_DISPLAY
| FM_NOCOLOR
| FM_NOINDENT
, f
)){
4501 q_status_message(SM_ORDER
|SM_DING
,3,3,"Error inserting Message");
4502 flush_status_messages(0);
4506 fs_give((void **)&pbf
->quote_str
);
4507 pbf
->quote_str
= old_quote
;
4512 /*----------------------------------------------------------------------
4513 Call back for pico to prompt the user for exit confirmation
4515 Args: dflt -- default answer for confirmation prompt
4517 Returns: either NULL if the user accepts exit, or string containing
4518 reason why the user declined.
4521 send_exit_for_pico(struct headerentry
*he
, void (*redraw_pico
)(void), int allow_flowed
,
4524 int i
, rv
, c
, verbose_label
= 0, bg_label
= 0, old_suspend
;
4525 int dsn_label
= 0, fcc_label
= 0, lparen
;
4526 int flowing_label
= 0, double_rad
;
4527 char *rstr
= NULL
, *p
, *lc
, *optp
;
4528 char dsn_string
[30];
4529 void (*redraw
)(void) = ps_global
->redrawer
;
4534 struct filters
*prev
, *next
;
4535 } *filters
= NULL
, *fp
;
4537 sending_filter_requested
= NULL
;
4538 call_mailer_flags
= 0;
4539 background_requested
= 0;
4540 flowing_requested
= allow_flowed
? 1 : 0;
4541 lmc
.text_only
= F_ON(F_NO_FCC_ATTACH
, ps_global
) != 0;
4542 if(priority_requested
)
4543 fs_give((void **) &priority_requested
);
4545 if(background_posting(FALSE
)){
4547 *result
= "Can't send while background posting. Use postpone.";
4552 if(F_ON(F_SEND_WO_CONFIRM
, ps_global
)){
4559 ps_global
->redrawer
= redraw_pico
;
4561 if((old_suspend
= F_ON(F_CAN_SUSPEND
, ps_global
)) != 0)
4562 (void) F_SET(F_CAN_SUSPEND
, ps_global
, 0);
4565 * Build list of available filters...
4567 for(i
=0; ps_global
->VAR_SEND_FILTER
&& ps_global
->VAR_SEND_FILTER
[i
]; i
++){
4568 for(p
= ps_global
->VAR_SEND_FILTER
[i
];
4569 *p
&& !isspace((unsigned char)*p
); p
++)
4574 if(!(is_absolute_path(ps_global
->VAR_SEND_FILTER
[i
])
4575 && can_access(ps_global
->VAR_SEND_FILTER
[i
],EXECUTE_ACCESS
) ==0)){
4580 fp
= (struct filters
*)fs_get(sizeof(struct filters
));
4582 if((lc
= last_cmpnt(ps_global
->VAR_SEND_FILTER
[i
])) != NULL
){
4583 fp
->filter
= cpystr(lc
);
4585 else if((p
- ps_global
->VAR_SEND_FILTER
[i
]) > 20){
4586 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, "...%s", p
- 17);
4587 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
4588 fp
->filter
= cpystr(tmp_20k_buf
);
4591 fp
->filter
= cpystr(ps_global
->VAR_SEND_FILTER
[i
]);
4597 fp
->prev
= filters
->prev
;
4598 fp
->prev
->next
= filters
->prev
= fp
;
4601 filters
= (struct filters
*)fs_get(sizeof(struct filters
));
4602 filters
->index
= -1;
4603 filters
->filter
= NULL
;
4604 filters
->next
= filters
->prev
= fp
;
4605 fp
->next
= fp
->prev
= filters
;
4613 opts
[i
++].label
= N_("Yes");
4618 opts
[i
++].label
= N_("No");
4621 /* set global_filter_pointer to desired filter or NULL if none */
4622 /* prepare two keymenu slots for selecting filter */
4623 opts
[i
].ch
= ctrl('P');
4625 opts
[i
].name
= "^P";
4626 opts
[i
++].label
= N_("Prev Filter");
4628 opts
[i
].ch
= ctrl('N');
4630 opts
[i
].name
= "^N";
4631 opts
[i
++].label
= N_("Next Filter");
4633 if(F_ON(F_FIRST_SEND_FILTER_DFLT
, ps_global
))
4634 filters
= filters
->next
;
4637 if(F_ON(F_VERBOSE_POST
, ps_global
)){
4638 /* setup keymenu slot to toggle verbose mode */
4639 opts
[i
].ch
= ctrl('W');
4641 opts
[i
].name
= "^W";
4642 verbose_label
= i
++;
4646 /* setup keymenu slot to toggle flowed mode */
4647 opts
[i
].ch
= ctrl('V');
4649 opts
[i
].name
= "^V";
4650 flowing_label
= i
++;
4651 flowing_requested
= 1;
4654 if(F_ON(F_NO_FCC_ATTACH
, ps_global
)){
4655 /* setup keymenu slot to toggle attacment on fcc */
4656 opts
[i
].ch
= ctrl('F');
4658 opts
[i
].name
= "^F";
4662 #if defined(BACKGROUND_POST) && defined(SIGCHLD)
4663 if(F_ON(F_BACKGROUND_POST
, ps_global
)){
4664 opts
[i
].ch
= ctrl('R');
4666 opts
[i
].name
= "^R";
4674 opts
[i
++].label
= N_("Priority");
4677 if(F_OFF(F_DONT_DO_SMIME
, ps_global
)){
4681 opts
[i
++].label
= "Encrypt";
4686 opts
[i
++].label
= "Sign";
4688 if(ps_global
->smime
){
4689 ps_global
->smime
->do_encrypt
= F_ON(F_ENCRYPT_DEFAULT_ON
, ps_global
);
4690 ps_global
->smime
->do_sign
= F_ON(F_SIGN_DEFAULT_ON
, ps_global
);
4697 if(F_ON(F_DSN
, ps_global
)){
4698 /* setup keymenu slots to toggle dsn bits */
4702 opts
[i
].label
= N_("DSNOpts");
4707 opts
[i
++].label
= "";
4711 opts
[i
++].label
= "";
4715 opts
[i
++].label
= "";
4719 opts
[i
].ch
= KEY_UP
;
4722 opts
[i
++].label
= "";
4724 opts
[i
].ch
= KEY_DOWN
;
4727 opts
[i
++].label
= "";
4732 fix_windsize(ps_global
);
4735 if(filters
&& filters
->filter
&& (p
= strindex(filters
->filter
, ' ')))
4741 strncpy(tmp_20k_buf
, "Send message", SIZEOF_20KBUF
);
4742 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
4743 optp
= tmp_20k_buf
+ strlen(tmp_20k_buf
);
4745 if(F_ON(F_NO_FCC_ATTACH
, ps_global
) && !lmc
.text_only
)
4746 sstrncpy(&optp
, " and Fcc Atmts", SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4748 if(allow_flowed
&& !flowing_requested
){
4749 if((optp
-tmp_20k_buf
)+2 < SIZEOF_20KBUF
){
4759 sstrncpy(&optp
, "not flowed", SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4763 if((optp
-tmp_20k_buf
)+2 < SIZEOF_20KBUF
){
4775 if(filters
->filter
){
4776 sstrncpy(&optp
, "filtered thru \"", SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4777 sstrncpy(&optp
, filters
->filter
, SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4778 if((optp
-tmp_20k_buf
) < SIZEOF_20KBUF
)
4782 sstrncpy(&optp
, "unfiltered", SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4785 if((call_mailer_flags
& CM_VERBOSE
) || background_requested
){
4786 if((optp
-tmp_20k_buf
)+2 < SIZEOF_20KBUF
){
4796 sstrncpy(&optp
, "in ", SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4797 if(call_mailer_flags
& CM_VERBOSE
)
4798 sstrncpy(&optp
, "verbose ", SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4800 if(background_requested
)
4801 sstrncpy(&optp
, "background ", SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4803 sstrncpy(&optp
, "mode", SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4806 if(g_rolenick
&& !(he
&& he
[N_FROM
].dirty
)){
4807 if((optp
-tmp_20k_buf
)+2 < SIZEOF_20KBUF
){
4817 sstrncpy(&optp
, "as \"", SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4818 sstrncpy(&optp
, g_rolenick
, SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4819 sstrncpy(&optp
, "\"", SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4822 if(call_mailer_flags
& CM_DSN_SHOW
){
4823 if((optp
-tmp_20k_buf
)+2 < SIZEOF_20KBUF
){
4835 sstrncpy(&optp
, dsn_string
, SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4839 if(ps_global
->smime
&& ps_global
->smime
->do_encrypt
){
4840 if((optp
-tmp_20k_buf
)+2 < SIZEOF_20KBUF
){
4852 sstrncpy(&optp
, "Encrypted", SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4855 if(ps_global
->smime
&& ps_global
->smime
->do_sign
){
4856 if((optp
-tmp_20k_buf
)+2 < SIZEOF_20KBUF
){
4868 sstrncpy(&optp
, "Signed", SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4872 if(lparen
&& (optp
-tmp_20k_buf
) < SIZEOF_20KBUF
)
4875 sstrncpy(&optp
, "? ", SIZEOF_20KBUF
-(optp
-tmp_20k_buf
));
4876 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
4882 opts
[flowing_label
].label
= flowing_requested
? N_("NoFlow") : N_("Flow");
4885 opts
[verbose_label
].label
= (call_mailer_flags
& CM_VERBOSE
) ? N_("Normal") : N_("Verbose");
4888 opts
[bg_label
].label
= background_requested
4889 ? N_("Foreground") : N_("Background");
4892 opts
[fcc_label
].label
= lmc
.text_only
? N_("Fcc Attchmnts")
4893 : N_("No Fcc Atmts ");
4895 if(F_ON(F_DSN
, ps_global
)){
4896 if(call_mailer_flags
& CM_DSN_SHOW
){
4897 opts
[dsn_label
].label
= (call_mailer_flags
& CM_DSN_DELAY
)
4898 ? N_("NoDelay") : N_("Delay");
4899 opts
[dsn_label
+1].ch
= 's';
4900 opts
[dsn_label
+1].label
= (call_mailer_flags
& CM_DSN_SUCCESS
)
4901 ? N_("NoSuccess") : N_("Success");
4902 opts
[dsn_label
+2].ch
= 'x';
4903 opts
[dsn_label
+2].label
= (call_mailer_flags
& CM_DSN_NEVER
)
4904 ? N_("ErrRets") : N_("NoErrRets");
4905 opts
[dsn_label
+3].ch
= 'h';
4906 opts
[dsn_label
+3].label
= (call_mailer_flags
& CM_DSN_FULL
)
4907 ? N_("RetHdrs") : N_("RetFull");
4912 ((call_mailer_flags
& CM_DSN_SHOW
)
4913 ? 4 : F_ON(F_DSN
, ps_global
) ? 1 : 0) > 11)
4914 rv
= double_radio_buttons(tmp_20k_buf
, -FOOTER_ROWS(ps_global
), opts
,
4916 (F_ON(F_DSN
, ps_global
) && allow_flowed
)
4917 ? h_send_prompt_dsn_flowed
:
4918 F_ON(F_DSN
, ps_global
) ? h_send_prompt_dsn
:
4919 allow_flowed
? h_send_prompt_flowed
:
4923 rv
= radio_buttons(tmp_20k_buf
, -FOOTER_ROWS(ps_global
), opts
,
4926 ((call_mailer_flags
& CM_DSN_SHOW
)
4927 ? 4 : F_ON(F_DSN
, ps_global
) ? 1 : 0) == 11)
4929 (F_ON(F_DSN
, ps_global
) && allow_flowed
)
4930 ? h_send_prompt_dsn_flowed
:
4931 F_ON(F_DSN
, ps_global
) ? h_send_prompt_dsn
:
4932 allow_flowed
? h_send_prompt_flowed
:
4936 if(rv
== 'y'){ /* user ACCEPTS! */
4939 else if(rv
== 'n'){ /* Declined! */
4940 rstr
= _("No Message Sent");
4943 else if(rv
== 'z'){ /* Cancelled! */
4944 rstr
= _("Send Cancelled");
4947 else if(rv
== 10){ /* PREVIOUS filter */
4948 filters
= filters
->prev
;
4950 else if(rv
== 11){ /* NEXT filter */
4951 filters
= filters
->next
;
4954 lmc
.text_only
= !lmc
.text_only
;
4956 else if(rv
== 12){ /* flip verbose bit */
4957 if(call_mailer_flags
& CM_VERBOSE
)
4958 call_mailer_flags
&= ~CM_VERBOSE
;
4960 call_mailer_flags
|= CM_VERBOSE
;
4962 if((call_mailer_flags
& CM_VERBOSE
) && background_requested
)
4963 background_requested
= 0;
4965 else if(rv
== 22){ /* flip flowing bit */
4966 flowing_requested
= !flowing_requested
;
4969 if((background_requested
= !background_requested
)
4970 && (call_mailer_flags
& CM_VERBOSE
))
4971 call_mailer_flags
&= ~CM_VERBOSE
; /* clear verbose */
4973 else if(call_mailer_flags
& CM_DSN_SHOW
){
4974 if(rv
== 's'){ /* flip success bit */
4975 call_mailer_flags
^= CM_DSN_SUCCESS
;
4976 /* turn off related bits */
4977 if(call_mailer_flags
& CM_DSN_SUCCESS
)
4978 call_mailer_flags
&= ~(CM_DSN_NEVER
);
4980 else if(rv
== 'd'){ /* flip delay bit */
4981 call_mailer_flags
^= CM_DSN_DELAY
;
4982 /* turn off related bits */
4983 if(call_mailer_flags
& CM_DSN_DELAY
)
4984 call_mailer_flags
&= ~(CM_DSN_NEVER
);
4986 else if(rv
== 'x'){ /* flip never bit */
4987 call_mailer_flags
^= CM_DSN_NEVER
;
4988 /* turn off related bits */
4989 if(call_mailer_flags
& CM_DSN_NEVER
)
4990 call_mailer_flags
&= ~(CM_DSN_SUCCESS
| CM_DSN_DELAY
);
4992 else if(rv
== 'h'){ /* flip full bit */
4993 call_mailer_flags
^= CM_DSN_FULL
;
4996 else if(rv
== 'd'){ /* show dsn options */
4998 * When you turn on DSN, the default is to notify on
4999 * failure, success, or delay; and to return the whole
5002 call_mailer_flags
|= (CM_DSN_SHOW
| CM_DSN_SUCCESS
| CM_DSN_DELAY
| CM_DSN_FULL
);
5004 else if(rv
== 'p'){ /* choose X-Priority */
5007 prio
= choose_a_priority(priority_requested
);
5008 if((ps_global
->redrawer
= redraw_pico
) != NULL
){
5009 (*ps_global
->redrawer
)();
5010 fix_windsize(ps_global
);
5014 if(priority_requested
)
5015 fs_give((void **) &priority_requested
);
5018 priority_requested
= prio
;
5020 fs_give((void **) &prio
);
5025 if(ps_global
->smime
)
5026 ps_global
->smime
->do_encrypt
= !ps_global
->smime
->do_encrypt
;
5029 if(ps_global
->smime
)
5030 ps_global
->smime
->do_sign
= !ps_global
->smime
->do_sign
;
5034 snprintf(dsn_string
, sizeof(dsn_string
), "DSN requested[%s%s%s%s]",
5035 (call_mailer_flags
& CM_DSN_NEVER
)
5037 (call_mailer_flags
& CM_DSN_DELAY
)
5039 (call_mailer_flags
& CM_DSN_SUCCESS
)
5041 (call_mailer_flags
& CM_DSN_NEVER
)
5043 : (call_mailer_flags
& CM_DSN_FULL
) ? "-Full"
5045 dsn_string
[sizeof(dsn_string
)-1] = '\0';
5048 /* remember selection */
5049 if(filters
&& filters
->index
> -1)
5050 sending_filter_requested
= ps_global
->VAR_SEND_FILTER
[filters
->index
];
5053 filters
->prev
->next
= NULL
; /* tie off list */
5054 while(filters
){ /* then free it */
5057 fs_give((void **)&filters
->filter
);
5059 fs_give((void **)&filters
);
5065 (void) F_SET(F_CAN_SUSPEND
, ps_global
, 1);
5070 ps_global
->redrawer
= redraw
;
5072 return((rstr
== NULL
) ? 0 : 1);
5077 * Allow user to choose a priority for sending.
5079 * Returns an allocated priority on success, NULL otherwise.
5082 choose_a_priority(char *default_val
)
5084 char *choice
= NULL
;
5085 char **priority_list
, **lp
;
5086 char *starting_val
= NULL
;
5091 for(cnt
= 0, p
= priorities
; p
&& p
->desc
; p
++)
5094 cnt
++; /* for NONE entry */
5095 lp
= priority_list
= (char **) fs_get((cnt
+ 1) * sizeof(*priority_list
));
5096 memset(priority_list
, 0, (cnt
+1) * sizeof(*priority_list
));
5098 for(i
= 0, p
= priorities
; p
&& p
->desc
; p
++){
5099 *lp
= cpystr(p
->desc
);
5100 if(default_val
&& !strcmp(default_val
, p
->desc
))
5101 starting_val
= (*lp
);
5106 none
= _("NONE - No X-Priority header included");
5109 starting_val
= (*lp
);
5111 /* TRANSLATORS: SELECT A PRIORITY is a screen title
5112 TRANSLATORS: Print something1 using something2.
5113 "priorities" is something1 */
5114 choice
= choose_item_from_list(priority_list
, NULL
, _("SELECT A PRIORITY"),
5115 _("priorities"), h_select_priority_screen
,
5116 _("HELP FOR SELECTING A PRIORITY"),
5120 q_status_message(SM_ORDER
, 1, 4, _("No change"));
5121 else if(!strcmp(choice
, none
))
5124 free_list_array(&priority_list
);
5131 dont_flow_this_time(void)
5133 return(flowing_requested
? 0 : 1);
5137 /*----------------------------------------------------------------------
5138 Call back for pico to display mime type of attachment
5140 Args: file -- filename being attached
5142 Returns: returns 1 on success (message queued), zero otherwise (don't know
5143 type so nothing queued).
5146 mime_type_for_pico(char *file
)
5150 void *file_contents
;
5152 body
= mail_newbody();
5153 body
->type
= TYPEOTHER
;
5154 body
->encoding
= ENCOTHER
;
5156 /* don't know where the cursor's been, reset it */
5158 if(!set_mime_type_by_extension(body
, file
)){
5159 if((file_contents
=(void *)so_get(FileStar
,file
,READ_ACCESS
|READ_FROM_LOCALE
)) != NULL
){
5160 body
->contents
.text
.data
= file_contents
;
5161 set_mime_type_by_grope(body
);
5165 if(body
->type
!= TYPEOTHER
){
5167 q_status_message3(SM_ORDER
, 0, 3,
5168 _("File %s attached as type %s/%s"), file
,
5169 body_types
[body
->type
],
5170 body
->subtype
? body
->subtype
: rfc822_default_subtype(body
->type
));
5175 pine_free_body(&body
);
5180 /*----------------------------------------------------------------------
5181 Call back for pico to receive an uploaded message
5183 Args: fname -- name for uploaded file (empty if they want us to assign it)
5184 size -- pointer to long to hold the attachment's size
5186 Notes: the attachment is uploaded to a temp file, and
5188 Returns: TRUE on success, FALSE otherwise
5191 upload_msg_to_pico(char *fname
, size_t fnlen
, long int *size
)
5193 char cmd
[MAXPATH
+1], *fnp
= NULL
;
5194 char *locale_name
= NULL
;
5198 dprint((1, "Upload cmd called to xfer \"%s\"\n",
5199 fname
? fname
: "<NO FILE>"));
5201 if(!fname
) /* no place for file name */
5204 if(!*fname
){ /* caller wants temp file */
5205 if((fnp
= temp_nam(NULL
, "pu")) != NULL
){
5206 strncpy(fname
, fnp
, fnlen
);
5207 fname
[fnlen
-1] = '\0';
5209 fs_give((void **)&fnp
);
5213 locale_name
= convert_to_locale(fname
);
5215 build_updown_cmd(cmd
, sizeof(cmd
), ps_global
->VAR_UPLOAD_CMD_PREFIX
,
5216 ps_global
->VAR_UPLOAD_CMD
, locale_name
? locale_name
: fname
);
5217 if((syspipe
= open_system_pipe(cmd
, NULL
, NULL
, PIPE_USER
| PIPE_RESET
,
5218 0, pipe_callback
, pipe_report_error
)) != NULL
){
5219 (void) close_system_pipe(&syspipe
, NULL
, pipe_callback
);
5220 if((l
= name_file_size(locale_name
? locale_name
: fname
)) < 0L){
5221 q_status_message2(SM_ORDER
| SM_DING
, 3, 4,
5222 "Error determining size of %s: %s", fname
,
5223 fnp
= error_description(errno
));
5225 "!!! Upload cmd \"%s\" failed for \"%s\": %s\n",
5227 fname
? fname
: "?",
5234 fs_give((void **) &locale_name
);
5239 q_status_message(SM_ORDER
| SM_DING
, 3, 4, _("Error opening pipe"));
5242 fs_give((void **) &locale_name
);
5249 cancel_for_pico(void (*redraw_pico
)(void))
5254 _("Cancel message (answering \"Confirm\" will abandon your mail message) ? ");
5255 void (*redraw
)(void) = ps_global
->redrawer
;
5256 static ESCKEY_S opts
[] = {
5257 {'c', 'c', "C", N_("Confirm")},
5258 {'n', 'n', "N", N_("No")},
5263 ps_global
->redrawer
= redraw_pico
;
5264 fix_windsize(ps_global
);
5267 rv
= radio_buttons(prompt
, -FOOTER_ROWS(ps_global
), opts
,
5268 'n', 'x', h_confirm_cancel
, RB_NORM
);
5269 if(rv
== 'c'){ /* user ACCEPTS! */
5274 q_status_message(SM_INFO
, 1, 3, _(" Type \"C\" to cancel message "));
5275 display_message('x');
5281 ps_global
->redrawer
= redraw
;
5286 /*----------------------------------------------------------------------
5287 Pass the first text segment of the message thru the "send filter"
5289 Args: body pointer and address for storage object of old data
5291 Returns: returns 1 on success, zero on error.
5294 filter_message_text(char *fcmd
, ENVELOPE
*outgoing
, struct mail_bodystruct
*body
,
5295 STORE_S
**old
, METAENV
*header
)
5297 char *cmd
, *tmpf
= NULL
, *resultf
= NULL
, *errstr
= NULL
, *mtf
= NULL
;
5298 int key
= 0, include_hdrs
= 0;
5300 STORE_S
**so
= (STORE_S
**)((body
->type
== TYPEMULTIPART
)
5301 ? &body
->nested
.part
->body
.contents
.text
.data
5302 : &body
->contents
.text
.data
),
5303 *tmp_so
= NULL
, *tmpf_so
,
5304 *save_local_so
, *readthis_so
= NULL
, *our_tmpf_so
= NULL
;
5305 #define DO_HEADERS 1
5308 && (cmd
=expand_filter_tokens(fcmd
, outgoing
, &tmpf
, &resultf
, &mtf
,
5309 &key
, &include_hdrs
, NULL
))){
5312 * We need WRITE_TO_LOCALE here because the user is going to
5313 * be operating on tmpf. We need to change it back after they
5316 if((tmpf_so
= so_get(FileStar
, tmpf
, EDIT_ACCESS
|OWNER_ONLY
|WRITE_TO_LOCALE
)) != NULL
){
5318 so_puts(tmpf_so
, filter_session_key());
5319 so_puts(tmpf_so
, NEWLINE
);
5323 * If the headers are wanted for filtering, we can just
5324 * stick them in the tmpf file that is already there before
5325 * putting the body in.
5328 save_local_so
= lmc
.so
;
5329 lmc
.so
= tmpf_so
; /* write it to tmpf_so */
5330 lmc
.all_written
= lmc
.text_written
= lmc
.text_only
= 0;
5331 pine_rfc822_header(header
, body
, NULL
, NULL
);
5332 lmc
.so
= save_local_so
;
5335 so_seek(*so
, 0L, 0);
5336 gf_set_so_readc(&gc
, *so
);
5337 gf_set_so_writec(&pc
, tmpf_so
);
5339 errstr
= gf_pipe(gc
, pc
);
5340 gf_clear_so_readc(*so
);
5341 gf_clear_so_writec(tmpf_so
);
5345 errstr
= "Can't create space for filter temporary file.";
5347 else if(include_hdrs
){
5349 * Gf_filter wants a single storage object to read from.
5350 * If headers are wanted for filtering we'll have to put them
5351 * and the body into a temp file first and then use that
5352 * as the storage object for gf_filter.
5353 * We don't use WRITE_TO_LOCALE in this case because gf_filter
5354 * takes care of that.
5356 if((our_tmpf_so
= so_get(TmpFileStar
, NULL
, EDIT_ACCESS
|OWNER_ONLY
)) != NULL
){
5357 /* put headers in our_tmpf_so */
5358 save_local_so
= lmc
.so
;
5359 lmc
.so
= our_tmpf_so
; /* write it to our_tmpf_so */
5360 lmc
.all_written
= lmc
.text_written
= lmc
.text_only
= 0;
5361 pine_rfc822_header(header
, body
, NULL
, NULL
);
5362 lmc
.so
= save_local_so
;
5364 /* put body in our_tmpf_so */
5365 so_seek(*so
, 0L, 0);
5366 gf_set_so_readc(&gc
, *so
);
5367 gf_set_so_writec(&pc
, our_tmpf_so
);
5369 errstr
= gf_pipe(gc
, pc
);
5370 gf_clear_so_readc(*so
);
5371 gf_clear_so_writec(our_tmpf_so
);
5373 /* tell gf_filter to read from our_tmpf_so instead of *so */
5374 readthis_so
= our_tmpf_so
;
5377 errstr
= "Can't create space for temporary file.";
5383 if((tmp_so
= so_get(PicoText
, NULL
, EDIT_ACCESS
)) != NULL
){
5384 gf_set_so_writec(&pc
, tmp_so
);
5385 ps_global
->mangled_screen
= 1;
5392 if((fpipe
= open_system_pipe(cmd
, NULL
, NULL
,
5393 PIPE_NOSHELL
| PIPE_RESET
,
5394 0, pipe_callback
, pipe_report_error
)) != NULL
){
5395 if(close_system_pipe(&fpipe
, NULL
, pipe_callback
) == 0){
5397 /* now we undo the WRITE_FROM_LOCALE change in tmpf */
5398 if((tmpf_so
= so_get(FileStar
, tmpf
, READ_ACCESS
|READ_FROM_LOCALE
)) != NULL
){
5399 gf_set_so_readc(&gc
, tmpf_so
);
5401 errstr
= gf_pipe(gc
, pc
);
5402 gf_clear_so_readc(tmpf_so
);
5406 errstr
= "Can't open temp file filter wrote.";
5409 errstr
= "Filter command returned error.";
5412 errstr
= "Can't exec filter text.";
5415 errstr
= gf_filter(cmd
, key
? filter_session_key() : NULL
,
5416 readthis_so
, pc
, NULL
, 0, 0,
5420 so_give(&our_tmpf_so
);
5422 gf_clear_so_writec(tmp_so
);
5427 * Can't really be using stdout, so don't print message that
5428 * gets printed in the else. Ideally the program being called
5429 * will wait after showing the message, we might want to look
5430 * into doing the waiting in console based apps... or not.
5436 fprintf(stdout
, "\r\n%s Hit return to continue.", errstr
);
5438 while((ch
= read_char(300)) != ctrl('M')
5439 && ch
!= NO_OP_IDLE
)
5443 #endif /* _WINDOWS */
5444 BODY
*b
= (body
->type
== TYPEMULTIPART
)
5445 ? &body
->nested
.part
->body
: body
;
5447 *old
= *so
; /* save old so */
5448 *so
= tmp_so
; /* return new one */
5449 (*so
)->attr
= copy_parameters((*old
)->attr
);
5452 * If the command said it would return new MIME
5453 * mime type data, check it out...
5456 char buf
[MAILTMPLEN
], *s
;
5459 if((fp
= our_fopen(mtf
, "rb")) != NULL
){
5460 if(fgets(buf
, sizeof(buf
), fp
)
5461 && !struncmp(buf
, "content-", 8)
5462 && (s
= strchr(buf
+8, ':'))){
5463 BODY
*nb
= mail_newbody();
5465 for(*s
++ = '\0'; *s
== ' '; s
++)
5468 rfc822_parse_content_header(nb
,
5469 (char *) ucase((unsigned char *) buf
+8),s
);
5470 if(nb
->type
== TYPETEXT
5473 || strucmp(b
->subtype
, nb
->subtype
))){
5475 fs_give((void **) &b
->subtype
);
5477 b
->subtype
= nb
->subtype
;
5480 mail_free_body_parameter(&b
->parameter
);
5481 b
->parameter
= nb
->parameter
;
5482 nb
->parameter
= NULL
;
5483 mail_free_body_parameter(&nb
->parameter
);
5486 mail_free_body(&nb
);
5494 * Reevaluate the encoding in case form's changed...
5496 b
->encoding
= ENCOTHER
;
5497 set_mime_type_by_grope(b
);
5504 errstr
= "Can't create space for filtered text.";
5507 fs_give((void **)&cmd
);
5514 fs_give((void **)&tmpf
);
5519 fs_give((void **) &mtf
);
5523 if(name_file_size(resultf
) > 0L)
5524 display_output_file(resultf
, "Filter", NULL
, DOF_BRIEF
);
5525 our_unlink(resultf
);
5526 fs_give((void **)&resultf
);
5532 q_status_message1(SM_ORDER
| SM_DING
, 3, 6, _("Problem filtering: %s"),
5534 dprint((1, "Filter FAILED: %s\n",
5535 errstr
? errstr
: "?"));
5538 return(errstr
== NULL
);
5542 /*----------------------------------------------------------------------
5543 Copy the newsgroup name of the given mailbox into the given buffer
5550 pine_send_newsgroup_name(char *mailbox
, char *group_name
, size_t len
)
5554 if(*mailbox
== '#'){ /* Strip the leading "#news." */
5555 strncpy(group_name
, mailbox
+ 6, len
-1);
5556 group_name
[len
-1] = '\0';
5558 else if(mail_valid_net_parse(mailbox
, &mb
)){
5559 pine_send_newsgroup_name(mb
.mailbox
, group_name
, len
);
5566 /*----------------------------------------------------------------------
5567 Set up fields for passing to pico. Assumes first text part is
5568 intended to be passed along for editing, and is in the form of
5569 of a storage object brought into existence sometime before pico_send().
5572 outgoing2strings(METAENV
*header
, struct mail_bodystruct
*bod
, void **text
,
5573 PATMT
**pico_a
, int from_bounce
)
5578 * SIMPLIFYING ASSUMPTION #37: the first TEXT part's storage object
5579 * is guaranteed to be of type PicoText!
5581 if(bod
->type
== TYPETEXT
){
5582 *text
= so_text((STORE_S
*) bod
->contents
.text
.data
);
5584 /* mark storage object as user edited */
5586 (void) so_attr((STORE_S
*) bod
->contents
.text
.data
, "edited", "1");
5588 else if(bod
->type
== TYPEMULTIPART
){
5591 char *type
, *name
, *p
;
5595 * We used to jump out the window if the first part wasn't text,
5596 * but that may not be the case when bouncing a message with
5597 * a leading non-text segment. So, IT'S UNDERSTOOD that the
5598 * contents of the first part to send is still ALWAYS in a
5599 * PicoText storage object, *AND* if that object doesn't contain
5600 * data of type text, then it must contain THE ENCODED NON-TEXT
5601 * DATA of the piece being sent.
5603 * It's up to the programmer to make sure that such a message is
5604 * sent via pine_simple_send and never get to the composer via
5609 *text
= so_text((STORE_S
*) bod
->nested
.part
->body
.contents
.text
.data
);
5611 /* mark storage object as user edited */
5613 (void) so_attr((STORE_S
*) bod
->nested
.part
->body
.contents
.text
.data
, "edited", "1");
5616 * If we already had a list, blast it now, so we can build a new
5617 * attachment list that reflects what's really there...
5620 free_attachment_list(pico_a
);
5623 /* Simplifyihg assumption #28e. (see cross reference)
5624 All parts in the body passed in here that are not already
5625 in the attachments list are added to the end of the attachments
5626 list. Attachment items not in the body list will be taken care
5627 of in strings2outgoing, but they are unlikely to occur
5630 for(part
= bod
->nested
.part
->next
; part
!= NULL
; part
= part
->next
) {
5631 /* Already in list? */
5633 *ppa
&& strcmp((*ppa
)->id
, part
->body
.id
);
5634 ppa
= &(*ppa
)->next
)
5637 if(!*ppa
){ /* Not in the list! append it... */
5638 *ppa
= (PATMT
*)fs_get(sizeof(PATMT
));
5640 if(part
->body
.description
){
5644 len
= 4*strlen(part
->body
.description
)+1;
5645 p
= (char *)fs_get(len
*sizeof(char));
5646 if(rfc1522_decode_to_utf8((unsigned char *)p
,
5647 len
, part
->body
.description
) == (unsigned char *) p
){
5648 (*ppa
)->description
= p
;
5651 fs_give((void **)&p
);
5652 (*ppa
)->description
= cpystr(part
->body
.description
);
5656 (*ppa
)->description
= cpystr("");
5658 type
= type_desc(part
->body
.type
, part
->body
.subtype
,
5659 part
->body
.parameter
, NULL
, 0);
5662 * If we can find a "name" parm, display that too...
5664 if((name
= parameter_val(part
->body
.parameter
, "name")) != NULL
){
5665 /* Convert any [ or ]'s the name contained */
5666 for(p
= name
; *p
; p
++)
5677 (*ppa
)->filename
= fs_get(strlen(type
) + name_l
+ 5);
5679 snprintf((*ppa
)->filename
, strlen(type
) + name_l
+ 5, "[%s%s%s]", type
,
5680 name
? ": " : "", name
? name
: "");
5681 (*ppa
)->filename
[strlen(type
) + name_l
+ 5 - 1] = '\0';
5684 fs_give((void **) &name
);
5686 (*ppa
)->flags
= A_FLIT
;
5687 (*ppa
)->size
= cpystr(byte_string(
5688 send_body_size(&part
->body
)));
5690 part
->body
.id
= generate_message_id(NULL
);
5692 (*ppa
)->id
= cpystr(part
->body
.id
);
5693 (*ppa
)->next
= NULL
;
5700 /*------------------------------------------------------------------
5701 Malloc strings to pass to composer editor because it expects
5702 such strings so it can realloc them
5703 -----------------------------------------------------------------*/
5705 * turn any address fields into text strings
5708 * SIMPLIFYING ASSUMPTION #116: all header strings are understood
5709 * NOT to be RFC1522 decoded. Said differently, they're understood
5710 * to be RFC1522 ENCODED as necessary. The intent is to preserve
5711 * original charset tagging as far into the compose/send pipe as
5714 for(pf
= header
->local
; pf
&& pf
->name
; pf
= pf
->next
)
5722 pf
->scratch
= addr_list_string(*pf
->addr
, NULL
, 1);
5725 * Scan for and fix-up patently bogus fields.
5727 * NOTE: collaboration with this code and what's done in
5728 * reply.c:reply_cp_addr to package up the bogus stuff
5731 for(p
= pf
->scratch
; (p
= strstr(p
, "@" RAWFIELD
)); )
5733 if(*t
== '&'){ /* find "leading" token */
5737 * Rfc822_cat has been changed so that it now quotes
5738 * this sometimes. So we have to look out for quotes
5739 * which confuse the decoder. It was only quoting
5740 * because we were putting \r \n in the input, I think.
5742 if(t
> pf
->scratch
&& t
[-1] == '\"' && p
[-1] == '\"')
5743 t
[-1] = p
[-1] = ' ';
5745 *t
++ = ' '; /* replace token */
5746 *p
= '\0'; /* tie off string */
5747 u
= rfc822_base64((unsigned char *) t
,
5748 (unsigned long) strlen(t
),
5749 (unsigned long *) &l
);
5753 replacelen
= strlen(t
);
5754 *p
= '@'; /* restore 'p' */
5755 rplstr(p
, strlen(p
), 12, ""); /* clear special token */
5756 rplstr(t
, strlen(u
)-replacelen
+1, replacelen
, u
);
5758 fs_give((void **) &u
);
5761 HE(pf
)->start_here
= 1;
5765 else if(t
== pf
->scratch
)
5768 removing_leading_white_space(pf
->scratch
);
5773 * Replace control characters with ^C notation, unless
5774 * some conditions are met (see istrncpy).
5775 * If user doesn't edit, then we switch back to the
5776 * original version. If user does edit, then all bets
5779 iutf8ncpy((char *)tmp_20k_buf
, pf
->scratch
, SIZEOF_20KBUF
-1);
5780 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
5781 if((l
=strlen((char *)tmp_20k_buf
)) > strlen(pf
->scratch
)){
5782 fs_give((void **)&pf
->scratch
);
5783 pf
->scratch
= (char *)fs_get((l
+1) * sizeof(char));
5786 strncpy(pf
->scratch
, (char *)tmp_20k_buf
, l
+1);
5797 src
= pf
->scratch
? pf
->scratch
5798 : (*pf
->text
) ? *pf
->text
: "";
5800 len
= 4*strlen(src
)+1;
5801 p
= (char *)fs_get(len
* sizeof(char));
5802 if(rfc1522_decode_to_utf8((unsigned char *)p
, len
, src
) == (unsigned char *) p
){
5804 fs_give((void **)&pf
->scratch
);
5809 fs_give((void **)&p
);
5811 pf
->scratch
= cpystr(src
);
5818 * Replace control characters with ^C notation, unless
5819 * some conditions are met (see istrncpy).
5820 * If user doesn't edit, then we switch back to the
5821 * original version. If user does edit, then all bets
5824 iutf8ncpy((char *)tmp_20k_buf
, pf
->scratch
, SIZEOF_20KBUF
-1);
5825 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
5826 if((l
=strlen((char *)tmp_20k_buf
)) > strlen(pf
->scratch
)){
5827 fs_give((void **)&pf
->scratch
);
5828 pf
->scratch
= (char *)fs_get((l
+1) * sizeof(char));
5831 strncpy(pf
->scratch
, (char *)tmp_20k_buf
, l
+1);
5843 /*----------------------------------------------------------------------
5844 Restore fields returned from pico to form useful to sending
5848 strings2outgoing(METAENV
*header
, struct mail_bodystruct
**bod
, PATMT
*attach
, int flow_it
)
5853 we_cancel
= busy_cue(NULL
, NULL
, 1);
5856 * turn any local address strings into address lists
5858 for(pf
= header
->local
; pf
&& pf
->name
; pf
= pf
->next
)
5860 char *the_address
= NULL
;
5864 removing_trailing_white_space(pf
->scratch
);
5866 if((the_address
|| *pf
->scratch
) && pf
->addr
){
5867 ADDRESS
*new_addr
= NULL
;
5868 static char *fakedomain
= "@";
5871 the_address
= pf
->scratch
;
5873 rfc822_parse_adrlist(&new_addr
, the_address
,
5874 (F_ON(F_COMPOSE_REJECTS_UNQUAL
, ps_global
))
5875 ? fakedomain
: ps_global
->maildomain
);
5876 mail_free_address(pf
->addr
); /* free old addrs */
5877 *pf
->addr
= new_addr
; /* assign new addr */
5880 mail_free_address(pf
->addr
); /* free old addrs */
5886 fs_give((void **)pf
->text
);
5889 *pf
->text
= cpystr(pf
->scratch
);
5898 fs_give((void **)&pf
->scratch
); /* free now useless text */
5901 create_message_body(bod
, attach
, flow_it
);
5904 cancel_busy_cue(-1);
5908 /*----------------------------------------------------------------------
5910 The head of the body list here is always either TEXT or MULTIPART. It may be
5911 changed from TEXT to MULTIPART if there are attachments to be added
5912 and it is not already multipart.
5915 create_message_body(struct mail_bodystruct
**b
, PATMT
*attach
, int flow_it
)
5919 BODY
*tmp_body
, *text_body
= NULL
;
5920 void *file_contents
;
5924 TIME_STAMP("create_body start.", 1);
5926 * if conditions are met short circuit MIME wrapping
5928 if((*b
)->type
!= TYPEMULTIPART
&& !attach
){
5930 /* only override assigned encoding if it might need upgrading */
5931 if((*b
)->type
== TYPETEXT
&& (*b
)->encoding
== ENC7BIT
)
5932 (*b
)->encoding
= ENCOTHER
;
5934 create_message_body_text(*b
, flow_it
);
5936 if(F_ON(F_COMPOSE_ALWAYS_DOWNGRADE
, ps_global
)
5937 || !((*b
)->encoding
== ENC8BIT
5938 || (*b
)->encoding
== ENCBINARY
)){
5939 TIME_STAMP("create_body end.", 1);
5942 else /* protect 8bit in multipart */
5946 if((*b
)->type
== TYPETEXT
) {
5947 /*-- Current type is text, but there are attachments to add --*/
5948 /*-- Upgrade to a TYPEMULTIPART --*/
5949 tmp_body
= (BODY
*)mail_newbody();
5950 tmp_body
->type
= TYPEMULTIPART
;
5951 tmp_body
->nested
.part
= mail_newbody_part();
5954 * Why do we do this?
5955 * The problem is that base64 or quoted-printable encoding is
5956 * sensitive to having random data appended to it's end. If
5957 * we use a single part TEXT message and something in between
5958 * us and the end appends advertising without adjusting for
5959 * the encoding, the message is screwed up. So we wrap the
5960 * text part inside a multipart and then the appended data
5961 * will come after the boundary.
5963 * We wish we could do this on the way out the door in a
5964 * child of post_rfc822_output because at that point we know
5965 * the character set and the encoding being used. For example,
5966 * iso-2022-jp is an encoding that is not sensitive to data
5967 * appended to the end, so it wouldn't need to be wrapped.
5968 * We could conceivably have post_rfc822_body inspect the
5969 * body and change it before doing the output. It would work
5970 * but would be very fragile. We'd be passed a body from
5971 * c-client to output and instead of just doing the output
5972 * we'd change the body and then output it. Not worth it
5973 * since the multipart wrapping is completely correct for
5974 * MIME-aware mailers.
5976 (void) copy_body(&(tmp_body
->nested
.part
->body
), *b
);
5977 /* move contents which were NOT copied */
5978 tmp_body
->nested
.part
->body
.contents
.text
.data
= (*b
)->contents
.text
.data
;
5979 (*b
)->contents
.text
.data
= NULL
;
5982 tmp_body
->nested
.part
->body
= **b
;
5984 (*b
)->subtype
= (*b
)->id
= (*b
)->description
= NULL
;
5985 (*b
)->parameter
= NULL
;
5986 (*b
)->contents
.text
.data
= NULL
;
5994 /*-- Now type must be MULTIPART with first part text --*/
5995 (*b
)->nested
.part
->body
.encoding
= ENCOTHER
;
5996 create_message_body_text(&((*b
)->nested
.part
->body
), flow_it
);
5999 /*------ Go through the parts list remove those to be deleted -----*/
6000 for(pp
= &(*b
)->nested
.part
->next
; *pp
;){
6001 for(pa
= attach
; pa
&& (*pp
)->body
.id
; pa
= pa
->next
)
6002 /* already existed? */
6003 if(pa
->id
&& strcmp(pa
->id
, (*pp
)->body
.id
) == 0){
6004 char *orig_descp
= NULL
, *cs
= NULL
;
6007 * decode original to see if it matches what was decoded
6008 * when we sent it in.
6011 if((*pp
)->body
.description
)
6012 orig_descp
= (char *) rfc1522_decode_to_utf8((unsigned char *) tmp_20k_buf
,
6013 SIZEOF_20KBUF
, (*pp
)->body
.description
);
6015 if(!(*pp
)->body
.description
/* update description? */
6016 || (pa
->description
&& strcmp(pa
->description
, orig_descp
))){
6017 if((*pp
)->body
.description
)
6018 fs_give((void **) &(*pp
)->body
.description
);
6020 /* encoding happens as msg text is written */
6021 (*pp
)->body
.description
= cpystr(pa
->description
);
6025 fs_give((void **) &cs
);
6031 p
= *pp
; /* prepare to zap *pp */
6032 *pp
= p
->next
; /* pull next one in list up */
6033 p
->next
= NULL
; /* tie off removed node */
6035 pine_free_body_data(&p
->body
); /* clean up contained data */
6036 mail_free_body_part(&p
); /* free up the part */
6042 /*---------- Now add any new attachments ---------*/
6043 for(p
= (*b
)->nested
.part
; p
->next
!= NULL
; p
= p
->next
);
6044 for(pa
= attach
; pa
!= NULL
; pa
= pa
->next
) {
6046 continue; /* Has an ID, it's old */
6049 * the idea is handle ALL attachments as open FILE *'s. Actual
6050 * encoding and such is handled at the time the message
6051 * is shoved into the mail slot or written to disk...
6053 * Also, we never unlink a file, so it's up to whoever opens
6054 * it to deal with tmpfile issues.
6056 if((file_contents
= (void *)so_get(FileStar
, pa
->filename
,
6057 READ_ACCESS
)) == NULL
){
6058 q_status_message2(SM_ORDER
| SM_DING
, 3, 4,
6059 _("Error \"%s\", couldn't attach file \"%s\""),
6060 error_description(errno
), pa
->filename
);
6061 display_message('x');
6065 p
->next
= mail_newbody_part();
6067 p
->body
.id
= generate_message_id(NULL
);
6068 p
->body
.contents
.text
.data
= file_contents
;
6071 * Set type to unknown and let set_mime_type_by_* figure it out.
6072 * Always encode attachments we add as BINARY.
6074 p
->body
.type
= TYPEOTHER
;
6075 p
->body
.encoding
= ENCBINARY
;
6076 p
->body
.size
.bytes
= name_file_size(pa
->filename
);
6077 if(!set_mime_type_by_extension(&p
->body
, pa
->filename
)){
6078 set_mime_type_by_grope(&p
->body
);
6079 set_charset_possibly_to_ascii(&p
->body
, ps_global
->keyboard_charmap
);
6082 so_release((STORE_S
*)p
->body
.contents
.text
.data
);
6084 if(pa
->description
) /* encoding happens when msg written */
6085 p
->body
.description
= cpystr(pa
->description
);
6087 /* Add name attribute for backward compatibility */
6088 for(parmp
= &p
->body
.parameter
; *parmp
; )
6089 if(!struncmp((*parmp
)->attribute
, "name", 4)
6090 && (!*((*parmp
)->attribute
+ 4)
6091 || *((*parmp
)->attribute
+ 4) == '*')){
6092 PARAMETER
*free_me
= *parmp
;
6093 *parmp
= (*parmp
)->next
;
6094 free_me
->next
= NULL
;
6095 mail_free_body_parameter(&free_me
);
6098 parmp
= &(*parmp
)->next
;
6100 set_parameter(parmp
, "name",
6102 ? ((lc
= last_cmpnt(pa
->filename
)) ? lc
: pa
->filename
)
6105 /* Then set the Content-Disposition ala RFC1806 */
6106 if(!p
->body
.disposition
.type
){
6107 p
->body
.disposition
.type
= cpystr("attachment");
6108 for(parmp
= &p
->body
.disposition
.parameter
; *parmp
; )
6109 if(!struncmp((*parmp
)->attribute
, "filename", 4)
6110 && (!*((*parmp
)->attribute
+ 4)
6111 || *((*parmp
)->attribute
+ 4) == '*')){
6112 PARAMETER
*free_me
= *parmp
;
6113 *parmp
= (*parmp
)->next
;
6114 free_me
->next
= NULL
;
6115 mail_free_body_parameter(&free_me
);
6118 parmp
= &(*parmp
)->next
;
6120 set_parameter(parmp
, "filename",
6122 ? ((lc
= last_cmpnt(pa
->filename
)) ? lc
: pa
->filename
)
6127 pa
->id
= cpystr(p
->body
.id
);
6131 * Now, if this multipart has but one text piece (that is, no
6132 * attachments), then downgrade from a composite type to a discrete
6133 * text/plain message if CTE is not 8bit.
6135 if(!(*b
)->nested
.part
->next
6136 && (*b
)->nested
.part
->body
.type
== TYPETEXT
6137 && (F_ON(F_COMPOSE_ALWAYS_DOWNGRADE
, ps_global
)
6138 || !((*b
)->nested
.part
->body
.encoding
== ENC8BIT
6139 || (*b
)->nested
.part
->body
.encoding
== ENCBINARY
))){
6140 /* Clone the interesting body part */
6141 tmp_body
= mail_newbody();
6142 *tmp_body
= (*b
)->nested
.part
->body
;
6143 /* and rub out what we don't want cleaned up when it's free'd */
6144 mail_initbody(&(*b
)->nested
.part
->body
);
6150 TIME_STAMP("create_body end.", 1);
6155 * Fill in text BODY part's structure
6159 create_message_body_text(struct mail_bodystruct
*b
, int flow_it
)
6161 set_mime_type_by_grope(b
);
6163 remove_parameter(&b
->parameter
, "format"); /* we will set it up below */
6164 remove_parameter(&b
->parameter
, "delsp"); /* we never set this up */
6166 if(F_OFF(F_QUELL_FLOWED_TEXT
, ps_global
)
6167 && F_OFF(F_STRIP_WS_BEFORE_SEND
, ps_global
)
6169 set_parameter(b
? &b
->parameter
: NULL
, "format", "flowed");
6176 * free_attachment_list - free attachments in given list
6179 free_attachment_list(PATMT
**alist
)
6183 while(alist
&& *alist
){ /* pointer pointing to something */
6184 leading
= (*alist
)->next
;
6185 if((*alist
)->description
)
6186 fs_give((void **)&(*alist
)->description
);
6188 if((*alist
)->filename
){
6189 if((*alist
)->flags
& A_TMP
)
6190 if(our_unlink((*alist
)->filename
) < 0)
6191 dprint((1, "-- Can't unlink(%s): %s\n",
6192 (*alist
)->filename
? (*alist
)->filename
: "?",
6193 error_description(errno
)));
6195 fs_give((void **)&(*alist
)->filename
);
6199 fs_give((void **)&(*alist
)->size
);
6202 fs_give((void **)&(*alist
)->id
);
6204 fs_give((void **)alist
);
6212 set_body_size(struct mail_bodystruct
*b
)
6217 we_cancel
= busy_cue(NULL
, NULL
, 1);
6218 so_seek((STORE_S
*)b
->contents
.text
.data
, 0L, 0);
6220 while(so_readc(&c
, (STORE_S
*)b
->contents
.text
.data
))
6224 cancel_busy_cue(-1);
6229 * view_as_rich - set the rich_header flag
6231 * name - name of the header field
6232 * deflt - default value to return if user didn't set it
6234 * Note: if the user tries to turn them all off with "", then
6235 * we take that to mean default, since otherwise there is no
6236 * way to get to the headers.
6239 view_as_rich(char *name
, int deflt
)
6244 p
= ps_global
->VAR_COMP_HDRS
;
6247 for(; (q
= *p
) != NULL
; p
++){
6248 if(!struncmp(q
, name
, strlen(name
)))
6249 return 0; /* 0 means we *do* view it by default */
6252 return 1; /* 1 means it starts out hidden */
6259 * background_posting - return whether or not we're already in the process
6263 background_posting(int gripe
)
6265 if(ps_global
->post
){
6267 q_status_message(SM_ORDER
|SM_DING
, 3, 3,
6268 _("Can't post while posting!"));
6276 /*----------------------------------------------------------------------
6277 Validate the given subject relative to any news groups.
6281 Returns: always returns 1, but also returns error if
6284 valid_subject(char *given
, char **expanded
, char **error
, BUILDER_ARG
*fcc
, int *mangled
)
6286 struct headerentry
*hp
;
6289 *expanded
= cpystr(given
);
6293 * Now look for any header entry we passed to pico that has to do
6294 * with news. If there's no subject, gripe.
6296 for(hp
= pbf
->headents
; hp
->prompt
; hp
++)
6297 if(hp
->help
== h_composer_news
){
6298 if(hp
->hd_text
->text
[0] && !*given
)
6300 _("News postings MUST have a subject! Please add one!"));
6311 * This is the build_address used by the composer to check for an address
6314 * Args: to -- the passed in line to parse
6315 * full_to -- Address of a pointer to return the full address in.
6316 * This will be allocated here and freed by the caller.
6317 * error -- Address of a pointer to return an error message in.
6318 * This will be allocated here and freed by the caller.
6319 * barg -- Address of a pointer to return the fcc in is in
6320 * fcc->tptr. It will have already been allocated by the
6321 * caller but we may free it and reallocate if we wish.
6322 * Caller will free it.
6324 * Result: 0 is returned if address was OK,
6325 * -1 if address wasn't OK.
6327 * Side effect: Can flush addrbook entry cache entries so they need to be
6328 * re-fetched afterwords.
6331 build_address(char *to
, char **full_to
, char **error
, BUILDER_ARG
*barg
, int *mangled
)
6334 int ret_val
, no_repo
= 0, *save_nesting_level
;
6336 PrivateTop
*pt
= NULL
;
6337 PrivateAffector
*af
= NULL
;
6338 char *fcc_local
= NULL
;
6339 jmp_buf save_jmp_buf
;
6341 dprint((5, "- build_address - (%s)\n", to
? to
: "nul"));
6343 /* check to see if to string is empty to avoid work */
6344 for(p
= to
; p
&& *p
&& isspace((unsigned char)*p
); p
++)
6349 *full_to
= cpystr(to
? to
: ""); /* because pico does a strcmp() */
6355 *full_to
= (char *)NULL
;
6358 *error
= (char *)NULL
;
6360 /* No guarantee cursor or status line is how we saved it */
6362 mark_status_unknown();
6364 if(ps_global
->remote_abook_validity
> 0 &&
6365 adrbk_check_and_fix_all(ab_nesting_level
== 0, 0, 0) && mangled
)
6366 *mangled
|= BUILDER_SCREEN_MANGLED
;
6369 * If we end up jumping back here because somebody else changed one of
6370 * our addrbooks out from underneath us, we may well leak some memory.
6371 * That's probably ok since this will be very rare.
6373 * The reason for the memcpy of the jmp_buf is that we may actually
6374 * be indirectly calling this function from within the address book.
6375 * For example, we may be in the address book screen and then run
6376 * the ComposeTo command which puts us in the composer, then we call
6377 * build_address from there which resets addrbook_changed_unexpectedly.
6378 * Once we leave build_address we need to reset addrbook_changed_un...
6379 * because this position on the stack will no longer be valid.
6380 * Same is true of the other setjmp's in this file which are wrapped
6383 save_nesting_level
= cpyint(ab_nesting_level
);
6384 memcpy(save_jmp_buf
, addrbook_changed_unexpectedly
, sizeof(jmp_buf));
6385 if(setjmp(addrbook_changed_unexpectedly
)){
6391 *error
= (char *)NULL
;
6393 if(full_to
&& *full_to
)
6394 fs_give((void **)full_to
);
6396 q_status_message(SM_ORDER
, 3, 5, "Resetting address book...");
6398 "RESETTING address book... build_address(%s)!\n", to
? to
: "?"));
6400 ab_nesting_level
= *save_nesting_level
;
6406 ret_val
= build_address_internal(bldto
, full_to
, error
,
6407 barg
? &fcc_local
: NULL
,
6408 &no_repo
, NULL
, save_and_restore
,
6411 if(save_nesting_level
)
6412 fs_give((void **)&save_nesting_level
);
6415 * Have to rfc1522_decode the full_to string before sending it back.
6417 if(full_to
&& *full_to
){
6421 len
= 4*strlen(*full_to
)+1;
6422 q
= (char *)fs_get(len
* sizeof(char));
6423 p
= (char *)rfc1522_decode_to_utf8((unsigned char *)q
, len
, *full_to
);
6425 /* p == q means that decoding happened, p is decoded *full_to */
6427 fs_give((void **)full_to
);
6431 fs_give((void **)&q
);
6437 /* Pt will point to headents[Fcc].bldr_private */
6439 if(barg
&& barg
->aff
)
6440 pt
= (PrivateTop
*)(*barg
->aff
);
6443 * If *barg->aff is set, that means fcc was set from a list
6444 * during some previous builder call.
6445 * If the current To line contains the old expansion as a prefix, then
6446 * we should leave things as they are. In order to decide that,
6447 * we look at a hash value computed from the strings.
6449 if(pt
&& (af
=pt
->affector
) && af
->who
== BP_To
){
6453 if(len
>= af
->cksumlen
){
6456 save
= to
[af
->cksumlen
];
6457 to
[af
->cksumlen
] = '\0';
6458 csum
= line_hash(to
);
6459 to
[af
->cksumlen
] = save
;
6462 csum
= af
->cksumval
+ 1; /* something not equal to cksumval */
6467 (pt
->affector
->who
== BP_To
&& csum
!= pt
->affector
->cksumval
)){
6469 /* replace fcc value */
6471 fs_give((void **)&barg
->tptr
);
6473 barg
->tptr
= fcc_local
;
6477 *barg
->aff
= (void *)fs_get(sizeof(PrivateTop
));
6478 pt
= (PrivateTop
*)(*barg
->aff
);
6479 memset((void *)pt
, 0, sizeof(PrivateTop
));
6485 (PrivateAffector
*)fs_get(sizeof(PrivateAffector
));
6489 af
->cksumlen
= strlen(((full_to
&& *full_to
)
6491 af
->cksumval
= line_hash(((full_to
&& *full_to
)
6496 * If result is reproducible, we don't keep track here.
6499 fs_give((void **)&pt
->affector
);
6504 fs_give((void **)&fcc_local
); /* unused in this case */
6507 /* This is so pico will erase the old message */
6508 if(error
!= NULL
&& *error
== NULL
)
6509 *error
= cpystr("");
6511 memcpy(addrbook_changed_unexpectedly
, save_jmp_buf
, sizeof(jmp_buf));
6512 flush_status_messages(1);
6518 * This is the builder used by the composer for the Lcc line.
6520 * Args: lcc -- the passed in Lcc line to parse
6521 * full_lcc -- Address of a pointer to return the full address in.
6522 * This will be allocated here and freed by the caller.
6523 * error -- Address of a pointer to return an error message in.
6524 * This is not allocated so should not be freed by the caller.
6525 * barg -- This is a pointer to text for affected entries which
6526 * we may be changing. The first one in the list is the
6527 * To entry. We may put the name of the list in empty
6528 * group syntax form there (like List Name: ;).
6529 * The second one in the list is the fcc field.
6530 * The tptr members already point to text allocated in the
6531 * caller. We may free and reallocate here, caller will
6532 * free the result in any case.
6534 * Result: 0 is returned if address was OK,
6535 * -1 if address wasn't OK.
6537 * Side effect: Can flush addrbook entry cache entries so they need to be
6538 * re-fetched afterwords.
6541 build_addr_lcc(char *lcc
, char **full_lcc
, char **error
, BUILDER_ARG
*barg
, int *mangled
)
6544 no_repo
= 0; /* fcc or lcc not reproducible */
6545 int *save_nesting_level
;
6547 PrivateTop
*pt
= NULL
;
6548 PrivateAffector
*af
= NULL
;
6553 jmp_buf save_jmp_buf
;
6555 dprint((5, "- build_addr_lcc - (%s)\n", lcc
? lcc
: "nul"));
6557 /* check to see if to string is empty to avoid work */
6558 for(p
= lcc
; p
&& *p
&& isspace((unsigned char)*p
); p
++)
6563 *full_lcc
= cpystr(lcc
? lcc
: ""); /* because pico does a strcmp() */
6569 *error
= (char *)NULL
;
6571 if(ps_global
->remote_abook_validity
> 0 &&
6572 adrbk_check_and_fix_all(ab_nesting_level
== 0, 0, 0) && mangled
)
6573 *mangled
|= BUILDER_SCREEN_MANGLED
;
6576 * If we end up jumping back here because somebody else changed one of
6577 * our addrbooks out from underneath us, we may well leak some memory.
6578 * That's probably ok since this will be very rare.
6580 save_nesting_level
= cpyint(ab_nesting_level
);
6581 memcpy(save_jmp_buf
, addrbook_changed_unexpectedly
, sizeof(jmp_buf));
6582 if(setjmp(addrbook_changed_unexpectedly
)){
6589 *error
= (char *)NULL
;
6591 if(full_lcc
&& *full_lcc
)
6592 fs_give((void **)full_lcc
);
6594 q_status_message(SM_ORDER
, 3, 5, "Resetting address book...");
6596 "RESETTING address book... build_address(%s)!\n", lcc
? lcc
: "?"));
6598 ab_nesting_level
= *save_nesting_level
;
6603 bldlcc
.arg
.str
= lcc
;
6606 * To is first affected_entry and Fcc is second.
6607 * The conditional stuff for the fcc argument says to only change the
6608 * fcc if the fcc pointer is passed in non-null, and the To pointer
6609 * is also non-null. If they are null, that means they've already been
6610 * entered (are sticky). We don't affect fcc if either fcc or To has
6613 ret_val
= build_address_internal(bldlcc
,
6616 (barg
&& barg
->next
&& barg
->next
->tptr
&& barg
->tptr
)
6617 ? &fcc_local
: NULL
,
6619 (barg
&& barg
->tptr
) ? &to
: NULL
,
6620 save_and_restore
, 0, mangled
);
6623 if(save_nesting_level
)
6624 fs_give((void **)&save_nesting_level
);
6626 /* full_lcc is what ends up in the Lcc: line */
6627 if(full_lcc
&& *full_lcc
){
6631 * Have to rfc1522_decode the full_lcc string before sending it back.
6633 len
= 4*strlen(*full_lcc
)+1;
6634 p
= (char *)fs_get(len
* sizeof(char));
6635 if(rfc1522_decode_to_utf8((unsigned char *)p
, len
, *full_lcc
) == (unsigned char *)p
){
6636 fs_give((void **)full_lcc
);
6640 fs_give((void **)&p
);
6643 /* to is what ends up in the To: line */
6649 * Have to rfc1522_decode the full_to string before sending it back.
6651 len
= 4*strlen(to
)+1;
6652 p
= (char *)fs_get(len
* sizeof(char));
6654 if(rfc1522_decode_to_utf8((unsigned char *)p
, len
, to
) == (unsigned char *)p
){
6656 * If the caller wants us to try to preserve the charset
6657 * information (they set aff) we copy it into encoded->etext.
6658 * We don't have to worry about pasting together pieces of
6659 * etext like we do in build_address because whenever the
6660 * Lcc line is setting the To line it will be setting the
6661 * whole line, not modifying it.
6662 * Pt will point to headents[To].bldr_private.
6664 if(barg
&& barg
->aff
){
6665 pt
= (PrivateTop
*)(*barg
->aff
);
6668 *barg
->aff
= (void *)fs_get(sizeof(PrivateTop
));
6669 pt
= (PrivateTop
*)(*barg
->aff
);
6670 memset((void *)pt
, 0, sizeof(PrivateTop
));
6674 fs_give((void **)&to
);
6678 fs_give((void **)&p
);
6681 fs_give((void **)&dummy
);
6685 * This part is recording the fact that the To line was set to
6686 * what it is by entering something on the Lcc line. In particular,
6687 * if a list alias was entered here then the fullname of the list
6688 * goes in the To line. We save this affector information so that
6689 * we can tell it shouldn't be modified if we call build_addr_lcc
6690 * again unless we actually modified what's in the Lcc line so that
6691 * it doesn't start with the same thing. The problem we're solving
6692 * is that the contents of the Lcc line no longer look like the
6693 * list they were derived from.
6694 * Pt will point to headents[To].bldr_private.
6696 if(barg
&& barg
->aff
)
6697 pt
= (PrivateTop
*)(*barg
->aff
);
6699 if(pt
&& (af
=pt
->affector
) && af
->who
== BP_Lcc
){
6703 if(len
>= af
->cksumlen
){
6706 save
= lcc
[af
->cksumlen
];
6707 lcc
[af
->cksumlen
] = '\0';
6708 csum
= line_hash(lcc
);
6709 lcc
[af
->cksumlen
] = save
;
6712 csum
= af
->cksumval
+ 1; /* so they aren't equal */
6717 pt
->affector
->who
!= BP_Lcc
||
6718 (pt
->affector
->who
== BP_Lcc
&& csum
!= pt
->affector
->cksumval
)){
6720 /* replace to value */
6721 if(barg
->tptr
&& barg
->tptr
[0]){
6725 l
= strlen(barg
->tptr
) + strlen(to
? to
: "") + 2;
6726 t
= (char *)fs_get((l
+1) * sizeof(char));
6727 snprintf(t
, l
+1, "%s%s%s",
6729 (to
&& *to
) ? ", " : "",
6730 (to
&& *to
) ? to
: "");
6731 fs_give((void **)&barg
->tptr
);
6733 fs_give((void **)&to
);
6739 fs_give((void **)&barg
->tptr
);
6746 *barg
->aff
= (void *)fs_get(sizeof(PrivateTop
));
6747 pt
= (PrivateTop
*)(*barg
->aff
);
6748 memset((void *)pt
, 0, sizeof(PrivateTop
));
6754 (PrivateAffector
*)fs_get(sizeof(PrivateAffector
));
6758 af
->cksumlen
= strlen(((full_lcc
&& *full_lcc
)
6760 af
->cksumval
= line_hash(((full_lcc
&& *full_lcc
)
6765 * If result is reproducible, we don't keep track here.
6768 fs_give((void **)&pt
->affector
);
6773 fs_give((void **)&to
); /* unused in this case */
6780 * If *barg->next->aff is set, that means fcc was set from a list
6781 * during some previous builder call. If the current Lcc line
6782 * contains the old expansion as a prefix, then we should leave
6783 * things as they are. In order to decide that we look at a hash
6784 * value computed from the strings.
6785 * Pt will point to headents[Fcc].bldr_private
6788 if(barg
&& barg
->next
&& barg
->next
->aff
)
6789 pt
= (PrivateTop
*)(*barg
->next
->aff
);
6791 if(pt
&& (af
=pt
->affector
) && af
->who
== BP_Lcc
){
6795 if(len
>= af
->cksumlen
){
6798 save
= lcc
[af
->cksumlen
];
6799 lcc
[af
->cksumlen
] = '\0';
6800 csum
= line_hash(lcc
);
6801 lcc
[af
->cksumlen
] = save
;
6804 csum
= af
->cksumval
+ 1; /* something not equal to cksumval */
6809 pt
->affector
->who
!= BP_Lcc
||
6810 (pt
->affector
->who
== BP_Lcc
&& csum
!= pt
->affector
->cksumval
)){
6812 /* replace fcc value */
6813 if(barg
->next
->tptr
)
6814 fs_give((void **)&barg
->next
->tptr
);
6816 barg
->next
->tptr
= fcc_local
;
6818 if(barg
->next
->aff
){
6820 *barg
->next
->aff
= (void *)fs_get(sizeof(PrivateTop
));
6821 pt
= (PrivateTop
*)(*barg
->next
->aff
);
6822 memset((void *)pt
, 0, sizeof(PrivateTop
));
6828 (PrivateAffector
*)fs_get(sizeof(PrivateAffector
));
6832 af
->cksumlen
= strlen(((full_lcc
&& *full_lcc
)
6834 af
->cksumval
= line_hash(((full_lcc
&& *full_lcc
)
6839 * If result is reproducible, we don't keep track here.
6842 fs_give((void **)&pt
->affector
);
6847 fs_give((void **)&fcc_local
); /* unused in this case */
6851 if(error
!= NULL
&& *error
== NULL
)
6852 *error
= cpystr("");
6854 memcpy(addrbook_changed_unexpectedly
, save_jmp_buf
, sizeof(jmp_buf));
6855 flush_status_messages(0);
6860 /*----------------------------------------------------------------------
6861 Verify and canonicalize news groups names.
6862 Called from the message composer
6864 Args: given_group -- List of groups typed by user
6865 expanded_group -- pointer to point to expanded list, which will be
6866 allocated here and freed in caller. If this is
6867 NULL, don't attempt to validate.
6868 error -- pointer to store error message
6869 fcc -- pointer to point to fcc, which will be
6870 allocated here and freed in caller
6872 Returns: 0 if all is OK
6873 -1 if addresses weren't valid
6875 Test the given list of newstroups against those recognized by our nntp
6876 servers. Testing by actually trying to open the list is much cheaper, both
6877 in bandwidth and memory, than yanking the whole list across the wire.
6880 news_build(char *given_group
, char **expanded_group
, char **error
, BUILDER_ARG
*fcc
, int *mangled
)
6883 char *fccptr
= NULL
;
6885 if(fcc
&& fcc
->tptr
)
6886 fccptr
= cpystr(fcc
->tptr
);
6890 rv
= news_grouper(given_group
, expanded_group
, error
, &fccptr
, news_build_busy
);
6892 /* assign any new fcc to the BUILDER_ARG */
6896 if(fcc
->tptr
&& strcmp(fcc
->tptr
, fccptr
)){
6897 fs_give((void **) &fcc
->tptr
);
6904 fs_give((void **) &fccptr
);
6907 /* deal with any busy indicator */
6911 mark_status_dirty();
6912 display_message('x');
6914 *mangled
|= BUILDER_MESSAGE_DISPLAYED
;
6923 news_build_busy(void)
6925 news_busy_cue
= busy_cue("Validating newsgroup(s)", NULL
, 0);
6929 #if defined(DOS) || defined(OS2)
6931 /*----------------------------------------------------------------------
6932 Verify that the necessary pieces are around to allow for
6933 message sending under DOS
6935 Args: strict -- tells us if a remote stream is required before
6936 sending is permitted.
6938 The idea is to make sure pine knows enough to put together a valid
6939 from line. The things we MUST know are a user-id, user-domain and
6940 smtp server to dump the message off on. Typically these are
6941 provided in pine's configuration file, but if not, the user is
6947 char prompt
[100], answer
[80];
6952 * query for user name portion of address, use IMAP login
6955 if(!ps_global
->VAR_USER_ID
|| ps_global
->VAR_USER_ID
[0] == '\0'){
6957 int no_prompt_user_id
= 0;
6959 if(ps_global
->mail_stream
&& ps_global
->mail_stream
->mailbox
6960 && mail_valid_net_parse(ps_global
->mail_stream
->mailbox
, &mb
)
6962 strncpy(answer
, mb
.user
, sizeof(answer
)-1);
6963 answer
[sizeof(answer
)-1] = '\0';
6965 else if(F_ON(F_QUELL_USER_ID_PROMPT
, ps_global
)){
6966 /* no user-id prompting if set */
6967 no_prompt_user_id
= 1;
6969 if(!ps_global
->mail_stream
)
6970 do_broach_folder(ps_global
->inbox_name
,
6971 ps_global
->context_list
, NULL
, DB_INBOXWOCNTXT
);
6972 if(ps_global
->mail_stream
&& ps_global
->mail_stream
->mailbox
6973 && mail_valid_net_parse(ps_global
->mail_stream
->mailbox
, &mb
)
6975 strncpy(answer
, mb
.user
, sizeof(answer
)-1);
6976 answer
[sizeof(answer
)-1] = '\0';
6984 if(F_ON(F_QUELL_USER_ID_PROMPT
, ps_global
) && answer
[0]){
6985 /* No prompt, just assume mailbox login is user-id */
6986 no_prompt_user_id
= 1;
6990 snprintf(prompt
,sizeof(prompt
),_("User-id for From address : "));
6991 prompt
[sizeof(prompt
)-1] = '\0';
6994 while(!no_prompt_user_id
) {
6995 flags
= OE_APPEND_CURRENT
;
6996 rc
= optionally_enter(answer
,-FOOTER_ROWS(ps_global
),0,
6997 sizeof(answer
),prompt
,NULL
,help
,&flags
);
7002 help
= (help
== NO_HELP
) ? h_sticky_user_id
: NO_HELP
;
7010 if(rc
== 1 || (rc
== 0 && !answer
[0])) {
7011 q_status_message(SM_ORDER
, 3, 4,
7012 _("Send cancelled (User-id must be provided before sending)"));
7017 snprintf(prompt
, sizeof(prompt
), _("Preserve %.*s as \"user-id\" in PINERC"),
7018 sizeof(prompt
)-50, answer
);
7019 prompt
[sizeof(prompt
)-1] = '\0';
7020 if(ps_global
->blank_user_id
7021 && !no_prompt_user_id
7022 && want_to(prompt
, 'y', 'n', NO_HELP
, WT_NORM
) == 'y'){
7023 set_variable(V_USER_ID
, answer
, 1, 1, Main
);
7026 fs_give((void **)&(ps_global
->VAR_USER_ID
));
7027 ps_global
->VAR_USER_ID
= cpystr(answer
);
7031 /* query for personal name */
7032 if(!ps_global
->VAR_PERSONAL_NAME
|| ps_global
->VAR_PERSONAL_NAME
[0]=='\0'
7033 && F_OFF(F_QUELL_PERSONAL_NAME_PROMPT
, ps_global
)){
7035 snprintf(prompt
, sizeof(prompt
), _("Personal name for From address : "));
7036 prompt
[sizeof(prompt
)-1] = '\0';
7040 flags
= OE_APPEND_CURRENT
;
7041 rc
= optionally_enter(answer
,-FOOTER_ROWS(ps_global
),0,
7042 sizeof(answer
),prompt
,NULL
,help
,&flags
);
7047 help
= (help
== NO_HELP
) ? h_sticky_personal_name
: NO_HELP
;
7055 if(rc
== 0 && answer
){ /* save the name */
7056 snprintf(prompt
, sizeof(prompt
), _("Preserve %.*s as \"personal-name\" in PINERC"),
7057 sizeof(prompt
)-50, answer
);
7058 prompt
[sizeof(prompt
)-1] = '\0';
7059 if(ps_global
->blank_personal_name
7060 && want_to(prompt
, 'y', 'n', NO_HELP
, WT_NORM
) == 'y'){
7061 set_variable(V_PERSONAL_NAME
, answer
, 1, 1, Main
);
7064 fs_give((void **)&(ps_global
->VAR_PERSONAL_NAME
));
7065 ps_global
->VAR_PERSONAL_NAME
= cpystr(answer
);
7071 * query for host/domain portion of address, using IMAP
7074 if(ps_global
->blank_user_domain
7075 || ps_global
->maildomain
== ps_global
->localdomain
7076 || ps_global
->maildomain
== ps_global
->hostname
){
7077 if(ps_global
->inbox_name
[0] == '{'){
7079 i
< sizeof(answer
)-1 && ps_global
->inbox_name
[i
+1] != '}'; i
++)
7080 answer
[i
] = ps_global
->inbox_name
[i
+1];
7087 snprintf(prompt
,sizeof(prompt
),_("Host/domain for From address : "));
7088 prompt
[sizeof(prompt
)-1] = '\0';
7092 flags
= OE_APPEND_CURRENT
;
7093 rc
= optionally_enter(answer
,-FOOTER_ROWS(ps_global
),0,
7094 sizeof(answer
),prompt
,NULL
,help
,&flags
);
7099 help
= (help
== NO_HELP
) ? h_sticky_domain
: NO_HELP
;
7107 if(rc
== 1 || (rc
== 0 && !answer
[0])) {
7108 q_status_message(SM_ORDER
, 3, 4,
7109 _("Send cancelled (Host/domain name must be provided before sending)"));
7114 snprintf(prompt
, sizeof(prompt
), _("Preserve %.*s as \"user-domain\" in PINERC"),
7115 sizeof(prompt
)-50, answer
);
7116 prompt
[sizeof(prompt
)-1] = '\0';
7117 if(!ps_global
->userdomain
&& !ps_global
->blank_user_domain
7118 && want_to(prompt
, 'y', 'n', NO_HELP
, WT_NORM
) == 'y'){
7119 set_variable(V_USER_DOMAIN
, answer
, 1, 1, Main
);
7120 fs_give((void **)&(ps_global
->maildomain
)); /* blast old val */
7121 ps_global
->userdomain
= cpystr(answer
);
7122 ps_global
->maildomain
= ps_global
->userdomain
;
7125 fs_give((void **)&(ps_global
->maildomain
));
7126 ps_global
->userdomain
= cpystr(answer
);
7127 ps_global
->maildomain
= ps_global
->userdomain
;
7131 /* check for smtp server */
7132 if(!ps_global
->VAR_SMTP_SERVER
||
7133 !ps_global
->VAR_SMTP_SERVER
[0] ||
7134 !ps_global
->VAR_SMTP_SERVER
[0][0]){
7137 if(ps_global
->inbox_name
[0] == '{'){
7139 i
< sizeof(answer
)-1 && ps_global
->inbox_name
[i
+1] != '}'; i
++)
7140 answer
[i
] = ps_global
->inbox_name
[i
+1];
7147 snprintf(prompt
,sizeof(prompt
),_("SMTP server to forward message : "));
7148 prompt
[sizeof(prompt
)-1] = '\0';
7152 flags
= OE_APPEND_CURRENT
;
7153 rc
= optionally_enter(answer
,-FOOTER_ROWS(ps_global
),0,
7154 sizeof(answer
),prompt
,NULL
,help
,&flags
);
7159 help
= (help
== NO_HELP
) ? h_sticky_smtp
: NO_HELP
;
7167 if(rc
== 1 || (rc
== 0 && answer
[0] == '\0')) {
7168 q_status_message(SM_ORDER
, 3, 4,
7169 _("Send cancelled (SMTP server must be provided before sending)"));
7174 list
= (char **) fs_get(2 * sizeof(char *));
7175 list
[0] = cpystr(answer
);
7177 set_variable_list(V_SMTP_SERVER
, list
, TRUE
, Main
);
7178 fs_give((void *)&list
[0]);
7179 fs_give((void *)list
);
7185 #endif /* defined(DOS) || defined(OS2) */