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-2014 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(strucmp(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
;
1850 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, _("BOUNCE (redirect) %ld messages to : "),
1851 mn_total_cur(pine_state
->msgmap
));
1852 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
1853 prmpt_who
= cpystr(tmp_20k_buf
);
1854 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, _("Send %ld messages "),
1855 mn_total_cur(pine_state
->msgmap
));
1856 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
1857 prmpt_cnf
= cpystr(tmp_20k_buf
);
1860 for(msgno
= mn_first_cur(pine_state
->msgmap
);
1862 msgno
= mn_next_cur(pine_state
->msgmap
)){
1864 rawno
= mn_m2raw(pine_state
->msgmap
, msgno
);
1865 if((env
= pine_mail_fetchstructure(pine_state
->mail_stream
, rawno
, NULL
)) != NULL
)
1866 errstr
= bounce_msg(pine_state
->mail_stream
, rawno
, NULL
, role
,
1867 save_toptr
, env
->subject
, prmpt_who
, prmpt_cnf
);
1869 errstr
= _("Can't fetch Subject for Bounce");
1874 q_status_message(SM_ORDER
| SM_DING
, 4, 7, errstr
);
1881 fs_give((void **)&save_to
);
1884 fs_give((void **) &prmpt_who
);
1887 fs_give((void **) &prmpt_cnf
);
1889 return(errstr
? 0 : 1);
1895 bounce_msg(MAILSTREAM
*stream
,
1904 char *errstr
= NULL
;
1910 if((errstr
= bounce_msg_body(stream
, rawno
, part
, to
, subject
, &outgoing
, &body
, &was_seen
)) == NULL
){
1911 if(pine_simple_send(outgoing
, &body
, role
, pmt_who
, pmt_cnf
, to
,
1912 !(to
&& *to
) ? SS_PROMPTFORTO
: 0) < 0){
1913 errstr
= ""; /* p_s_s() better have explained! */
1914 /* clear seen flag */
1915 if(was_seen
== 0 && rawno
> 0L
1916 && stream
&& rawno
<= stream
->nmsgs
1917 && (mc
= mail_elt(stream
, rawno
)) && mc
->seen
)
1918 mail_flag(stream
, long2string(rawno
), "\\SEEN", 0);
1922 /* Just for good measure... */
1923 mail_free_envelope(&outgoing
);
1924 pine_free_body(&body
);
1926 return(errstr
); /* no problem-o */
1930 /*----------------------------------------------------------------------
1931 Serve up the current signature within pico for editing
1935 Result: signature changed or not.
1938 signature_edit(char *sigfile
, char *title
)
1941 char sig_path
[MAXPATH
+1], errbuf
[2000], *errstr
= NULL
;
1943 STORE_S
*msgso
, *tmpso
= NULL
;
1946 struct variable
*vars
= ps_global
->vars
;
1947 REMDATA_S
*rd
= NULL
;
1949 if(!signature_path(sigfile
, sig_path
, MAXPATH
))
1950 return(cpystr(_("No signature file defined.")));
1952 if(IS_REMOTE(sigfile
)){
1953 rd
= rd_create_remote(RemImap
, sig_path
, REMOTE_SIG_SUBTYPE
,
1955 _("Can't access remote configuration."));
1957 return(cpystr(_("Error attempting to edit remote configuration")));
1959 (void)rd_read_metadata(rd
);
1961 if(rd
->access
== MaybeRorW
){
1962 if(rd
->read_status
== 'R')
1963 rd
->access
= ReadOnly
;
1965 rd
->access
= ReadWrite
;
1968 if(rd
->access
!= NoExists
){
1970 rd_check_remvalid(rd
, 1L);
1973 * If the cached info says it is readonly but
1974 * it looks like it's been fixed now, change it to readwrite.
1976 if(rd
->read_status
== 'R'){
1977 rd_check_readonly_access(rd
);
1978 if(rd
->read_status
== 'W'){
1979 rd
->access
= ReadWrite
;
1980 rd
->flags
|= REM_OUTOFDATE
;
1983 rd
->access
= ReadOnly
;
1987 if(rd
->flags
& REM_OUTOFDATE
){
1988 if(rd_update_local(rd
) != 0){
1991 "signature_edit: rd_update_local failed\n"));
1992 rd_close_remdata(&rd
);
1993 return(cpystr(_("Can't access remote sig")));
1999 if(rd
->access
!= ReadWrite
|| rd_remote_is_readonly(rd
)){
2000 rd_close_remdata(&rd
);
2001 return(cpystr(_("Can't get write permission for remote sig")));
2004 rd
->flags
|= DO_REMTRIM
;
2006 strncpy(sig_path
, rd
->lf
, sizeof(sig_path
)-1);
2007 sig_path
[sizeof(sig_path
)-1] = '\0';
2010 standard_picobuf_setup(&pbf
);
2011 pbf
.tty_fix
= PineRaw
;
2012 pbf
.composer_help
= h_composer_sigedit
;
2013 pbf
.exittest
= sigedit_exit_for_pico
;
2014 pbf
.upload
= (VAR_UPLOAD_CMD
&& VAR_UPLOAD_CMD
[0])
2015 ? upload_msg_to_pico
: NULL
;
2016 pbf
.alt_ed
= (VAR_EDITOR
&& VAR_EDITOR
[0] && VAR_EDITOR
[0][0])
2017 ? VAR_EDITOR
: NULL
;
2018 pbf
.alt_spell
= (VAR_SPELLER
&& VAR_SPELLER
[0]) ? VAR_SPELLER
: NULL
;
2019 pbf
.always_spell_check
= F_ON(F_ALWAYS_SPELL_CHECK
, ps_global
);
2020 pbf
.strip_ws_before_send
= F_ON(F_STRIP_WS_BEFORE_SEND
, ps_global
);
2021 pbf
.allow_flowed_text
= 0;
2023 pbf
.pine_anchor
= set_titlebar(title
,
2024 ps_global
->mail_stream
,
2025 ps_global
->context_current
,
2026 ps_global
->cur_folder
,
2028 0, FolderName
, 0, 0, NULL
);
2030 /* NOTE: at this point, alot of pico struct fields are null'd out
2031 * thanks to the leading memset; in particular "headents" which tells
2032 * pico to behave like a normal editor (though modified slightly to
2033 * let the caller dictate the file to edit and such)...
2036 if(VAR_OPER_DIR
&& !in_dir(VAR_OPER_DIR
, sig_path
)){
2039 l
= strlen(VAR_OPER_DIR
) + 100;
2040 ret
= (char *) fs_get((l
+1) * sizeof(char));
2041 snprintf(ret
, l
+1, _("Can't edit file outside of %s"), VAR_OPER_DIR
);
2047 * Now alloc and init the text to pass pico
2049 if(!(msgso
= so_get(PicoText
, NULL
, EDIT_ACCESS
))){
2050 ret
= cpystr(_("Error allocating space for file"));
2051 dprint((1, "Can't alloc space for signature_edit"));
2055 pbf
.msgtext
= so_text(msgso
);
2057 if(can_access(sig_path
, READ_ACCESS
) == 0
2058 && !(tmpso
= so_get(FileStar
, sig_path
, READ_ACCESS
|READ_FROM_LOCALE
))){
2059 char *problem
= error_description(errno
);
2061 snprintf(errbuf
, sizeof(errbuf
), _("Error editing \"%s\": %s"),
2062 sig_path
, problem
? problem
: "<NULL>");
2063 errbuf
[sizeof(errbuf
)-1] = '\0';
2064 ret
= cpystr(errbuf
);
2066 dprint((1, "signature_edit: can't open %s: %s", sig_path
,
2067 problem
? problem
: "<NULL>"));
2070 else if(tmpso
){ /* else, fill pico's edit buffer */
2071 gf_set_so_readc(&gc
, tmpso
); /* read from file, write pico buf */
2072 gf_set_so_writec(&pc
, msgso
);
2073 gf_filter_init(); /* no filters needed */
2074 if((errstr
= gf_pipe(gc
, pc
)) != NULL
){
2075 snprintf(errbuf
, sizeof(errbuf
), _("Error reading file: \"%s\""), errstr
);
2076 errbuf
[sizeof(errbuf
)-1] = '\0';
2077 ret
= cpystr(errbuf
);
2080 gf_clear_so_readc(tmpso
);
2081 gf_clear_so_writec(msgso
);
2087 mswin_setwindowmenu (MENU_COMPOSER
);
2090 /*------ OK, Go edit the signature ------*/
2091 editor_result
= pico(&pbf
);
2094 mswin_setwindowmenu (MENU_DEFAULT
);
2096 if(editor_result
& COMP_GOTHUP
){
2097 hup_signal(); /* do what's normal for a hup */
2100 fix_windsize(ps_global
);
2104 if(editor_result
& (COMP_SUSPEND
| COMP_GOTHUP
| COMP_CANCEL
)){
2107 /*------ Must have an edited buffer, write it to .sig -----*/
2108 our_unlink(sig_path
); /* blast old copy */
2109 if((tmpso
= so_get(FileStar
, sig_path
, WRITE_ACCESS
|WRITE_TO_LOCALE
)) != NULL
){
2110 so_seek(msgso
, 0L, 0);
2111 gf_set_so_readc(&gc
, msgso
); /* read from pico buf */
2112 gf_set_so_writec(&pc
, tmpso
); /* write sig file */
2113 gf_filter_init(); /* no filters needed */
2114 if((errstr
= gf_pipe(gc
, pc
)) != NULL
){
2115 snprintf(errbuf
, sizeof(errbuf
), _("Error writing file: \"%s\""),
2117 errbuf
[sizeof(errbuf
)-1] = '\0';
2118 ret
= cpystr(errbuf
);
2121 gf_clear_so_readc(msgso
);
2122 gf_clear_so_writec(tmpso
);
2123 if(so_give(&tmpso
)){
2124 errstr
= error_description(errno
);
2125 snprintf(errbuf
, sizeof(errbuf
), _("Error writing file: \"%s\""),
2127 errbuf
[sizeof(errbuf
)-1] = '\0';
2128 ret
= cpystr(errbuf
);
2131 if(IS_REMOTE(sigfile
)){
2137 we_cancel
= busy_cue("Copying to remote sig", NULL
, 1);
2138 if((e
= rd_update_remote(rd
, datebuf
)) != 0){
2140 q_status_message2(SM_ORDER
| SM_DING
, 3, 5,
2141 _("Error opening temporary sig file %s: %s"),
2142 rd
->lf
, error_description(errno
));
2144 "write_remote_sig: error opening temp file %s\n",
2145 rd
->lf
? rd
->lf
: "?"));
2148 q_status_message2(SM_ORDER
| SM_DING
, 3, 5,
2149 _("Error copying to %s: %s"),
2150 rd
->rn
, error_description(errno
));
2152 "write_remote_sig: error copying from %s to %s\n",
2153 rd
->lf
? rd
->lf
: "?", rd
->rn
? rd
->rn
: "?"));
2156 q_status_message(SM_ORDER
| SM_DING
, 5, 5,
2157 _("Copy of sig to remote folder failed, changes NOT saved remotely"));
2160 rd_update_metadata(rd
, datebuf
);
2161 rd
->read_status
= 'W';
2164 rd_close_remdata(&rd
);
2167 cancel_busy_cue(-1);
2171 snprintf(errbuf
, sizeof(errbuf
), _("Error writing \"%s\""), sig_path
);
2172 errbuf
[sizeof(errbuf
)-1] = '\0';
2173 ret
= cpystr(errbuf
);
2174 dprint((1, "signature_edit: can't write %s",
2180 standard_picobuf_teardown(&pbf
);
2186 /*----------------------------------------------------------------------
2187 Serve up the current signature within pico for editing
2189 Args: literal signature to edit
2191 Result: raw edited signature is returned in result arg
2194 signature_edit_lit(char *litsig
, char **result
, char *title
, HelpType composer_help
)
2197 char *errstr
= NULL
;
2201 struct variable
*vars
= ps_global
->vars
;
2203 standard_picobuf_setup(&pbf
);
2204 pbf
.tty_fix
= PineRaw
;
2205 pbf
.search_help
= h_sigedit_search
;
2206 pbf
.composer_help
= composer_help
;
2207 pbf
.exittest
= sigedit_exit_for_pico
;
2208 pbf
.upload
= (VAR_UPLOAD_CMD
&& VAR_UPLOAD_CMD
[0])
2209 ? upload_msg_to_pico
: NULL
;
2210 pbf
.alt_ed
= (VAR_EDITOR
&& VAR_EDITOR
[0] && VAR_EDITOR
[0][0])
2211 ? VAR_EDITOR
: NULL
;
2212 pbf
.alt_spell
= (VAR_SPELLER
&& VAR_SPELLER
[0]) ? VAR_SPELLER
: NULL
;
2213 pbf
.always_spell_check
= F_ON(F_ALWAYS_SPELL_CHECK
, ps_global
);
2214 pbf
.strip_ws_before_send
= F_ON(F_STRIP_WS_BEFORE_SEND
, ps_global
);
2215 pbf
.allow_flowed_text
= 0;
2217 pbf
.pine_anchor
= set_titlebar(title
,
2218 ps_global
->mail_stream
,
2219 ps_global
->context_current
,
2220 ps_global
->cur_folder
,
2222 0, FolderName
, 0, 0, NULL
);
2224 /* NOTE: at this point, alot of pico struct fields are null'd out
2225 * thanks to the leading memset; in particular "headents" which tells
2226 * pico to behave like a normal editor (though modified slightly to
2227 * let the caller dictate the file to edit and such)...
2231 * Now alloc and init the text to pass pico
2233 if(!(msgso
= so_get(PicoText
, NULL
, EDIT_ACCESS
))){
2234 ret
= cpystr(_("Error allocating space"));
2235 dprint((1, "Can't alloc space for signature_edit_lit"));
2239 pbf
.msgtext
= so_text(msgso
);
2241 so_puts(msgso
, litsig
? litsig
: "");
2246 mswin_setwindowmenu (MENU_COMPOSER
);
2249 /*------ OK, Go edit the signature ------*/
2250 editor_result
= pico(&pbf
);
2253 mswin_setwindowmenu (MENU_DEFAULT
);
2255 if(editor_result
& COMP_GOTHUP
){
2256 hup_signal(); /* do what's normal for a hup */
2259 fix_windsize(ps_global
);
2263 if(editor_result
& (COMP_SUSPEND
| COMP_GOTHUP
| COMP_CANCEL
)){
2264 ret
= cpystr(_("Edit Cancelled"));
2267 /*------ Must have an edited buffer, write it to .sig -----*/
2272 so_seek(msgso
, 0L, 0);
2273 while(so_readc(&c
, msgso
))
2276 *result
= (char *)fs_get((cnt
+1) * sizeof(char));
2278 so_seek(msgso
, 0L, 0);
2279 while(so_readc(&c
, msgso
))
2286 standard_picobuf_teardown(&pbf
);
2293 * Returns 0 for Save Changes and exit
2295 * -1 exit but Dont Save Changes
2298 sigedit_exit_for_pico(struct headerentry
*he
, void (*redraw_pico
)(void), int allow_flowed
,
2303 void (*redraw
)(void) = ps_global
->redrawer
;
2304 static ESCKEY_S opts
[] = {
2305 {'s', 's', "S", N_("Save changes")},
2306 {'d', 'd', "D", N_("Don't save changes")},
2310 ps_global
->redrawer
= redraw_pico
;
2311 fix_windsize(ps_global
);
2314 rv
= radio_buttons(_("Exit editor? "),
2315 -FOOTER_ROWS(ps_global
), opts
,
2316 's', 'x', h_exit_editor
, RB_NORM
);
2317 if(rv
== 's'){ /* user ACCEPTS! */
2320 else if(rv
== 'd'){ /* Declined! */
2321 rstr
= _("No Changes Saved");
2324 else if(rv
== 'x'){ /* Cancelled! */
2325 rstr
= _("Exit Cancelled");
2333 ps_global
->redrawer
= redraw
;
2334 return((rv
== 's') ? 0 : (rv
== 'd') ? -1 : 1);
2339 * Common stuff we almost always want to set when calling pico.
2342 standard_picobuf_setup(PICO
*pbf
)
2344 memset(pbf
, 0, sizeof(*pbf
));
2346 pbf
->pine_version
= ALPINE_VERSION
;
2347 pbf
->fillcolumn
= ps_global
->composer_fillcol
;
2348 pbf
->menu_rows
= FOOTER_ROWS(ps_global
) - 1;
2349 pbf
->colors
= colors_for_pico();
2350 pbf
->wordseps
= user_wordseps(ps_global
->VAR_WORDSEPS
);
2351 pbf
->helper
= helper
;
2352 pbf
->showmsg
= display_message_for_pico
;
2353 pbf
->suspend
= do_suspend
;
2354 pbf
->keybinput
= cmd_input_for_pico
;
2355 pbf
->tty_fix
= ttyfix
; /* watch out for this one */
2356 pbf
->newmail
= new_mail_for_pico
;
2357 pbf
->ckptdir
= checkpoint_dir_for_pico
;
2358 pbf
->resize
= resize_for_pico
;
2359 pbf
->input_cs
= ps_global
->input_cs
;
2360 pbf
->winch_cleanup
= winch_cleanup
;
2361 pbf
->search_help
= h_composer_search
;
2362 pbf
->ins_help
= h_composer_ins
;
2363 pbf
->ins_m_help
= h_composer_ins_m
;
2364 pbf
->composer_help
= h_composer
;
2365 pbf
->browse_help
= h_composer_browse
;
2366 pbf
->attach_help
= h_composer_ctrl_j
;
2369 ( (F_ON(F_CAN_SUSPEND
,ps_global
) ? P_SUSPEND
: 0L)
2370 | (F_ON(F_USE_FK
,ps_global
) ? P_FKEYS
: 0L)
2371 | (ps_global
->restricted
? P_SECURE
: 0L)
2372 | (F_ON(F_ALT_ED_NOW
,ps_global
) ? P_ALTNOW
: 0L)
2373 | (F_ON(F_USE_CURRENT_DIR
,ps_global
) ? P_CURDIR
: 0L)
2374 | (F_ON(F_SUSPEND_SPAWNS
,ps_global
) ? P_SUBSHELL
: 0L)
2375 | (F_ON(F_COMPOSE_MAPS_DEL
,ps_global
) ? P_DELRUBS
: 0L)
2376 | (F_ON(F_ENABLE_TAB_COMPLETE
,ps_global
) ? P_COMPLETE
: 0L)
2377 | (F_ON(F_SHOW_CURSOR
,ps_global
) ? P_SHOCUR
: 0L)
2378 | (F_ON(F_DEL_FROM_DOT
,ps_global
) ? P_DOTKILL
: 0L)
2379 | (F_ON(F_ENABLE_DOT_FILES
,ps_global
) ? P_DOTFILES
: 0L)
2380 | (F_ON(F_ALLOW_GOTO
,ps_global
) ? P_ALLOW_GOTO
: 0L)
2381 | (F_ON(F_ENABLE_SEARCH_AND_REPL
,ps_global
) ? P_REPLACE
: 0L)
2382 | (!ps_global
->pass_ctrl_chars
2383 && !ps_global
->pass_c1_ctrl_chars
? P_HICTRL
: 0L)
2384 | ((F_ON(F_ENABLE_ALT_ED
,ps_global
)
2385 || F_ON(F_ALT_ED_NOW
,ps_global
)
2386 || (ps_global
->VAR_EDITOR
2387 && ps_global
->VAR_EDITOR
[0]
2388 && ps_global
->VAR_EDITOR
[0][0]))
2390 | ((!ps_global
->keyboard_charmap
2391 || !strucmp(ps_global
->keyboard_charmap
, "US-ASCII"))
2392 ? P_HIBITIGN
: 0L));
2394 if(ps_global
->VAR_OPER_DIR
){
2395 pbf
->oper_dir
= ps_global
->VAR_OPER_DIR
;
2396 pbf
->pine_flags
|= P_TREE
;
2399 pbf
->home_dir
= ps_global
->home_dir
;
2404 standard_picobuf_teardown(PICO
*pbf
)
2408 free_pcolors(&pbf
->colors
);
2411 fs_give((void **) &pbf
->wordseps
);
2416 /*----------------------------------------------------------------------
2417 Call back for pico to use to check for new mail.
2419 Args: cursor -- pointer to in to tell caller if cursor location changed
2420 if NULL, turn off cursor positioning.
2421 timing -- whether or not it's a good time to check
2424 Returns: returns 1 on success, zero on error.
2427 new_mail_for_pico(int timing
, int status
)
2430 * If we're not interested in the status, don't display the busy
2433 /* don't know where the cursor's been, reset it */
2435 return(new_mail(0, timing
,
2436 (status
? NM_STATUS_MSG
: NM_NONE
) | NM_DEFER_SORT
2437 | NM_FROM_COMPOSER
));
2442 cmd_input_for_pico(void)
2444 zero_new_mail_count();
2448 /*----------------------------------------------------------------------
2449 Call back for pico to get newmail status messages displayed
2451 Args: x -- char processed
2456 display_message_for_pico(int x
)
2460 clear_cursor_pos(); /* can't know where cursor is */
2461 mark_status_dirty(); /* don't count on cached text */
2462 fix_windsize(ps_global
);
2465 rv
= ps_global
->mangled_screen
;
2466 ps_global
->mangled_screen
= 0;
2471 /*----------------------------------------------------------------------
2472 Call back for pico to get desired directory for its check point file
2474 Args: s -- buffer to write directory name
2475 n -- length of that buffer
2477 Returns: pointer to static buffer
2480 checkpoint_dir_for_pico(char *s
, size_t n
)
2482 #if defined(DOS) || defined(OS2)
2484 * we can't assume anything about root or home dirs, so
2485 * just plunk it down in the same place as the pinerc
2487 if(!getenv("HOME")){
2488 char *lc
= last_cmpnt(ps_global
->pinerc
);
2491 strncpy(s
, ps_global
->pinerc
, MIN(n
-1,lc
-ps_global
->pinerc
));
2492 s
[MIN(n
-1,lc
-ps_global
->pinerc
)] = '\0';
2495 strncpy(s
, ".\\", n
-1);
2501 strncpy(s
, ps_global
->home_dir
, n
-1);
2508 /*----------------------------------------------------------------------
2509 Call back for pico to tell us the window size's changed
2513 Returns: none (but pine's ttyo structure may have been updated)
2516 resize_for_pico(void)
2518 fix_windsize(ps_global
);
2523 colors_for_pico(void)
2525 PCOLORS
*colors
= NULL
;
2526 struct variable
*vars
= ps_global
->vars
;
2528 if (pico_usingcolor()){
2529 colors
= (PCOLORS
*)fs_get(sizeof(PCOLORS
));
2531 colors
->tbcp
= current_titlebar_color();
2533 if (VAR_KEYLABEL_FORE_COLOR
&& VAR_KEYLABEL_BACK_COLOR
){
2534 colors
->klcp
= new_color_pair(VAR_KEYLABEL_FORE_COLOR
,
2535 VAR_KEYLABEL_BACK_COLOR
);
2536 if (!pico_is_good_colorpair(colors
->klcp
))
2537 free_color_pair(&colors
->klcp
);
2539 else colors
->klcp
= NULL
;
2541 if (colors
->klcp
&& VAR_KEYNAME_FORE_COLOR
&& VAR_KEYNAME_BACK_COLOR
){
2542 colors
->kncp
= new_color_pair(VAR_KEYNAME_FORE_COLOR
,
2543 VAR_KEYNAME_BACK_COLOR
);
2545 else colors
->kncp
= NULL
;
2547 if (VAR_STATUS_FORE_COLOR
&& VAR_STATUS_BACK_COLOR
){
2548 colors
->stcp
= new_color_pair(VAR_STATUS_FORE_COLOR
,
2549 VAR_STATUS_BACK_COLOR
);
2551 else colors
->stcp
= NULL
;
2553 if (VAR_PROMPT_FORE_COLOR
&& VAR_PROMPT_BACK_COLOR
){
2554 colors
->prcp
= new_color_pair(VAR_PROMPT_FORE_COLOR
,
2555 VAR_PROMPT_BACK_COLOR
);
2557 else colors
->prcp
= NULL
;
2565 free_pcolors(PCOLORS
**colors
)
2568 if ((*colors
)->tbcp
)
2569 free_color_pair(&(*colors
)->tbcp
);
2570 if ((*colors
)->kncp
)
2571 free_color_pair(&(*colors
)->kncp
);
2572 if ((*colors
)->klcp
)
2573 free_color_pair(&(*colors
)->klcp
);
2574 if ((*colors
)->stcp
)
2575 free_color_pair(&(*colors
)->stcp
);
2576 if ((*colors
)->prcp
)
2577 free_color_pair(&(*colors
)->prcp
);
2578 fs_give((void **)colors
);
2579 fs_give((void **)colors
);