1 #if !defined(lint) && !defined(DOS)
2 static char rcsid
[] = "$Id: reply.c 1074 2008-06-04 00:08:43Z hubert@u.washington.edu $";
6 * ========================================================================
7 * Copyright 2006-2008 University of Washington
8 * Copyright 2013-2015 Eduardo Chappa
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
14 * http://www.apache.org/licenses/LICENSE-2.0
16 * ========================================================================
19 /*======================================================================
20 Code here for forward and reply to mail
21 A few support routines as well
23 This code will forward and reply to MIME messages. The Alpine composer
24 at this time will only support non-text segments at the end of a
25 message so, things don't always come out as one would like. If you
26 always forward a message in MIME format, all will be correct. Forwarding
27 of nested MULTIPART messages will work. There's still a problem with
28 MULTIPART/ALTERNATIVE as the "first text part" rule doesn't allow modifying
29 the equivalent parts. Ideally, we should probably such segments as a
30 single attachment when forwarding/replying. It would also be real nice to
31 flatten out the nesting in the composer so pieces inside can get snipped.
33 The evolution continues...
49 #include "../pith/state.h"
50 #include "../pith/conf.h"
51 #include "../pith/init.h"
52 #include "../pith/filter.h"
53 #include "../pith/pattern.h"
54 #include "../pith/charset.h"
55 #include "../pith/mimedesc.h"
56 #include "../pith/remote.h"
57 #include "../pith/news.h"
58 #include "../pith/util.h"
59 #include "../pith/detoken.h"
60 #include "../pith/newmail.h"
61 #include "../pith/readfile.h"
62 #include "../pith/tempfile.h"
63 #include "../pith/busy.h"
64 #include "../pith/ablookup.h"
70 int reply_poster_followup(ENVELOPE
*);
71 int sigedit_exit_for_pico(struct headerentry
*, void (*)(void), int, char **);
72 long new_mail_for_pico(int, int);
73 void cmd_input_for_pico(void);
74 int display_message_for_pico(int);
75 char *checkpoint_dir_for_pico(char *, size_t);
76 void resize_for_pico(void);
77 PCOLORS
*colors_for_pico(void);
78 void free_pcolors(PCOLORS
**);
81 /*----------------------------------------------------------------------
82 Fill in an outgoing message for reply and pass off to send
84 Args: pine_state -- The usual pine structure
86 Result: Reply is formatted and passed off to composer/mailer
90 - put senders address in To field
91 - search to and cc fields to see if we aren't the only recipients
92 - if other than us, ask if we should reply to all.
93 - if answer yes, fill out the To and Cc fields
94 - fill in the fcc argument
95 - fill in the subject field
96 - fill out the body and the attachments
97 - pass off to pine_send()
100 reply(struct pine
*pine_state
, ACTION_S
*role_arg
)
102 ADDRESS
*saved_from
, *saved_to
, *saved_cc
, *saved_resent
;
103 ADDRESS
*us_in_to_and_cc
, *ap
;
104 ENVELOPE
*env
, *outgoing
;
105 BODY
*body
, *orig_body
= NULL
;
107 void *msgtext
= NULL
;
108 char *tmpfix
= NULL
, *prefix
= NULL
, *fcc
= NULL
, *errmsg
= NULL
;
109 long msgno
, j
, totalm
, rflags
, *seq
= NULL
;
110 int i
, include_text
= 0, times
= -1, warned
= 0, rv
= 0,
111 flags
= RSF_QUERY_REPLY_ALL
, reply_raw_body
= 0;
112 int rolemsg
= 0, copytomsg
= 0;
115 REDRAFT_POS_S
*redraft_pos
= NULL
;
116 ACTION_S
*role
= NULL
, *nrole
;
117 #if defined(DOS) && !defined(_WINDOWS)
121 outgoing
= mail_newenvelope();
122 totalm
= mn_total_cur(pine_state
->msgmap
);
123 seq
= (long *)fs_get(((size_t)totalm
+ 1) * sizeof(long));
125 dprint((4,"\n - reply (%s msgs) -\n", comatose(totalm
)));
127 saved_from
= (ADDRESS
*) NULL
;
128 saved_to
= (ADDRESS
*) NULL
;
129 saved_cc
= (ADDRESS
*) NULL
;
130 saved_resent
= (ADDRESS
*) NULL
;
132 us_in_to_and_cc
= (ADDRESS
*) NULL
;
134 outgoing
->subject
= NULL
;
136 memset((void *)&reply
, 0, sizeof(reply
));
138 if(ps_global
->full_header
== 2
139 && F_ON(F_ENABLE_FULL_HDR_AND_TEXT
, ps_global
))
143 * We may have to loop through first to figure out what default
144 * reply-indent-string to offer...
146 if(mn_total_cur(pine_state
->msgmap
) > 1 &&
147 F_ON(F_ENABLE_EDIT_REPLY_INDENT
, pine_state
) &&
148 reply_quote_str_contains_tokens()){
149 for(msgno
= mn_first_cur(pine_state
->msgmap
);
150 msgno
> 0L && !tmpfix
;
151 msgno
= mn_next_cur(pine_state
->msgmap
)){
153 env
= pine_mail_fetchstructure(pine_state
->mail_stream
,
154 mn_m2raw(pine_state
->msgmap
, msgno
),
157 q_status_message1(SM_ORDER
,3,4,
158 _("Error fetching message %s. Can't reply to it."),
163 if(!tmpfix
){ /* look for prefix? */
164 tmpfix
= reply_quote_str(env
);
166 i
= strcmp(tmpfix
, prefix
);
167 fs_give((void **) &tmpfix
);
168 if(i
){ /* don't check back if dissimilar */
169 fs_give((void **) &prefix
);
171 * We free prefix, not tmpfix. We set tmpfix to prefix
172 * so that we won't come check again.
174 tmpfix
= prefix
= cpystr("> ");
179 tmpfix
= NULL
; /* check back later? */
188 * Loop thru the selected messages building the
189 * outgoing envelope's destinations...
191 for(msgno
= mn_first_cur(pine_state
->msgmap
);
193 msgno
= mn_next_cur(pine_state
->msgmap
)){
195 /*--- Grab current envelope ---*/
196 env
= pine_mail_fetchstructure(pine_state
->mail_stream
,
197 seq
[++times
] = mn_m2raw(pine_state
->msgmap
, msgno
),
200 q_status_message1(SM_ORDER
,3,4,
201 _("Error fetching message %s. Can't reply to it."),
207 * We check for the prefix here if we didn't do it in the first
208 * loop above. This is just to save having to go through the loop
209 * twice in the cases where we don't need to.
212 tmpfix
= reply_quote_str(env
);
214 i
= strcmp(tmpfix
, prefix
);
215 fs_give((void **) &tmpfix
);
216 if(i
){ /* don't check back if dissimilar */
217 fs_give((void **) &prefix
);
218 tmpfix
= prefix
= cpystr("> ");
223 tmpfix
= NULL
; /* check back later? */
228 * For consistency, the first question is always "include text?"
230 if(!times
){ /* only first time */
231 char *p
= cpystr(prefix
);
233 if((include_text
=reply_text_query(pine_state
,totalm
,&prefix
)) < 0)
237 if(strcmp(p
, prefix
))
238 tmpfix
= prefix
; /* stop looking */
240 fs_give((void **)&p
);
244 * If we're agg-replying or there's a newsgroup and the user want's
245 * to post to news *and* via email, add relevant addresses to the
246 * outgoing envelope...
248 * The single message case gets us around the aggregate reply
249 * to messages in a mixed mail-news archive where some might
250 * have newsgroups and others not or whatever.
252 if(totalm
> 1L || ((i
= reply_news_test(env
, outgoing
)) & 1)){
254 flags
|= RSF_FORCE_REPLY_TO
;
256 if(!reply_harvest(pine_state
, seq
[times
], NULL
, env
,
257 &saved_from
, &saved_to
, &saved_cc
,
258 &saved_resent
, &flags
))
264 /* collect a list of addresses that are us in to and cc fields */
266 if((ap
=reply_cp_addr(pine_state
, 0L, NULL
,
267 NULL
, us_in_to_and_cc
, NULL
,
268 env
->to
, RCA_ONLY_US
)) != NULL
)
269 reply_append_addr(&us_in_to_and_cc
, ap
);
272 if((ap
=reply_cp_addr(pine_state
, 0L, NULL
,
273 NULL
, us_in_to_and_cc
, NULL
,
274 env
->cc
, RCA_ONLY_US
)) != NULL
)
275 reply_append_addr(&us_in_to_and_cc
, ap
);
277 /*------------ Format the subject line ---------------*/
278 if(outgoing
->subject
){
280 * if reply to more than one message, and all subjects
281 * match, so be it. otherwise set it to something generic...
283 if(!same_subject(outgoing
->subject
,
284 reply_subject(env
->subject
,tmp_20k_buf
,SIZEOF_20KBUF
))){
285 fs_give((void **)&outgoing
->subject
);
286 outgoing
->subject
= cpystr("Re: several messages");
290 outgoing
->subject
= reply_subject(env
->subject
, NULL
, 0);
293 /* fill reply header */
294 reply_seed(pine_state
, outgoing
, env
, saved_from
,
295 saved_to
, saved_cc
, saved_resent
,
296 &fcc
, flags
& RSF_FORCE_REPLY_ALL
, &errmsg
);
299 q_status_message1(SM_ORDER
, 3, 3, "%.200s", errmsg
);
300 display_message(NO_OP_COMMAND
);
303 fs_give((void **)&errmsg
);
306 if(sp_expunge_count(pine_state
->mail_stream
)) /* cur msg expunged */
309 /* Setup possible role */
311 role
= copy_action(role_arg
);
315 if(nonempty_patterns(rflags
, &dummy
)){
316 /* setup default role */
318 j
= mn_first_cur(pine_state
->msgmap
);
321 nrole
= set_role_from_msg(pine_state
, rflags
,
322 mn_m2raw(pine_state
->msgmap
, j
),
324 } while(nrole
&& (!role
|| nrole
== role
)
325 && (j
=mn_next_cur(pine_state
->msgmap
)) > 0L);
327 if(!role
|| nrole
== role
)
332 if(confirm_role(rflags
, &role
))
333 role
= combine_inherited_role(role
);
334 else{ /* cancel reply */
336 cmd_cancelled("Reply");
343 * Reply_seed may call c-client in get_fcc_based_on_to, so env may
344 * no longer be valid. Get it again.
345 * Similarly for set_role_from_message.
347 env
= pine_mail_fetchstructure(pine_state
->mail_stream
, seq
[times
], NULL
);
351 /* override fcc gotten in reply_seed */
353 fs_give((void **) &fcc
);
356 if(F_ON(F_COPY_TO_TO_FROM
, pine_state
) && !(role
&& role
->from
)){
358 * A list of all of our addresses that appear in the To
359 * and cc fields is in us_in_to_and_cc.
360 * If there is exactly one address in that list then
361 * use it for the outgoing From.
363 if(us_in_to_and_cc
&& !us_in_to_and_cc
->next
){
364 PINEFIELD
*custom
, *pf
;
369 * Check to see if this address is different from what
370 * we would have used anyway. If it is, notify the user
371 * with a status message. This is pretty hokey because we're
372 * mimicking how pine_send would set the From address and
373 * there is no coordination between the two.
376 /* in case user has a custom From value */
377 custom
= parse_custom_hdrs(ps_global
->VAR_CUSTOM_HDRS
, UseAsDef
);
379 pf
= (PINEFIELD
*) fs_get(sizeof(*pf
));
380 memset((void *) pf
, 0, sizeof(*pf
));
381 pf
->name
= cpystr("From");
383 if(set_default_hdrval(pf
, custom
) >= UseAsDef
384 && pf
->textbuf
&& pf
->textbuf
[0]){
385 removing_trailing_white_space(pf
->textbuf
);
386 (void)removing_double_quotes(pf
->textbuf
);
387 build_address(pf
->textbuf
, &addr
, NULL
, NULL
, NULL
);
388 rfc822_parse_adrlist(pf
->addr
, addr
, ps_global
->maildomain
);
390 fs_give((void **) &addr
);
394 *pf
->addr
= generate_from();
396 if(*pf
->addr
&& !address_is_same(*pf
->addr
, us_in_to_and_cc
)){
399 role
= (ACTION_S
*) fs_get(sizeof(*role
));
400 memset((void *) role
, 0, sizeof(*role
));
404 role
->from
= us_in_to_and_cc
;
405 us_in_to_and_cc
= NULL
;
408 free_customs(custom
);
414 if(rolemsg
&& copytomsg
)
415 q_status_message1(SM_ORDER
, 3, 4,
416 _("Replying using role \"%s\" and To as From"), role
->nick
);
418 q_status_message1(SM_ORDER
, 3, 4,
419 _("Replying using role \"%s\""), role
->nick
);
421 q_status_message(SM_ORDER
, 3, 4,
422 _("Replying using incoming To as outgoing From"));
426 mail_free_address(&us_in_to_and_cc
);
429 seq
[++times
] = -1L; /* mark end of sequence list */
431 /*========== Other miscelaneous fields ===================*/
432 outgoing
->in_reply_to
= reply_in_reply_to(env
);
433 outgoing
->references
= reply_build_refs(env
);
434 outgoing
->message_id
= generate_message_id();
439 !outgoing
->newsgroups
)
440 q_status_message(SM_ORDER
| SM_DING
, 3, 6,
441 _("Warning: no valid addresses to reply to!"));
444 /*==================== Now fix up the message body ====================*/
447 * create storage object to be used for message text
449 if((msgtext
= (void *)so_get(PicoText
, NULL
, EDIT_ACCESS
)) == NULL
){
450 q_status_message(SM_ORDER
| SM_DING
, 3, 4,
451 _("Error allocating message text"));
455 gf_set_so_writec(&pc
, (STORE_S
*) msgtext
);
457 /*---- Include the original text if requested ----*/
458 if(include_text
&& totalm
> 1L){
460 int impl
, template_len
= 0, leave_cursor_at_top
= 0;
464 if(role
&& role
->template){
468 filtered
= detoken(role
, env
, 0,
469 F_ON(F_SIG_AT_BOTTOM
, ps_global
) ? 1 : 0,
470 0, &redraft_pos
, &impl
);
473 so_puts((STORE_S
*)msgtext
, filtered
);
475 template_len
= strlen(filtered
);
477 leave_cursor_at_top
++;
480 fs_give((void **)&filtered
);
488 if((sig
= reply_signature(role
, env
, &redraft_pos
, &impl
)) &&
489 F_OFF(F_SIG_AT_BOTTOM
, ps_global
)){
492 * If CURSORPOS was set explicitly in sig_file, and there was a
493 * template file before that, we need to adjust the offset by the
494 * length of the template file. However, if the template had
495 * a set CURSORPOS in it then impl was 2 before getting to the
496 * signature, so offset wouldn't have been reset by the signature
497 * CURSORPOS and offset would already be correct. That case will
498 * be ok here because template_len will be 0 and adding it does
499 * nothing. If template
500 * didn't have CURSORPOS in it, then impl was 1 and got set to 2
501 * by the CURSORPOS in the sig. In that case we have to adjust the
502 * offset. That's what the next line does. It adjusts it if
503 * template_len is nonzero and if CURSORPOS was set in sig_file.
506 redraft_pos
->offset
+= template_len
;
509 so_puts((STORE_S
*)msgtext
, sig
);
512 * Set sig to NULL because we've already used it. If SIG_AT_BOTTOM
513 * is set, we won't have used it yet and want it to be non-NULL.
515 fs_give((void **)&sig
);
519 * Only put cursor in sig if there is a cursorpos there but not
520 * one in the template, and sig-at-bottom.
522 if(!(sig
&& impl
== 2 && !leave_cursor_at_top
))
523 leave_cursor_at_top
++;
525 body
= mail_newbody();
526 body
->type
= TYPETEXT
;
527 body
->contents
.text
.data
= msgtext
;
529 for(msgno
= mn_first_cur(pine_state
->msgmap
);
531 msgno
= mn_next_cur(pine_state
->msgmap
)){
533 if(env
){ /* put 2 between messages */
534 gf_puts(NEWLINE
, pc
);
535 gf_puts(NEWLINE
, pc
);
538 /*--- Grab current envelope ---*/
539 env
= pine_mail_fetchstructure(pine_state
->mail_stream
,
540 mn_m2raw(pine_state
->msgmap
, msgno
),
543 q_status_message1(SM_ORDER
,3,4,
544 _("Error fetching message %s. Can't reply to it."),
545 long2string(mn_get_cur(pine_state
->msgmap
)));
549 if(orig_body
== NULL
|| orig_body
->type
== TYPETEXT
|| reply_raw_body
) {
550 reply_delimiter(env
, role
, pc
);
551 if(F_ON(F_INCLUDE_HEADER
, pine_state
))
552 reply_forward_header(pine_state
->mail_stream
,
553 mn_m2raw(pine_state
->msgmap
,msgno
),
554 NULL
, env
, pc
, prefix
);
556 get_body_part_text(pine_state
->mail_stream
, reply_raw_body
? NULL
: orig_body
,
557 mn_m2raw(pine_state
->msgmap
, msgno
),
558 reply_raw_body
? NULL
: "1", 0L, pc
, prefix
,
561 else if(orig_body
->type
== TYPEMULTIPART
) {
563 q_status_message(SM_ORDER
,3,7,
564 _("WARNING! Attachments not included in multiple reply."));
566 if(orig_body
->nested
.part
567 && orig_body
->nested
.part
->body
.type
== TYPETEXT
) {
568 /*---- First part of the message is text -----*/
569 reply_delimiter(env
, role
, pc
);
570 if(F_ON(F_INCLUDE_HEADER
, pine_state
))
571 reply_forward_header(pine_state
->mail_stream
,
572 mn_m2raw(pine_state
->msgmap
,
574 NULL
, env
, pc
, prefix
);
576 get_body_part_text(pine_state
->mail_stream
,
577 &orig_body
->nested
.part
->body
,
578 mn_m2raw(pine_state
->msgmap
, msgno
),
579 "1", 0L, pc
, prefix
, NULL
, GBPT_NONE
);
582 q_status_message(SM_ORDER
,0,3,
583 _("Multipart with no leading text part."));
587 /*---- Single non-text message of some sort ----*/
588 q_status_message(SM_ORDER
,3,3,
589 _("Non-text message not included."));
593 if(!leave_cursor_at_top
){
597 /* rewind and count chars to start of sig file */
598 so_seek((STORE_S
*)msgtext
, 0L, 0);
599 while(so_readc(&c
, (STORE_S
*)msgtext
))
603 redraft_pos
= (REDRAFT_POS_S
*)fs_get(sizeof(*redraft_pos
));
604 memset((void *)redraft_pos
, 0,sizeof(*redraft_pos
));
605 redraft_pos
->hdrname
= cpystr(":");
609 * If explicit cursor positioning in sig file,
610 * add offset to start of sig file plus offset into sig file.
611 * Else, just offset to start of sig file.
613 redraft_pos
->offset
+= cnt
;
618 so_puts((STORE_S
*)msgtext
, sig
);
620 fs_give((void **)&sig
);
624 msgno
= mn_m2raw(pine_state
->msgmap
,
625 mn_get_cur(pine_state
->msgmap
));
627 /*--- Grab current envelope ---*/
628 env
= pine_mail_fetchstructure(pine_state
->mail_stream
, msgno
,
632 * If the charset of the body part is different from ascii and
633 * charset conversion is _not_ happening, then preserve the original
634 * charset from the message so that if we don't enter any new
635 * chars with the hibit set we can use the original charset.
636 * If not all those things, then don't try to preserve it.
641 charset
= parameter_val(orig_body
->parameter
, "charset");
642 if(charset
&& strucmp(charset
, "us-ascii") != 0){
646 * There is a non-ascii charset, is there conversion happening?
648 if(!(ct
=conversion_table(charset
, ps_global
->posting_charmap
)) || !ct
->table
){
649 reply
.orig_charset
= charset
;
655 fs_give((void **) &charset
);
659 if(!(body
= reply_body(pine_state
->mail_stream
, env
, orig_body
,
660 msgno
, NULL
, msgtext
, prefix
,
661 include_text
, role
, 1, &redraft_pos
)))
665 q_status_message1(SM_ORDER
,3,4,
666 _("Error fetching message %s. Can't reply to it."),
667 long2string(mn_get_cur(pine_state
->msgmap
)));
672 /* fill in reply structure */
673 reply
.prefix
= prefix
;
674 reply
.mailbox
= cpystr(pine_state
->mail_stream
->mailbox
);
675 reply
.origmbox
= cpystr(pine_state
->mail_stream
->original_mailbox
676 ? pine_state
->mail_stream
->original_mailbox
677 : pine_state
->mail_stream
->mailbox
);
678 reply
.data
.uid
.msgs
= (imapuid_t
*) fs_get((times
+ 1) * sizeof(imapuid_t
));
679 if((reply
.data
.uid
.validity
= pine_state
->mail_stream
->uid_validity
) != 0){
681 for(i
= 0; i
< times
; i
++)
682 reply
.data
.uid
.msgs
[i
] = mail_uid(pine_state
->mail_stream
, seq
[i
]);
686 for(i
= 0; i
< times
; i
++)
687 reply
.data
.uid
.msgs
[i
] = seq
[i
];
690 reply
.data
.uid
.msgs
[i
] = 0; /* tie off list */
692 #if defined(DOS) && !defined(_WINDOWS)
693 free((void *)reserve
);
696 /* partially formatted outgoing message */
697 pine_send(outgoing
, &body
, _("COMPOSE MESSAGE REPLY"),
698 role
, fcc
, &reply
, redraft_pos
, NULL
, NULL
, 0);
701 pine_free_body(&body
);
703 fs_give((void **) &reply
.mailbox
);
705 fs_give((void **) &reply
.origmbox
);
706 if(reply
.orig_charset
)
707 fs_give((void **) &reply
.orig_charset
);
708 fs_give((void **) &reply
.data
.uid
.msgs
);
710 if((STORE_S
*) msgtext
)
711 gf_clear_so_writec((STORE_S
*) msgtext
);
713 mail_free_envelope(&outgoing
);
714 mail_free_address(&saved_from
);
715 mail_free_address(&saved_to
);
716 mail_free_address(&saved_cc
);
717 mail_free_address(&saved_resent
);
719 fs_give((void **)&seq
);
722 fs_give((void **)&prefix
);
725 fs_give((void **) &fcc
);
727 free_redraft_pos(&redraft_pos
);
734 * Ask user to confirm role choice, or choose another role.
736 * Args role -- A pointer into the pattern_h space at the default
737 * role to use. This can't be a copy, the comparison
738 * relies on it pointing at the actual role.
739 * This arg is also used to return a pointer to the
742 * Returns 1 -- Yes, use role which is now in *role. This may not be
743 * the same as the role passed in and it may even be NULL.
747 confirm_role(long int rflags
, ACTION_S
**role
)
749 ACTION_S
*role_p
= NULL
;
750 ACTION_S
*default_role
= NULL
;
751 char prompt
[80], *prompt_fodder
;
752 int cmd
, done
, ret
= 1;
753 void (*prev_screen
)(struct pine
*) = ps_global
->prev_screen
,
754 (*redraw
)(void) = ps_global
->redrawer
;
760 if(!nonempty_patterns(ROLE_DO_ROLES
, &pstate
) || !role
)
764 * If this is a reply or forward and the role doesn't require confirmation,
765 * then we just return with what was passed in.
767 if(((rflags
& ROLE_REPLY
) &&
768 *role
&& (*role
)->repl_type
== ROLE_REPL_NOCONF
) ||
769 ((rflags
& ROLE_FORWARD
) &&
770 *role
&& (*role
)->forw_type
== ROLE_FORW_NOCONF
) ||
771 ((rflags
& ROLE_COMPOSE
) &&
772 *role
&& (*role
)->comp_type
== ROLE_COMP_NOCONF
) ||
773 (!*role
&& F_OFF(F_ROLE_CONFIRM_DEFAULT
, ps_global
)
774 && !ps_global
->default_role
))
778 * Check that there is at least one role available. This is among all
779 * roles, not just the reply roles or just the forward roles. That's
780 * because we have ^T take us to all the roles, not the category-specific
783 if(!(pat
= last_pattern(&pstate
)))
792 ekey
[2].ch
= ctrl('T');
798 /* check for more than one role available (or no role set) */
799 if(pat
== first_pattern(&pstate
) && *role
) /* no ^T */
804 * Go through the loop just in case default_role doesn't point
805 * to a real current role.
807 if(ps_global
->default_role
){
808 for(pat
= first_pattern(&pstate
);
810 pat
= next_pattern(&pstate
)){
811 if(pat
->action
== ps_global
->default_role
){
812 default_role
= ps_global
->default_role
;
820 /* override default */
822 for(pat
= first_pattern(&pstate
);
824 pat
= next_pattern(&pstate
)){
825 if(pat
->action
== *role
){
832 if(rflags
& ROLE_REPLY
)
833 prompt_fodder
= _("Reply");
834 else if(rflags
& ROLE_FORWARD
)
835 prompt_fodder
= _("Forward");
837 prompt_fodder
= _("Compose");
844 help
= h_role_confirm
;
846 ekey
[0].label
= N_("Yes");
849 ekey
[1].label
= N_("No, use default role");
851 ekey
[1].label
= N_("No, use default settings");
853 ekey
[2].label
= N_("To Select Alternate Role");
855 if(curpat
->patgrp
&& curpat
->patgrp
->nick
)
856 /* TRANSLATORS: This is something like Use role <nickname of role> for Reply? */
857 snprintf(prompt
, sizeof(prompt
), _("Use role \"%s\" for %s? "),
858 short_str(curpat
->patgrp
->nick
, buf
, sizeof(buf
), 50, MidDots
),
861 snprintf(prompt
, sizeof(prompt
),
862 _("Use role \"<a role without a nickname>\" for %s? "),
866 help
= h_norole_confirm
;
867 ekey
[0].name
= "Ret";
868 ekey
[0].label
= prompt_fodder
;
871 ekey
[2].label
= N_("To Select Role");
872 snprintf(prompt
, sizeof(prompt
),
873 _("Press Return to %s using %s role, or ^T to select a role "),
874 prompt_fodder
, default_role
? _("default") : _("no"));
877 prompt
[sizeof(prompt
)-1] = '\0';
879 cmd
= radio_buttons(prompt
, -FOOTER_ROWS(ps_global
), ekey
,
880 'y', 'x', help
, RB_NORM
);
883 case 'y': /* Accept */
885 *role
= curpat
? curpat
->action
: default_role
;
888 case 'x': /* Cancel */
892 case 'n': /* NoRole */
894 *role
= default_role
;
898 if(role_select_screen(ps_global
, &role_p
, 0) >= 0){
900 for(pat
= first_pattern(&pstate
);
902 pat
= next_pattern(&pstate
)){
903 if(pat
->action
== role_p
){
914 ps_global
->mangled_body
= 1;
915 ps_global
->prev_screen
= prev_screen
;
916 ps_global
->redrawer
= redraw
;
926 * reply_to_all_query - Ask user about replying to all recipients
928 * Returns: -1 if cancel, 0 otherwise
929 * by reference: flagp
932 reply_to_all_query(int *flagp
)
941 ekey
[0].label
= N_("Yes");
945 ekey
[1].label
= N_("No");
951 ps_global
->preserve
= F_ON(F_PRESERVE_ORIGINAL_FIELD
, ps_global
);
955 ekey
[2].label
= ps_global
->preserve
? N_("Not Preserve") : N_("Preserve");
956 snprintf(prompt
, sizeof(prompt
), _("Reply to all recipients%s"),
957 ps_global
->preserve
? _(" (preserving fields)? ") : "? ");
959 prompt
[sizeof(prompt
)-1] = '\0';
961 switch(cmd
= radio_buttons(prompt
, -FOOTER_ROWS(ps_global
), ekey
,
962 'n', 'x', h_preserve_field
, RB_NORM
)){
967 case 'y' : /* set reply-all bit */
968 (*flagp
) |= RSF_FORCE_REPLY_ALL
;
971 case 'n' : /* clear reply-all bit */
972 (*flagp
) &= ~RSF_FORCE_REPLY_ALL
;
976 ps_global
->preserve
= !ps_global
->preserve
;
977 goto loop
; /* ugly, but saves me a variable */
986 * reply_using_replyto_query - Ask user about replying with reply-to value
988 * Returns: 'y' if yes
992 reply_using_replyto_query(void)
994 return(want_to("Use \"Reply-To:\" address instead of \"From:\" address",
995 'y', 'x', NO_HELP
,WT_SEQ_SENSITIVE
));
1000 * reply_text_query - Ask user about replying with text...
1002 * Returns: 1 if include the text
1003 * 0 if we're NOT to include the text
1004 * -1 on cancel or error
1007 reply_text_query(struct pine
*ps
, long int many
, char **prefix
)
1009 int ret
, edited
= 0;
1010 static ESCKEY_S rtq_opts
[] = {
1011 {'y', 'y', "Y", N_("Yes")},
1012 {'n', 'n', "N", N_("No")},
1013 {-1, 0, NULL
, NULL
}, /* may be overridden below */
1017 if(F_ON(F_AUTO_INCLUDE_IN_REPLY
, ps
)
1018 && F_OFF(F_ENABLE_EDIT_REPLY_INDENT
, ps
))
1023 /* TRANSLATORS: The final three %s's can probably be safely ignored */
1024 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, _("Include %s original messages in Reply%s%s%s? "),
1026 F_ON(F_ENABLE_EDIT_REPLY_INDENT
, ps
) ? " (using \"" : "",
1027 F_ON(F_ENABLE_EDIT_REPLY_INDENT
, ps
) ? *prefix
: "",
1028 F_ON(F_ENABLE_EDIT_REPLY_INDENT
, ps
) ? "\")" : "");
1030 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, _("Include original message in Reply%s%s%s? "),
1031 F_ON(F_ENABLE_EDIT_REPLY_INDENT
, ps
) ? " (using \"" : "",
1032 F_ON(F_ENABLE_EDIT_REPLY_INDENT
, ps
) ? *prefix
: "",
1033 F_ON(F_ENABLE_EDIT_REPLY_INDENT
, ps
) ? "\")" : "");
1035 if(F_ON(F_ENABLE_EDIT_REPLY_INDENT
, ps
)){
1036 rtq_opts
[2].ch
= ctrl('R');
1037 rtq_opts
[2].rval
= 'r';
1038 rtq_opts
[2].name
= "^R";
1039 rtq_opts
[2].label
= N_("Edit Indent String");
1042 rtq_opts
[2].ch
= -1;
1044 switch(ret
= radio_buttons(tmp_20k_buf
,
1045 ps
->ttyo
->screen_rows
> 4
1046 ? -FOOTER_ROWS(ps_global
) : -1,
1048 (edited
|| F_ON(F_AUTO_INCLUDE_IN_REPLY
, ps
))
1050 'x', NO_HELP
, RB_SEQ_SENSITIVE
)){
1052 cmd_cancelled("Reply");
1056 if(prefix
&& *prefix
){
1062 strncpy(buf
, *prefix
, sizeof(buf
)-1);
1063 buf
[sizeof(buf
)-1] = '\0';
1065 flags
= OE_APPEND_CURRENT
|
1066 OE_KEEP_TRAILING_SPACE
|
1070 switch(optionally_enter(buf
, ps
->ttyo
->screen_rows
> 4
1071 ? -FOOTER_ROWS(ps_global
) : -1,
1072 0, sizeof(buf
), "Reply prefix : ",
1073 NULL
, NO_HELP
, &flags
)){
1074 case 0: /* entry successful, continue */
1075 if(flags
& OE_USER_MODIFIED
){
1076 fs_give((void **)prefix
);
1077 *prefix
= removing_quotes(cpystr(buf
));
1085 cmd_cancelled("Reply");
1094 if(ps_global
->redrawer
!= NULL
)
1095 (*ps_global
->redrawer
)();
1105 q_status_message(SM_ORDER
, 3, 4,
1106 "Programmer botch in reply_text_query()");
1121 q_status_message1(SM_ORDER
, 3, 4,
1122 "Invalid rval \'%s\'", pretty_command(ret
));
1130 * reply_poster_followup - return TRUE if "followup-to" set to "poster"
1132 * NOTE: queues status message indicating such
1135 reply_poster_followup(ENVELOPE
*e
)
1137 if(e
&& e
->followup_to
&& !strucmp(e
->followup_to
, "poster")){
1138 q_status_message(SM_ORDER
, 2, 3,
1139 _("Replying to Poster as specified in \"Followup-To\""));
1148 * reply_news_test - Test given envelope for newsgroup data and copy
1149 * it at the users request
1151 * 0 if error or cancel
1153 * 2 follow-up via news
1157 reply_news_test(ENVELOPE
*env
, ENVELOPE
*outgoing
)
1160 static ESCKEY_S news_opt
[] = { {'f', 'f', "F", N_("Follow-up")},
1161 {'r', 'r', "R", N_("Reply")},
1162 {'b', 'b', "B", N_("Both")},
1163 {-1, 0, NULL
, NULL
} };
1165 if(env
->newsgroups
&& *env
->newsgroups
&& !reply_poster_followup(env
))
1167 * Now that we know a newsgroups field is present,
1168 * ask if the user is posting a follow-up article...
1170 switch(radio_buttons(
1171 _("Follow-up to news group(s), Reply via email to author or Both? "),
1172 -FOOTER_ROWS(ps_global
), news_opt
, 'r', 'x',
1174 case 'r' : /* Reply */
1178 case 'f' : /* Follow-Up via news ONLY! */
1182 case 'b' : /* BOTH */
1186 case 'x' : /* cancel or unknown response */
1188 cmd_cancelled("Reply");
1194 if(env
->followup_to
){
1195 q_status_message(SM_ORDER
, 2, 3,
1196 _("Posting to specified Followup-To groups"));
1197 outgoing
->newsgroups
= cpystr(env
->followup_to
);
1199 else if(!outgoing
->newsgroups
)
1200 outgoing
->newsgroups
= cpystr(env
->newsgroups
);
1207 /*----------------------------------------------------------------------
1208 Acquire the pinerc defined signature file
1209 It is allocated here and freed by the caller.
1211 file -- use this file
1212 prenewlines -- prefix the file contents with this many newlines
1213 postnewlines -- postfix the file contents with this many newlines
1214 is_sig -- this is a signature (not a template)
1217 get_signature_file(char *file
, int prenewlines
, int postnewlines
, int is_sig
)
1219 char *sig
, *tmp_sig
= NULL
, sig_path
[MAXPATH
+1];
1220 int len
, do_the_pipe_thang
= 0;
1221 long sigsize
= 0L, cntdown
;
1224 if(!signature_path(file
, sig_path
, MAXPATH
))
1227 dprint((5, "get_signature(%s)\n", sig_path
));
1229 if(sig_path
[(len
=strlen(sig_path
))-1] == '|'){
1230 if(is_sig
&& F_ON(F_DISABLE_PIPES_IN_SIGS
, ps_global
)){
1231 q_status_message(SM_ORDER
| SM_DING
, 3, 4,
1232 _("Pipes for signatures are administratively disabled"));
1235 else if(!is_sig
&& F_ON(F_DISABLE_PIPES_IN_TEMPLATES
, ps_global
)){
1236 q_status_message(SM_ORDER
| SM_DING
, 3, 4,
1237 _("Pipes for templates are administratively disabled"));
1241 sig_path
[len
-1] = '\0';
1242 removing_trailing_white_space(sig_path
);
1243 do_the_pipe_thang
++;
1246 if(!IS_REMOTE(sig_path
) && ps_global
->VAR_OPER_DIR
&&
1247 !in_dir(ps_global
->VAR_OPER_DIR
, sig_path
)){
1248 q_status_message2(SM_ORDER
| SM_DING
, 3, 4,
1249 /* TRANSLATORS: First arg is the directory name, second is
1250 the file user wants to read but can't. */
1251 _("Can't read file outside %s: %s"),
1252 ps_global
->VAR_OPER_DIR
, file
);
1257 if(IS_REMOTE(sig_path
) || can_access(sig_path
, ACCESS_EXISTS
) == 0){
1258 if(do_the_pipe_thang
){
1259 if(can_access(sig_path
, EXECUTE_ACCESS
) == 0){
1266 if((store
= so_get(CharStar
, NULL
, EDIT_ACCESS
)) != NULL
){
1268 flags
= PIPE_READ
| PIPE_STDERR
| PIPE_NOSHELL
;
1272 if((syspipe
= open_system_pipe(sig_path
, NULL
, NULL
, flags
, 5,
1273 pipe_callback
, pipe_report_error
)) != NULL
){
1277 gf_set_so_writec(&pc
, store
);
1278 gf_set_readc(&gc
, (void *)syspipe
, 0, PipeStar
, READ_FROM_LOCALE
);
1281 if((error
= gf_pipe(gc
, pc
)) != NULL
){
1282 (void)close_system_pipe(&syspipe
, NULL
, pipe_callback
);
1283 gf_clear_so_writec(store
);
1285 q_status_message1(SM_ORDER
| SM_DING
, 3, 4,
1286 _("Can't get file: %s"), error
);
1290 if(close_system_pipe(&syspipe
, NULL
, pipe_callback
)){
1294 q_status_message2(SM_ORDER
, 3, 4,
1295 _("Error running program \"%s\"%s"),
1297 (now
- start
> 4) ? ": timed out" : "");
1300 gf_clear_so_writec(store
);
1302 /* rewind and count chars */
1303 so_seek(store
, 0L, 0);
1304 while(so_readc(&c
, store
) && sigsize
< 100000L)
1307 /* allocate space */
1308 tmp_sig
= fs_get((sigsize
+ 1) * sizeof(char));
1312 /* rewind and copy chars, no prenewlines... */
1313 so_seek(store
, 0L, 0);
1315 while(so_readc(&c
, store
) && cntdown
-- > 0L)
1323 q_status_message1(SM_ORDER
| SM_DING
, 3, 4,
1324 _("Error running program \"%s\""),
1329 q_status_message(SM_ORDER
| SM_DING
, 3, 4,
1330 "Error allocating space for sig or template program");
1333 q_status_message1(SM_ORDER
| SM_DING
, 3, 4,
1334 /* TRANSLATORS: Arg is a program name */
1335 _("Can't execute \"%s\": Permission denied"),
1338 else if((IS_REMOTE(sig_path
) &&
1339 (tmp_sig
= simple_read_remote_file(sig_path
, REMOTE_SIG_SUBTYPE
))) ||
1340 (tmp_sig
= read_file(sig_path
, READ_FROM_LOCALE
)))
1341 sigsize
= strlen(tmp_sig
);
1343 q_status_message2(SM_ORDER
| SM_DING
, 3, 4,
1344 /* TRANSLATORS: First arg is error description, 2nd is
1346 _("Error \"%s\" reading file \"%s\""),
1347 error_description(errno
), sig_path
);
1350 sig
= get_signature_lit(tmp_sig
, prenewlines
, postnewlines
, is_sig
, 0);
1352 fs_give((void **)&tmp_sig
);
1359 /*----------------------------------------------------------------------
1360 Partially set up message to forward and pass off to composer/mailer
1362 Args: pine_state -- The usual pine structure
1364 Result: outgoing envelope and body created and passed off to composer/mailer
1366 Create the outgoing envelope for the mail being forwarded, which is
1367 not much more than filling in the subject, and create the message body
1368 of the outgoing message which requires formatting the header from the
1369 envelope of the original messasge.
1370 ----------------------------------------------------------------------*/
1372 forward(struct pine
*ps
, ACTION_S
*role_arg
)
1375 int ret
, forward_raw_body
= 0, rv
= 0, i
;
1376 long msgno
, j
, totalmsgs
, rflags
;
1377 ENVELOPE
*env
, *outgoing
;
1378 BODY
*orig_body
, *body
= NULL
;
1380 void *msgtext
= NULL
;
1382 int impl
, template_len
= 0;
1384 REDRAFT_POS_S
*redraft_pos
= NULL
;
1385 ACTION_S
*role
= NULL
, *nrole
;
1386 #if defined(DOS) && !defined(_WINDOWS)
1390 dprint((4, "\n - forward -\n"));
1392 memset((void *)&reply
, 0, sizeof(reply
));
1393 outgoing
= mail_newenvelope();
1394 outgoing
->message_id
= generate_message_id();
1396 if(ps_global
->full_header
== 2
1397 && F_ON(F_ENABLE_FULL_HDR_AND_TEXT
, ps_global
))
1398 forward_raw_body
= 1;
1400 if((totalmsgs
= mn_total_cur(ps
->msgmap
)) > 1L){
1401 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, "%s forwarded messages...", comatose(totalmsgs
));
1402 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
1403 outgoing
->subject
= cpystr(tmp_20k_buf
);
1406 /*---------- Get the envelope of message we're forwarding ------*/
1407 msgno
= mn_m2raw(ps
->msgmap
, mn_get_cur(ps
->msgmap
));
1408 if(!((env
= pine_mail_fetchstructure(ps
->mail_stream
, msgno
, NULL
))
1409 && (outgoing
->subject
= forward_subject(env
, 0)))){
1410 q_status_message1(SM_ORDER
,3,4,
1411 _("Error fetching message %s. Can't forward it."),
1412 long2string(msgno
));
1418 * as with all text bound for the composer, build it in
1419 * a storage object of the type it understands...
1421 if((msgtext
= (void *)so_get(PicoText
, NULL
, EDIT_ACCESS
)) == NULL
){
1422 q_status_message(SM_ORDER
| SM_DING
, 3, 4,
1423 _("Error allocating message text"));
1427 ret
= (F_ON(F_FORWARD_AS_ATTACHMENT
, ps_global
))
1430 ? want_to(_("Forward messages as a MIME digest"), 'y', 'x', NO_HELP
, WT_SEQ_SENSITIVE
)
1431 : (ps
->full_header
== 2)
1432 ? want_to(_("Forward message as an attachment"), 'n', 'x', NO_HELP
, WT_SEQ_SENSITIVE
)
1436 cmd_cancelled("Forward");
1437 so_give((STORE_S
**)&msgtext
);
1441 /* Setup possible role */
1443 role
= copy_action(role_arg
);
1446 rflags
= ROLE_FORWARD
;
1447 if(nonempty_patterns(rflags
, &dummy
)){
1448 /* setup default role */
1450 j
= mn_first_cur(ps
->msgmap
);
1453 nrole
= set_role_from_msg(ps
, rflags
,
1454 mn_m2raw(ps
->msgmap
, j
), NULL
);
1455 } while(nrole
&& (!role
|| nrole
== role
)
1456 && (j
=mn_next_cur(ps
->msgmap
)) > 0L);
1458 if(!role
|| nrole
== role
)
1463 if(confirm_role(rflags
, &role
))
1464 role
= combine_inherited_role(role
);
1465 else{ /* cancel reply */
1467 cmd_cancelled("Forward");
1468 so_give((STORE_S
**)&msgtext
);
1475 q_status_message1(SM_ORDER
, 3, 4,
1476 _("Forwarding using role \"%s\""), role
->nick
);
1478 if(role
&& role
->template){
1482 filtered
= detoken(role
, (totalmsgs
== 1L) ? env
: NULL
,
1483 0, 0, 0, &redraft_pos
, &impl
);
1486 so_puts((STORE_S
*)msgtext
, filtered
);
1488 template_len
= strlen(filtered
);
1491 fs_give((void **)&filtered
);
1497 if((sig
= detoken(role
, NULL
, 2, 0, 1, &redraft_pos
, &impl
)) != NULL
){
1499 redraft_pos
->offset
+= template_len
;
1501 so_puts((STORE_S
*)msgtext
, *sig
? sig
: NEWLINE
);
1503 fs_give((void **)&sig
);
1506 so_puts((STORE_S
*)msgtext
, NEWLINE
);
1508 gf_set_so_writec(&pc
, (STORE_S
*)msgtext
);
1510 #if defined(DOS) && !defined(_WINDOWS)
1511 #if defined(LWP) || defined(PCTCP) || defined(PCNFS)
1512 #define IN_RESERVE 8192
1514 #define IN_RESERVE 16384
1516 if((reserve
=(char *)malloc(IN_RESERVE
)) == NULL
){
1517 gf_clear_so_writec((STORE_S
*) msgtext
);
1518 so_give((STORE_S
**)&msgtext
);
1519 q_status_message(SM_ORDER
| SM_DING
, 3, 4,
1520 _("Insufficient memory for message text"));
1526 * If we're forwarding multiple messages *or* the forward-as-mime
1527 * is turned on and the users wants it done that way, package things
1530 if(ret
== 'y'){ /* attach message[s]!!! */
1532 long totalsize
= 0L;
1534 /*---- New Body to start with ----*/
1535 body
= mail_newbody();
1536 body
->type
= TYPEMULTIPART
;
1538 /*---- The TEXT part/body ----*/
1539 body
->nested
.part
= mail_newbody_part();
1540 body
->nested
.part
->body
.type
= TYPETEXT
;
1541 body
->nested
.part
->body
.contents
.text
.data
= msgtext
;
1544 /*---- The MULTIPART/DIGEST part ----*/
1545 body
->nested
.part
->next
= mail_newbody_part();
1546 body
->nested
.part
->next
->body
.type
= TYPEMULTIPART
;
1547 body
->nested
.part
->next
->body
.subtype
= cpystr("Digest");
1548 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, "Digest of %s messages", comatose(totalmsgs
));
1549 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
1550 body
->nested
.part
->next
->body
.description
= cpystr(tmp_20k_buf
);
1551 pp
= &(body
->nested
.part
->next
->body
.nested
.part
);
1554 pp
= &(body
->nested
.part
->next
);
1556 /*---- The Message body subparts ----*/
1557 for(msgno
= mn_first_cur(ps
->msgmap
);
1559 msgno
= mn_next_cur(ps
->msgmap
)){
1561 msgno
= mn_m2raw(ps
->msgmap
, msgno
);
1562 env
= pine_mail_fetchstructure(ps
->mail_stream
, msgno
, NULL
);
1564 if(forward_mime_msg(ps
->mail_stream
,msgno
,NULL
,env
,pp
,msgtext
)){
1565 totalsize
+= (*pp
)->body
.size
.bytes
;
1566 pp
= &((*pp
)->next
);
1573 body
->nested
.part
->next
->body
.size
.bytes
= totalsize
;
1575 else if(totalmsgs
> 1L){
1577 body
= mail_newbody();
1578 body
->type
= TYPETEXT
;
1579 body
->contents
.text
.data
= msgtext
;
1582 for(msgno
= mn_first_cur(ps
->msgmap
);
1584 msgno
= mn_next_cur(ps
->msgmap
)){
1586 if(env
){ /* put 2 between messages */
1587 gf_puts(NEWLINE
, pc
);
1588 gf_puts(NEWLINE
, pc
);
1591 /*--- Grab current envelope ---*/
1592 env
= pine_mail_fetchstructure(ps
->mail_stream
,
1593 mn_m2raw(ps
->msgmap
, msgno
),
1595 if(!env
|| !orig_body
){
1596 q_status_message1(SM_ORDER
,3,4,
1597 _("Error fetching message %s. Can't forward it."),
1598 long2string(msgno
));
1602 if(orig_body
== NULL
|| orig_body
->type
== TYPETEXT
|| forward_raw_body
) {
1603 forward_delimiter(pc
);
1604 reply_forward_header(ps
->mail_stream
,
1605 mn_m2raw(ps
->msgmap
, msgno
),
1608 if(!get_body_part_text(ps
->mail_stream
, forward_raw_body
? NULL
: orig_body
,
1609 mn_m2raw(ps
->msgmap
, msgno
),
1610 forward_raw_body
? NULL
: "1", 0L, pc
,
1611 NULL
, NULL
, GBPT_NONE
))
1613 } else if(orig_body
->type
== TYPEMULTIPART
) {
1615 q_status_message(SM_ORDER
,3,7,
1616 _("WARNING! Attachments not included in multiple forward."));
1618 if(orig_body
->nested
.part
&&
1619 orig_body
->nested
.part
->body
.type
== TYPETEXT
) {
1620 /*---- First part of the message is text -----*/
1621 forward_delimiter(pc
);
1622 reply_forward_header(ps
->mail_stream
,
1623 mn_m2raw(ps
->msgmap
,msgno
),
1626 if(!get_body_part_text(ps
->mail_stream
,
1627 &orig_body
->nested
.part
->body
,
1628 mn_m2raw(ps
->msgmap
, msgno
),
1630 NULL
, NULL
, GBPT_NONE
))
1633 q_status_message(SM_ORDER
,0,3,
1634 _("Multipart with no leading text part!"));
1637 /*---- Single non-text message of some sort ----*/
1638 q_status_message(SM_ORDER
,0,3,
1639 _("Non-text message not included!"));
1643 else if(!((env
= pine_mail_fetchstructure(ps
->mail_stream
, msgno
,
1645 && (body
= forward_body(ps
->mail_stream
, env
, orig_body
, msgno
,
1648 q_status_message1(SM_ORDER
,3,4,
1649 _("Error fetching message %s. Can't forward it."),
1650 long2string(msgno
));
1654 if(ret
!= 'y' && totalmsgs
== 1L && orig_body
){
1657 charset
= parameter_val(orig_body
->parameter
, "charset");
1658 if(charset
&& strucmp(charset
, "us-ascii") != 0){
1662 * There is a non-ascii charset, is there conversion happening?
1664 if(!(ct
=conversion_table(charset
, ps_global
->posting_charmap
)) || !ct
->table
){
1665 reply
.orig_charset
= charset
;
1671 fs_give((void **) &charset
);
1674 * I don't think orig_charset is ever used except possibly
1675 * right here. Hubert 2008-01-15.
1677 if(reply
.orig_charset
)
1681 /* fill in reply structure */
1682 reply
.forwarded
= 1;
1683 reply
.mailbox
= cpystr(ps
->mail_stream
->mailbox
);
1684 reply
.origmbox
= cpystr(ps
->mail_stream
->original_mailbox
1685 ? ps
->mail_stream
->original_mailbox
1686 : ps
->mail_stream
->mailbox
);
1687 reply
.data
.uid
.msgs
= (imapuid_t
*) fs_get((totalmsgs
+ 1) * sizeof(imapuid_t
));
1688 if((reply
.data
.uid
.validity
= ps
->mail_stream
->uid_validity
) != 0){
1690 for(msgno
= mn_first_cur(ps
->msgmap
), i
= 0;
1692 msgno
= mn_next_cur(ps
->msgmap
), i
++)
1693 reply
.data
.uid
.msgs
[i
] = mail_uid(ps
->mail_stream
, mn_m2raw(ps
->msgmap
, msgno
));
1697 for(msgno
= mn_first_cur(ps
->msgmap
), i
= 0;
1699 msgno
= mn_next_cur(ps
->msgmap
), i
++)
1700 reply
.data
.uid
.msgs
[i
] = mn_m2raw(ps
->msgmap
, msgno
);
1703 reply
.data
.uid
.msgs
[i
] = 0; /* tie off list */
1705 #if defined(DOS) && !defined(_WINDOWS)
1706 free((void *)reserve
);
1708 pine_send(outgoing
, &body
, "FORWARD MESSAGE",
1709 role
, NULL
, &reply
, redraft_pos
,
1715 pine_free_body(&body
);
1717 if((STORE_S
*) msgtext
)
1718 gf_clear_so_writec((STORE_S
*) msgtext
);
1720 mail_free_envelope(&outgoing
);
1721 free_redraft_pos(&redraft_pos
);
1724 if(reply
.orig_charset
)
1725 fs_give((void **)&reply
.orig_charset
);
1730 q_status_message(SM_ORDER
| SM_DING
, 4, 5,
1731 _("Error fetching message contents. Can't forward message."));
1736 /*----------------------------------------------------------------------
1737 Partially set up message to forward and pass off to composer/mailer
1739 Args: pine_state -- The usual pine structure
1740 message -- The MESSAGECACHE of entry to reply to
1742 Result: outgoing envelope and body created and passed off to composer/mailer
1744 Create the outgoing envelope for the mail being forwarded, which is
1745 not much more than filling in the subject, and create the message body
1746 of the outgoing message which requires formatting the header from the
1747 envelope of the original messasge.
1748 ----------------------------------------------------------------------*/
1750 forward_text(struct pine
*pine_state
, void *text
, SourceType source
)
1756 char *enc_error
, *sig
;
1757 ACTION_S
*role
= NULL
;
1759 long rflags
= ROLE_COMPOSE
;
1761 if((msgtext
= so_get(PicoText
, NULL
, EDIT_ACCESS
)) != NULL
){
1762 env
= mail_newenvelope();
1763 env
->message_id
= generate_message_id();
1764 body
= mail_newbody();
1765 body
->type
= TYPETEXT
;
1766 body
->contents
.text
.data
= (void *) msgtext
;
1768 if(nonempty_patterns(rflags
, &dummy
)){
1770 * This is really more like Compose, even though it
1771 * is called Forward.
1773 if(confirm_role(rflags
, &role
))
1774 role
= combine_inherited_role(role
);
1776 cmd_cancelled("Composition");
1777 display_message('x');
1778 mail_free_envelope(&env
);
1779 pine_free_body(&body
);
1785 q_status_message1(SM_ORDER
, 3, 4, _("Composing using role \"%s\""),
1788 sig
= detoken(role
, NULL
, 2, 0, 1, NULL
, NULL
);
1789 so_puts(msgtext
, (sig
&& *sig
) ? sig
: NEWLINE
);
1790 so_puts(msgtext
, NEWLINE
);
1791 so_puts(msgtext
, "----- Included text -----");
1792 so_puts(msgtext
, NEWLINE
);
1794 fs_give((void **)&sig
);
1797 gf_set_so_writec(&pc
, msgtext
);
1798 gf_set_readc(&gc
,text
,(source
== CharStar
) ? strlen((char *)text
) : 0L,
1801 if((enc_error
= gf_pipe(gc
, pc
)) == NULL
){
1802 pine_send(env
, &body
, "SEND MESSAGE", role
, NULL
, NULL
, NULL
,
1804 pine_state
->mangled_screen
= 1;
1807 q_status_message1(SM_ORDER
| SM_DING
, 3, 5,
1808 _("Error reading text \"%s\""),enc_error
);
1809 display_message('x');
1812 gf_clear_so_writec(msgtext
);
1813 mail_free_envelope(&env
);
1814 pine_free_body(&body
);
1817 q_status_message(SM_ORDER
| SM_DING
, 3, 4,
1818 _("Error allocating message text"));
1819 display_message('x');
1826 /*----------------------------------------------------------------------
1827 Partially set up message to resend and pass off to mailer
1829 Args: pine_state -- The usual pine structure
1831 Result: outgoing envelope and body created and passed off to mailer
1833 Create the outgoing envelope for the mail being resent, which is
1834 not much more than filling in the subject, and create the message body
1835 of the outgoing message which requires formatting the header from the
1836 envelope of the original messasge.
1837 ----------------------------------------------------------------------*/
1839 bounce(struct pine
*pine_state
, ACTION_S
*role
)
1843 char *save_to
= NULL
, **save_toptr
= NULL
, *errstr
= NULL
,
1844 *prmpt_who
= NULL
, *prmpt_cnf
= NULL
;
1846 dprint((4, "\n - bounce -\n"));
1848 if(mn_total_cur(pine_state
->msgmap
) > 1L){
1849 save_toptr
= &save_to
;
1851 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, _("BOUNCE (redirect) %ld messages (using role %s) to : "),
1852 mn_total_cur(pine_state
->msgmap
), role
->nick
);
1854 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, _("BOUNCE (redirect) %ld messages to : "),
1855 mn_total_cur(pine_state
->msgmap
));
1856 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
1857 prmpt_who
= cpystr(tmp_20k_buf
);
1858 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, _("Send %ld messages "),
1859 mn_total_cur(pine_state
->msgmap
));
1860 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
1861 prmpt_cnf
= cpystr(tmp_20k_buf
);
1864 for(msgno
= mn_first_cur(pine_state
->msgmap
);
1866 msgno
= mn_next_cur(pine_state
->msgmap
)){
1868 rawno
= mn_m2raw(pine_state
->msgmap
, msgno
);
1869 if((env
= pine_mail_fetchstructure(pine_state
->mail_stream
, rawno
, NULL
)) != NULL
)
1870 errstr
= bounce_msg(pine_state
->mail_stream
, rawno
, NULL
, role
,
1871 save_toptr
, env
->subject
, prmpt_who
, prmpt_cnf
);
1873 errstr
= _("Can't fetch Subject for Bounce");
1878 q_status_message(SM_ORDER
| SM_DING
, 4, 7, errstr
);
1885 fs_give((void **)&save_to
);
1888 fs_give((void **) &prmpt_who
);
1891 fs_give((void **) &prmpt_cnf
);
1893 return(errstr
? 0 : 1);
1899 bounce_msg(MAILSTREAM
*stream
,
1908 char *errstr
= NULL
;
1914 if((errstr
= bounce_msg_body(stream
, rawno
, part
, to
, subject
, &outgoing
, &body
, &was_seen
)) == NULL
){
1915 if(pine_simple_send(outgoing
, &body
, role
, pmt_who
, pmt_cnf
, to
,
1916 !(to
&& *to
) ? SS_PROMPTFORTO
: 0) < 0){
1917 errstr
= ""; /* p_s_s() better have explained! */
1918 /* clear seen flag */
1919 if(was_seen
== 0 && rawno
> 0L
1920 && stream
&& rawno
<= stream
->nmsgs
1921 && (mc
= mail_elt(stream
, rawno
)) && mc
->seen
)
1922 mail_flag(stream
, long2string(rawno
), "\\SEEN", 0);
1926 /* Just for good measure... */
1927 mail_free_envelope(&outgoing
);
1928 pine_free_body(&body
);
1930 return(errstr
); /* no problem-o */
1934 /*----------------------------------------------------------------------
1935 Serve up the current signature within pico for editing
1939 Result: signature changed or not.
1942 signature_edit(char *sigfile
, char *title
)
1945 char sig_path
[MAXPATH
+1], errbuf
[2000], *errstr
= NULL
;
1947 STORE_S
*msgso
, *tmpso
= NULL
;
1950 struct variable
*vars
= ps_global
->vars
;
1951 REMDATA_S
*rd
= NULL
;
1953 if(!signature_path(sigfile
, sig_path
, MAXPATH
))
1954 return(cpystr(_("No signature file defined.")));
1956 if(IS_REMOTE(sigfile
)){
1957 rd
= rd_create_remote(RemImap
, sig_path
, REMOTE_SIG_SUBTYPE
,
1959 _("Can't access remote configuration."));
1961 return(cpystr(_("Error attempting to edit remote configuration")));
1963 (void)rd_read_metadata(rd
);
1965 if(rd
->access
== MaybeRorW
){
1966 if(rd
->read_status
== 'R')
1967 rd
->access
= ReadOnly
;
1969 rd
->access
= ReadWrite
;
1972 if(rd
->access
!= NoExists
){
1974 rd_check_remvalid(rd
, 1L);
1977 * If the cached info says it is readonly but
1978 * it looks like it's been fixed now, change it to readwrite.
1980 if(rd
->read_status
== 'R'){
1981 rd_check_readonly_access(rd
);
1982 if(rd
->read_status
== 'W'){
1983 rd
->access
= ReadWrite
;
1984 rd
->flags
|= REM_OUTOFDATE
;
1987 rd
->access
= ReadOnly
;
1991 if(rd
->flags
& REM_OUTOFDATE
){
1992 if(rd_update_local(rd
) != 0){
1995 "signature_edit: rd_update_local failed\n"));
1996 rd_close_remdata(&rd
);
1997 return(cpystr(_("Can't access remote sig")));
2003 if(rd
->access
!= ReadWrite
|| rd_remote_is_readonly(rd
)){
2004 rd_close_remdata(&rd
);
2005 return(cpystr(_("Can't get write permission for remote sig")));
2008 rd
->flags
|= DO_REMTRIM
;
2010 strncpy(sig_path
, rd
->lf
, sizeof(sig_path
)-1);
2011 sig_path
[sizeof(sig_path
)-1] = '\0';
2014 standard_picobuf_setup(&pbf
);
2015 pbf
.tty_fix
= PineRaw
;
2016 pbf
.composer_help
= h_composer_sigedit
;
2017 pbf
.exittest
= sigedit_exit_for_pico
;
2018 pbf
.upload
= (VAR_UPLOAD_CMD
&& VAR_UPLOAD_CMD
[0])
2019 ? upload_msg_to_pico
: NULL
;
2020 pbf
.alt_ed
= (VAR_EDITOR
&& VAR_EDITOR
[0] && VAR_EDITOR
[0][0])
2021 ? VAR_EDITOR
: NULL
;
2022 pbf
.alt_spell
= (VAR_SPELLER
&& VAR_SPELLER
[0]) ? VAR_SPELLER
: NULL
;
2023 pbf
.always_spell_check
= F_ON(F_ALWAYS_SPELL_CHECK
, ps_global
);
2024 pbf
.strip_ws_before_send
= F_ON(F_STRIP_WS_BEFORE_SEND
, ps_global
);
2025 pbf
.allow_flowed_text
= 0;
2027 pbf
.pine_anchor
= set_titlebar(title
,
2028 ps_global
->mail_stream
,
2029 ps_global
->context_current
,
2030 ps_global
->cur_folder
,
2032 0, FolderName
, 0, 0, NULL
);
2034 /* NOTE: at this point, alot of pico struct fields are null'd out
2035 * thanks to the leading memset; in particular "headents" which tells
2036 * pico to behave like a normal editor (though modified slightly to
2037 * let the caller dictate the file to edit and such)...
2040 if(VAR_OPER_DIR
&& !in_dir(VAR_OPER_DIR
, sig_path
)){
2043 l
= strlen(VAR_OPER_DIR
) + 100;
2044 ret
= (char *) fs_get((l
+1) * sizeof(char));
2045 snprintf(ret
, l
+1, _("Can't edit file outside of %s"), VAR_OPER_DIR
);
2051 * Now alloc and init the text to pass pico
2053 if(!(msgso
= so_get(PicoText
, NULL
, EDIT_ACCESS
))){
2054 ret
= cpystr(_("Error allocating space for file"));
2055 dprint((1, "Can't alloc space for signature_edit"));
2059 pbf
.msgtext
= so_text(msgso
);
2061 if(can_access(sig_path
, READ_ACCESS
) == 0
2062 && !(tmpso
= so_get(FileStar
, sig_path
, READ_ACCESS
|READ_FROM_LOCALE
))){
2063 char *problem
= error_description(errno
);
2065 snprintf(errbuf
, sizeof(errbuf
), _("Error editing \"%s\": %s"),
2066 sig_path
, problem
? problem
: "<NULL>");
2067 errbuf
[sizeof(errbuf
)-1] = '\0';
2068 ret
= cpystr(errbuf
);
2070 dprint((1, "signature_edit: can't open %s: %s", sig_path
,
2071 problem
? problem
: "<NULL>"));
2074 else if(tmpso
){ /* else, fill pico's edit buffer */
2075 gf_set_so_readc(&gc
, tmpso
); /* read from file, write pico buf */
2076 gf_set_so_writec(&pc
, msgso
);
2077 gf_filter_init(); /* no filters needed */
2078 if((errstr
= gf_pipe(gc
, pc
)) != NULL
){
2079 snprintf(errbuf
, sizeof(errbuf
), _("Error reading file: \"%s\""), errstr
);
2080 errbuf
[sizeof(errbuf
)-1] = '\0';
2081 ret
= cpystr(errbuf
);
2084 gf_clear_so_readc(tmpso
);
2085 gf_clear_so_writec(msgso
);
2091 mswin_setwindowmenu (MENU_COMPOSER
);
2094 /*------ OK, Go edit the signature ------*/
2095 editor_result
= pico(&pbf
);
2098 mswin_setwindowmenu (MENU_DEFAULT
);
2100 if(editor_result
& COMP_GOTHUP
){
2101 hup_signal(); /* do what's normal for a hup */
2104 fix_windsize(ps_global
);
2108 if(editor_result
& (COMP_SUSPEND
| COMP_GOTHUP
| COMP_CANCEL
)){
2111 /*------ Must have an edited buffer, write it to .sig -----*/
2112 our_unlink(sig_path
); /* blast old copy */
2113 if((tmpso
= so_get(FileStar
, sig_path
, WRITE_ACCESS
|WRITE_TO_LOCALE
)) != NULL
){
2114 so_seek(msgso
, 0L, 0);
2115 gf_set_so_readc(&gc
, msgso
); /* read from pico buf */
2116 gf_set_so_writec(&pc
, tmpso
); /* write sig file */
2117 gf_filter_init(); /* no filters needed */
2118 if((errstr
= gf_pipe(gc
, pc
)) != NULL
){
2119 snprintf(errbuf
, sizeof(errbuf
), _("Error writing file: \"%s\""),
2121 errbuf
[sizeof(errbuf
)-1] = '\0';
2122 ret
= cpystr(errbuf
);
2125 gf_clear_so_readc(msgso
);
2126 gf_clear_so_writec(tmpso
);
2127 if(so_give(&tmpso
)){
2128 errstr
= error_description(errno
);
2129 snprintf(errbuf
, sizeof(errbuf
), _("Error writing file: \"%s\""),
2131 errbuf
[sizeof(errbuf
)-1] = '\0';
2132 ret
= cpystr(errbuf
);
2135 if(IS_REMOTE(sigfile
)){
2141 we_cancel
= busy_cue("Copying to remote sig", NULL
, 1);
2142 if((e
= rd_update_remote(rd
, datebuf
)) != 0){
2144 q_status_message2(SM_ORDER
| SM_DING
, 3, 5,
2145 _("Error opening temporary sig file %s: %s"),
2146 rd
->lf
, error_description(errno
));
2148 "write_remote_sig: error opening temp file %s\n",
2149 rd
->lf
? rd
->lf
: "?"));
2152 q_status_message2(SM_ORDER
| SM_DING
, 3, 5,
2153 _("Error copying to %s: %s"),
2154 rd
->rn
, error_description(errno
));
2156 "write_remote_sig: error copying from %s to %s\n",
2157 rd
->lf
? rd
->lf
: "?", rd
->rn
? rd
->rn
: "?"));
2160 q_status_message(SM_ORDER
| SM_DING
, 5, 5,
2161 _("Copy of sig to remote folder failed, changes NOT saved remotely"));
2164 rd_update_metadata(rd
, datebuf
);
2165 rd
->read_status
= 'W';
2168 rd_close_remdata(&rd
);
2171 cancel_busy_cue(-1);
2175 snprintf(errbuf
, sizeof(errbuf
), _("Error writing \"%s\""), sig_path
);
2176 errbuf
[sizeof(errbuf
)-1] = '\0';
2177 ret
= cpystr(errbuf
);
2178 dprint((1, "signature_edit: can't write %s",
2184 standard_picobuf_teardown(&pbf
);
2190 /*----------------------------------------------------------------------
2191 Serve up the current signature within pico for editing
2193 Args: literal signature to edit
2195 Result: raw edited signature is returned in result arg
2198 signature_edit_lit(char *litsig
, char **result
, char *title
, HelpType composer_help
)
2201 char *errstr
= NULL
;
2205 struct variable
*vars
= ps_global
->vars
;
2207 standard_picobuf_setup(&pbf
);
2208 pbf
.tty_fix
= PineRaw
;
2209 pbf
.search_help
= h_sigedit_search
;
2210 pbf
.composer_help
= composer_help
;
2211 pbf
.exittest
= sigedit_exit_for_pico
;
2212 pbf
.upload
= (VAR_UPLOAD_CMD
&& VAR_UPLOAD_CMD
[0])
2213 ? upload_msg_to_pico
: NULL
;
2214 pbf
.alt_ed
= (VAR_EDITOR
&& VAR_EDITOR
[0] && VAR_EDITOR
[0][0])
2215 ? VAR_EDITOR
: NULL
;
2216 pbf
.alt_spell
= (VAR_SPELLER
&& VAR_SPELLER
[0]) ? VAR_SPELLER
: NULL
;
2217 pbf
.always_spell_check
= F_ON(F_ALWAYS_SPELL_CHECK
, ps_global
);
2218 pbf
.strip_ws_before_send
= F_ON(F_STRIP_WS_BEFORE_SEND
, ps_global
);
2219 pbf
.allow_flowed_text
= 0;
2221 pbf
.pine_anchor
= set_titlebar(title
,
2222 ps_global
->mail_stream
,
2223 ps_global
->context_current
,
2224 ps_global
->cur_folder
,
2226 0, FolderName
, 0, 0, NULL
);
2228 /* NOTE: at this point, alot of pico struct fields are null'd out
2229 * thanks to the leading memset; in particular "headents" which tells
2230 * pico to behave like a normal editor (though modified slightly to
2231 * let the caller dictate the file to edit and such)...
2235 * Now alloc and init the text to pass pico
2237 if(!(msgso
= so_get(PicoText
, NULL
, EDIT_ACCESS
))){
2238 ret
= cpystr(_("Error allocating space"));
2239 dprint((1, "Can't alloc space for signature_edit_lit"));
2243 pbf
.msgtext
= so_text(msgso
);
2245 so_puts(msgso
, litsig
? litsig
: "");
2250 mswin_setwindowmenu (MENU_COMPOSER
);
2253 /*------ OK, Go edit the signature ------*/
2254 editor_result
= pico(&pbf
);
2257 mswin_setwindowmenu (MENU_DEFAULT
);
2259 if(editor_result
& COMP_GOTHUP
){
2260 hup_signal(); /* do what's normal for a hup */
2263 fix_windsize(ps_global
);
2267 if(editor_result
& (COMP_SUSPEND
| COMP_GOTHUP
| COMP_CANCEL
)){
2268 ret
= cpystr(_("Edit Cancelled"));
2271 /*------ Must have an edited buffer, write it to .sig -----*/
2276 so_seek(msgso
, 0L, 0);
2277 while(so_readc(&c
, msgso
))
2280 *result
= (char *)fs_get((cnt
+1) * sizeof(char));
2282 so_seek(msgso
, 0L, 0);
2283 while(so_readc(&c
, msgso
))
2290 standard_picobuf_teardown(&pbf
);
2297 * Returns 0 for Save Changes and exit
2299 * -1 exit but Dont Save Changes
2302 sigedit_exit_for_pico(struct headerentry
*he
, void (*redraw_pico
)(void), int allow_flowed
,
2307 void (*redraw
)(void) = ps_global
->redrawer
;
2308 static ESCKEY_S opts
[] = {
2309 {'s', 's', "S", N_("Save changes")},
2310 {'d', 'd', "D", N_("Don't save changes")},
2314 ps_global
->redrawer
= redraw_pico
;
2315 fix_windsize(ps_global
);
2318 rv
= radio_buttons(_("Exit editor? "),
2319 -FOOTER_ROWS(ps_global
), opts
,
2320 's', 'x', h_exit_editor
, RB_NORM
);
2321 if(rv
== 's'){ /* user ACCEPTS! */
2324 else if(rv
== 'd'){ /* Declined! */
2325 rstr
= _("No Changes Saved");
2328 else if(rv
== 'x'){ /* Cancelled! */
2329 rstr
= _("Exit Cancelled");
2337 ps_global
->redrawer
= redraw
;
2338 return((rv
== 's') ? 0 : (rv
== 'd') ? -1 : 1);
2343 * Common stuff we almost always want to set when calling pico.
2346 standard_picobuf_setup(PICO
*pbf
)
2348 memset(pbf
, 0, sizeof(*pbf
));
2350 pbf
->pine_version
= ALPINE_VERSION
;
2351 pbf
->fillcolumn
= ps_global
->composer_fillcol
;
2352 pbf
->menu_rows
= FOOTER_ROWS(ps_global
) - 1;
2353 pbf
->colors
= colors_for_pico();
2354 pbf
->wordseps
= user_wordseps(ps_global
->VAR_WORDSEPS
);
2355 pbf
->helper
= helper
;
2356 pbf
->showmsg
= display_message_for_pico
;
2357 pbf
->suspend
= do_suspend
;
2358 pbf
->keybinput
= cmd_input_for_pico
;
2359 pbf
->tty_fix
= ttyfix
; /* watch out for this one */
2360 pbf
->newmail
= new_mail_for_pico
;
2361 pbf
->ckptdir
= checkpoint_dir_for_pico
;
2362 pbf
->resize
= resize_for_pico
;
2363 pbf
->input_cs
= ps_global
->input_cs
;
2364 pbf
->winch_cleanup
= winch_cleanup
;
2365 pbf
->search_help
= h_composer_search
;
2366 pbf
->ins_help
= h_composer_ins
;
2367 pbf
->ins_m_help
= h_composer_ins_m
;
2368 pbf
->composer_help
= h_composer
;
2369 pbf
->browse_help
= h_composer_browse
;
2370 pbf
->attach_help
= h_composer_ctrl_j
;
2373 ( (F_ON(F_CAN_SUSPEND
,ps_global
) ? P_SUSPEND
: 0L)
2374 | (F_ON(F_USE_FK
,ps_global
) ? P_FKEYS
: 0L)
2375 | (ps_global
->restricted
? P_SECURE
: 0L)
2376 | (F_ON(F_ALT_ED_NOW
,ps_global
) ? P_ALTNOW
: 0L)
2377 | (F_ON(F_USE_CURRENT_DIR
,ps_global
) ? P_CURDIR
: 0L)
2378 | (F_ON(F_SUSPEND_SPAWNS
,ps_global
) ? P_SUBSHELL
: 0L)
2379 | (F_ON(F_COMPOSE_MAPS_DEL
,ps_global
) ? P_DELRUBS
: 0L)
2380 | (F_ON(F_ENABLE_TAB_COMPLETE
,ps_global
) ? P_COMPLETE
: 0L)
2381 | (F_ON(F_SHOW_CURSOR
,ps_global
) ? P_SHOCUR
: 0L)
2382 | (F_ON(F_DEL_FROM_DOT
,ps_global
) ? P_DOTKILL
: 0L)
2383 | (F_ON(F_ENABLE_DOT_FILES
,ps_global
) ? P_DOTFILES
: 0L)
2384 | (F_ON(F_ALLOW_GOTO
,ps_global
) ? P_ALLOW_GOTO
: 0L)
2385 | (F_ON(F_ENABLE_SEARCH_AND_REPL
,ps_global
) ? P_REPLACE
: 0L)
2386 | (!ps_global
->pass_ctrl_chars
2387 && !ps_global
->pass_c1_ctrl_chars
? P_HICTRL
: 0L)
2388 | ((F_ON(F_ENABLE_ALT_ED
,ps_global
)
2389 || F_ON(F_ALT_ED_NOW
,ps_global
)
2390 || (ps_global
->VAR_EDITOR
2391 && ps_global
->VAR_EDITOR
[0]
2392 && ps_global
->VAR_EDITOR
[0][0]))
2394 | ((!ps_global
->keyboard_charmap
2395 || !strucmp(ps_global
->keyboard_charmap
, "US-ASCII"))
2396 ? P_HIBITIGN
: 0L));
2398 if(ps_global
->VAR_OPER_DIR
){
2399 pbf
->oper_dir
= ps_global
->VAR_OPER_DIR
;
2400 pbf
->pine_flags
|= P_TREE
;
2403 pbf
->home_dir
= ps_global
->home_dir
;
2408 standard_picobuf_teardown(PICO
*pbf
)
2412 free_pcolors(&pbf
->colors
);
2415 fs_give((void **) &pbf
->wordseps
);
2420 /*----------------------------------------------------------------------
2421 Call back for pico to use to check for new mail.
2423 Args: cursor -- pointer to in to tell caller if cursor location changed
2424 if NULL, turn off cursor positioning.
2425 timing -- whether or not it's a good time to check
2428 Returns: returns 1 on success, zero on error.
2431 new_mail_for_pico(int timing
, int status
)
2434 * If we're not interested in the status, don't display the busy
2437 /* don't know where the cursor's been, reset it */
2439 return(new_mail(0, timing
,
2440 (status
? NM_STATUS_MSG
: NM_NONE
) | NM_DEFER_SORT
2441 | NM_FROM_COMPOSER
));
2446 cmd_input_for_pico(void)
2448 zero_new_mail_count();
2452 /*----------------------------------------------------------------------
2453 Call back for pico to get newmail status messages displayed
2455 Args: x -- char processed
2460 display_message_for_pico(int x
)
2464 clear_cursor_pos(); /* can't know where cursor is */
2465 mark_status_dirty(); /* don't count on cached text */
2466 fix_windsize(ps_global
);
2469 rv
= ps_global
->mangled_screen
;
2470 ps_global
->mangled_screen
= 0;
2475 /*----------------------------------------------------------------------
2476 Call back for pico to get desired directory for its check point file
2478 Args: s -- buffer to write directory name
2479 n -- length of that buffer
2481 Returns: pointer to static buffer
2484 checkpoint_dir_for_pico(char *s
, size_t n
)
2486 #if defined(DOS) || defined(OS2)
2488 * we can't assume anything about root or home dirs, so
2489 * just plunk it down in the same place as the pinerc
2491 if(!getenv("HOME")){
2492 char *lc
= last_cmpnt(ps_global
->pinerc
);
2495 strncpy(s
, ps_global
->pinerc
, MIN(n
-1,lc
-ps_global
->pinerc
));
2496 s
[MIN(n
-1,lc
-ps_global
->pinerc
)] = '\0';
2499 strncpy(s
, ".\\", n
-1);
2505 strncpy(s
, ps_global
->home_dir
, n
-1);
2512 /*----------------------------------------------------------------------
2513 Call back for pico to tell us the window size's changed
2517 Returns: none (but pine's ttyo structure may have been updated)
2520 resize_for_pico(void)
2522 fix_windsize(ps_global
);
2527 colors_for_pico(void)
2529 PCOLORS
*colors
= NULL
;
2530 struct variable
*vars
= ps_global
->vars
;
2532 if (pico_usingcolor()){
2533 colors
= (PCOLORS
*)fs_get(sizeof(PCOLORS
));
2535 colors
->tbcp
= current_titlebar_color();
2537 if (VAR_KEYLABEL_FORE_COLOR
&& VAR_KEYLABEL_BACK_COLOR
){
2538 colors
->klcp
= new_color_pair(VAR_KEYLABEL_FORE_COLOR
,
2539 VAR_KEYLABEL_BACK_COLOR
);
2540 if (!pico_is_good_colorpair(colors
->klcp
))
2541 free_color_pair(&colors
->klcp
);
2543 else colors
->klcp
= NULL
;
2545 if (colors
->klcp
&& VAR_KEYNAME_FORE_COLOR
&& VAR_KEYNAME_BACK_COLOR
){
2546 colors
->kncp
= new_color_pair(VAR_KEYNAME_FORE_COLOR
,
2547 VAR_KEYNAME_BACK_COLOR
);
2549 else colors
->kncp
= NULL
;
2551 if (VAR_STATUS_FORE_COLOR
&& VAR_STATUS_BACK_COLOR
){
2552 colors
->stcp
= new_color_pair(VAR_STATUS_FORE_COLOR
,
2553 VAR_STATUS_BACK_COLOR
);
2555 else colors
->stcp
= NULL
;
2557 if (VAR_PROMPT_FORE_COLOR
&& VAR_PROMPT_BACK_COLOR
){
2558 colors
->prcp
= new_color_pair(VAR_PROMPT_FORE_COLOR
,
2559 VAR_PROMPT_BACK_COLOR
);
2561 else colors
->prcp
= NULL
;
2569 free_pcolors(PCOLORS
**colors
)
2572 if ((*colors
)->tbcp
)
2573 free_color_pair(&(*colors
)->tbcp
);
2574 if ((*colors
)->kncp
)
2575 free_color_pair(&(*colors
)->kncp
);
2576 if ((*colors
)->klcp
)
2577 free_color_pair(&(*colors
)->klcp
);
2578 if ((*colors
)->stcp
)
2579 free_color_pair(&(*colors
)->stcp
);
2580 if ((*colors
)->prcp
)
2581 free_color_pair(&(*colors
)->prcp
);
2582 fs_give((void **)colors
);
2583 fs_give((void **)colors
);