~ubuntu-branches/debian/stretch/alpine/stretch

« back to all changes in this revision

Viewing changes to alpine/reply.c

  • Committer: Bazaar Package Importer
  • Author(s): Asheesh Laroia
  • Date: 2007-02-17 13:17:42 UTC
  • Revision ID: james.westby@ubuntu.com-20070217131742-99x5c6cpg1pbkdhw
Tags: upstream-0.82+dfsg
ImportĀ upstreamĀ versionĀ 0.82+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#if !defined(lint) && !defined(DOS)
 
2
static char rcsid[] = "$Id: reply.c 394 2007-01-25 20:29:45Z hubert@u.washington.edu $";
 
3
#endif
 
4
 
 
5
/*
 
6
 * ========================================================================
 
7
 * Copyright 2006-2007 University of Washington
 
8
 *
 
9
 * Licensed under the Apache License, Version 2.0 (the "License");
 
10
 * you may not use this file except in compliance with the License.
 
11
 * You may obtain a copy of the License at
 
12
 *
 
13
 *     http://www.apache.org/licenses/LICENSE-2.0
 
14
 *
 
15
 * ========================================================================
 
16
 */
 
17
 
 
18
/*======================================================================
 
19
   Code here for forward and reply to mail
 
20
   A few support routines as well
 
21
 
 
22
  This code will forward and reply to MIME messages. The Alpine composer
 
23
at this time will only support non-text segments at the end of a
 
24
message so, things don't always come out as one would like. If you
 
25
always forward a message in MIME format, all will be correct.  Forwarding
 
26
of nested MULTIPART messages will work.  There's still a problem with
 
27
MULTIPART/ALTERNATIVE as the "first text part" rule doesn't allow modifying
 
28
the equivalent parts.  Ideally, we should probably such segments as a 
 
29
single attachment when forwarding/replying.  It would also be real nice to
 
30
flatten out the nesting in the composer so pieces inside can get snipped.
 
31
 
 
32
The evolution continues...
 
33
  =====*/
 
34
 
 
35
 
 
36
#include "headers.h"
 
37
#include "reply.h"
 
38
#include "status.h"
 
39
#include "radio.h"
 
40
#include "send.h"
 
41
#include "titlebar.h"
 
42
#include "mailindx.h"
 
43
#include "help.h"
 
44
#include "signal.h"
 
45
#include "mailcmd.h"
 
46
#include "alpine.h"
 
47
#include "../pith/state.h"
 
48
#include "../pith/conf.h"
 
49
#include "../pith/init.h"
 
50
#include "../pith/filter.h"
 
51
#include "../pith/pattern.h"
 
52
#include "../pith/charset.h"
 
53
#include "../pith/rfc2231.h"
 
54
#include "../pith/remote.h"
 
55
#include "../pith/news.h"
 
56
#include "../pith/util.h"
 
57
#include "../pith/detoken.h"
 
58
#include "../pith/newmail.h"
 
59
#include "../pith/readfile.h"
 
60
 
 
61
 
 
62
/*
 
63
 * Internal Prototypes
 
64
 */
 
65
int      reply_poster_followup(ENVELOPE *);
 
66
char    *sigedit_exit_for_pico(struct headerentry *, void (*)(void), int);
 
67
long     new_mail_for_pico(int, int);
 
68
void     cmd_input_for_pico(void);
 
69
int      display_message_for_pico(int);
 
70
char    *checkpoint_dir_for_pico(char *, size_t);
 
71
void     resize_for_pico(void);
 
72
PCOLORS *colors_for_pico(void);
 
73
void     free_pcolors(PCOLORS **);
 
74
 
 
75
/*
 
76
 * standard type of storage object used for body parts...
 
77
 */
 
78
#if     defined(DOS) && !defined(WIN32)
 
79
#define           PART_SO_TYPE  TmpFileStar
 
80
#else
 
81
#define           PART_SO_TYPE  CharStar
 
82
#endif
 
83
 
 
84
 
 
85
/*----------------------------------------------------------------------
 
86
        Fill in an outgoing message for reply and pass off to send
 
87
 
 
88
    Args: pine_state -- The usual pine structure
 
89
 
 
90
  Result: Reply is formatted and passed off to composer/mailer
 
91
 
 
92
Reply
 
93
 
 
94
   - put senders address in To field
 
95
   - search to and cc fields to see if we aren't the only recipients
 
96
   - if other than us, ask if we should reply to all.
 
97
   - if answer yes, fill out the To and Cc fields
 
98
   - fill in the fcc argument
 
99
   - fill in the subject field
 
100
   - fill out the body and the attachments
 
101
   - pass off to pine_send()
 
102
  ---*/
 
103
int
 
104
reply(struct pine *pine_state, ACTION_S *role_arg)
 
105
{
 
106
    ADDRESS    *saved_from, *saved_to, *saved_cc, *saved_resent;
 
107
    ENVELOPE   *env, *outgoing;
 
108
    BODY       *body, *orig_body = NULL;
 
109
    REPLY_S     reply;
 
110
    void       *msgtext = NULL;
 
111
    char       *tmpfix = NULL, *prefix = NULL, *fcc = NULL, *errmsg = NULL;
 
112
    long        msgno, j, totalm, rflags, *seq = NULL;
 
113
    int         i, include_text = 0, times = -1, warned = 0, rv = 0,
 
114
                flags = RSF_QUERY_REPLY_ALL, reply_raw_body = 0;
 
115
    gf_io_t     pc;
 
116
    PAT_STATE   dummy;
 
117
    REDRAFT_POS_S *redraft_pos = NULL;
 
118
    ACTION_S   *role = NULL, *nrole;
 
119
#if     defined(DOS) && !defined(_WINDOWS)
 
120
    char *reserve;
 
121
#endif
 
122
 
 
123
    outgoing = mail_newenvelope();
 
124
    totalm   = mn_total_cur(pine_state->msgmap);
 
125
    seq      = (long *)fs_get(((size_t)totalm + 1) * sizeof(long));
 
126
 
 
127
    dprint((4,"\n - reply (%s msgs) -\n", comatose(totalm)));
 
128
 
 
129
    saved_from            = (ADDRESS *) NULL;
 
130
    saved_to              = (ADDRESS *) NULL;
 
131
    saved_cc              = (ADDRESS *) NULL;
 
132
    saved_resent          = (ADDRESS *) NULL;
 
133
    outgoing->subject     = NULL;
 
134
 
 
135
    memset((void *)&reply, 0, sizeof(reply));
 
136
 
 
137
    if(ps_global->full_header == 2
 
138
       && F_ON(F_ENABLE_FULL_HDR_AND_TEXT, ps_global))
 
139
      reply_raw_body = 1;
 
140
 
 
141
    /*
 
142
     * We may have to loop through first to figure out what default
 
143
     * reply-indent-string to offer...
 
144
     */
 
145
    if(mn_total_cur(pine_state->msgmap) > 1 &&
 
146
       F_ON(F_ENABLE_EDIT_REPLY_INDENT, pine_state) &&
 
147
       reply_quote_str_contains_tokens()){
 
148
        for(msgno = mn_first_cur(pine_state->msgmap);
 
149
            msgno > 0L && !tmpfix;
 
150
            msgno = mn_next_cur(pine_state->msgmap)){
 
151
 
 
152
            env = pine_mail_fetchstructure(pine_state->mail_stream,
 
153
                                           mn_m2raw(pine_state->msgmap, msgno),
 
154
                                           NULL);
 
155
            if(!env) {
 
156
                q_status_message1(SM_ORDER,3,4,
 
157
                            _("Error fetching message %s. Can't reply to it."),
 
158
                                long2string(msgno));
 
159
                goto done_early;
 
160
            }
 
161
 
 
162
            if(!tmpfix){                        /* look for prefix? */
 
163
                tmpfix = reply_quote_str(env);
 
164
                if(prefix){
 
165
                    i = strcmp(tmpfix, prefix);
 
166
                    fs_give((void **) &tmpfix);
 
167
                    if(i){              /* don't check back if dissimilar */
 
168
                        fs_give((void **) &prefix);
 
169
                        /*
 
170
                         * We free prefix, not tmpfix. We set tmpfix to prefix
 
171
                         * so that we won't come check again.
 
172
                         */
 
173
                        tmpfix = prefix = cpystr("> ");
 
174
                    }
 
175
                }
 
176
                else{
 
177
                    prefix = tmpfix;
 
178
                    tmpfix = NULL;              /* check back later? */
 
179
                }
 
180
            }
 
181
        }
 
182
 
 
183
        tmpfix = prefix;
 
184
    }
 
185
 
 
186
    /*
 
187
     * Loop thru the selected messages building the
 
188
     * outgoing envelope's destinations...
 
189
     */
 
190
    for(msgno = mn_first_cur(pine_state->msgmap);
 
191
        msgno > 0L;
 
192
        msgno = mn_next_cur(pine_state->msgmap)){
 
193
 
 
194
        /*--- Grab current envelope ---*/
 
195
        env = pine_mail_fetchstructure(pine_state->mail_stream,
 
196
                            seq[++times] = mn_m2raw(pine_state->msgmap, msgno),
 
197
                            NULL);
 
198
        if(!env) {
 
199
            q_status_message1(SM_ORDER,3,4,
 
200
                          _("Error fetching message %s. Can't reply to it."),
 
201
                              long2string(msgno));
 
202
            goto done_early;
 
203
        }
 
204
 
 
205
        /*
 
206
         * We check for the prefix here if we didn't do it in the first
 
207
         * loop above. This is just to save having to go through the loop
 
208
         * twice in the cases where we don't need to.
 
209
         */
 
210
        if(!tmpfix){
 
211
            tmpfix = reply_quote_str(env);
 
212
            if(prefix){
 
213
                i = strcmp(tmpfix, prefix);
 
214
                fs_give((void **) &tmpfix);
 
215
                if(i){                  /* don't check back if dissimilar */
 
216
                    fs_give((void **) &prefix);
 
217
                    tmpfix = prefix = cpystr("> ");
 
218
                }
 
219
            }
 
220
            else{
 
221
                prefix = tmpfix;
 
222
                tmpfix = NULL;          /* check back later? */
 
223
            }
 
224
        }
 
225
 
 
226
        /*
 
227
         * For consistency, the first question is always "include text?"
 
228
         */
 
229
        if(!times){             /* only first time */
 
230
            char *p = cpystr(prefix);
 
231
 
 
232
            if((include_text=reply_text_query(pine_state,totalm,&prefix)) < 0)
 
233
              goto done_early;
 
234
            
 
235
            /* edited prefix? */
 
236
            if(strcmp(p, prefix))
 
237
              tmpfix = prefix;          /* stop looking */
 
238
            
 
239
            fs_give((void **)&p);
 
240
        }
 
241
        
 
242
        /*
 
243
         * If we're agg-replying or there's a newsgroup and the user want's
 
244
         * to post to news *and* via email, add relevant addresses to the
 
245
         * outgoing envelope...
 
246
         *
 
247
         * The single message case gets us around the aggregate reply
 
248
         * to messages in a mixed mail-news archive where some might
 
249
         * have newsgroups and others not or whatever.
 
250
         */
 
251
        if(totalm > 1L || ((i = reply_news_test(env, outgoing)) & 1)){
 
252
            if(totalm > 1)
 
253
              flags |= RSF_FORCE_REPLY_TO;
 
254
 
 
255
            if(!reply_harvest(pine_state, seq[times], NULL, env,
 
256
                              &saved_from, &saved_to, &saved_cc,
 
257
                              &saved_resent, &flags))
 
258
              goto done_early;
 
259
        }
 
260
        else if(i == 0)
 
261
          goto done_early;
 
262
 
 
263
        /*------------ Format the subject line ---------------*/
 
264
        if(outgoing->subject){
 
265
            /*
 
266
             * if reply to more than one message, and all subjects
 
267
             * match, so be it.  otherwise set it to something generic...
 
268
             */
 
269
            if(strucmp(outgoing->subject,
 
270
                       reply_subject(env->subject,tmp_20k_buf,SIZEOF_20KBUF))){
 
271
                fs_give((void **)&outgoing->subject);
 
272
                outgoing->subject = cpystr("Re: several messages");
 
273
            }
 
274
        }
 
275
        else
 
276
          outgoing->subject = reply_subject(env->subject, NULL, 0);
 
277
    }
 
278
 
 
279
    /* fill reply header */
 
280
    reply_seed(pine_state, outgoing, env, saved_from,
 
281
               saved_to, saved_cc, saved_resent,
 
282
               &fcc, flags & RSF_FORCE_REPLY_ALL, &errmsg);
 
283
    if(errmsg){
 
284
        if(*errmsg){
 
285
            q_status_message1(SM_ORDER, 3, 3, "%.200s", errmsg);
 
286
            display_message(NO_OP_COMMAND);
 
287
        }
 
288
 
 
289
        fs_give((void **)&errmsg);
 
290
    }
 
291
 
 
292
    if(sp_expunge_count(pine_state->mail_stream))       /* cur msg expunged */
 
293
      goto done_early;
 
294
 
 
295
    /* Setup possible role */
 
296
    if(role_arg)
 
297
      role = copy_action(role_arg);
 
298
 
 
299
    if(!role){
 
300
        rflags = ROLE_REPLY;
 
301
        if(nonempty_patterns(rflags, &dummy)){
 
302
            /* setup default role */
 
303
            nrole = NULL;
 
304
            j = mn_first_cur(pine_state->msgmap);
 
305
            do {
 
306
                role = nrole;
 
307
                nrole = set_role_from_msg(pine_state, rflags,
 
308
                                          mn_m2raw(pine_state->msgmap, j),
 
309
                                          NULL);
 
310
            } while(nrole && (!role || nrole == role)
 
311
                    && (j=mn_next_cur(pine_state->msgmap)) > 0L);
 
312
 
 
313
            if(!role || nrole == role)
 
314
              role = nrole;
 
315
            else
 
316
              role = NULL;
 
317
 
 
318
            if(confirm_role(rflags, &role))
 
319
              role = combine_inherited_role(role);
 
320
            else{                               /* cancel reply */
 
321
                role = NULL;
 
322
                cmd_cancelled("Reply");
 
323
                goto done_early;
 
324
            }
 
325
        }
 
326
    }
 
327
 
 
328
    /*
 
329
     * Reply_seed may call c-client in get_fcc_based_on_to, so env may
 
330
     * no longer be valid. Get it again.
 
331
     * Similarly for set_role_from_message.
 
332
     */
 
333
    env = pine_mail_fetchstructure(pine_state->mail_stream, seq[times], NULL);
 
334
 
 
335
    if(role){
 
336
        q_status_message1(SM_ORDER, 3, 4,
 
337
                          _("Replying using role \"%s\""), role->nick);
 
338
 
 
339
        /* override fcc gotten in reply_seed */
 
340
        if(role->fcc && fcc)
 
341
          fs_give((void **) &fcc);
 
342
    }
 
343
 
 
344
    seq[++times] = -1L;         /* mark end of sequence list */
 
345
 
 
346
    /*==========  Other miscelaneous fields ===================*/   
 
347
    outgoing->in_reply_to = reply_in_reply_to(env);
 
348
    outgoing->references = reply_build_refs(env);
 
349
    outgoing->message_id = generate_message_id();
 
350
 
 
351
    if(!outgoing->to &&
 
352
       !outgoing->cc &&
 
353
       !outgoing->bcc &&
 
354
       !outgoing->newsgroups)
 
355
      q_status_message(SM_ORDER | SM_DING, 3, 6,
 
356
                       _("Warning: no valid addresses to reply to!"));
 
357
 
 
358
 
 
359
   /*==================== Now fix up the message body ====================*/
 
360
 
 
361
    /* 
 
362
     * create storage object to be used for message text
 
363
     */
 
364
    if((msgtext = (void *)so_get(PicoText, NULL, EDIT_ACCESS)) == NULL){
 
365
        q_status_message(SM_ORDER | SM_DING, 3, 4,
 
366
                         _("Error allocating message text"));
 
367
        goto done_early;
 
368
    }
 
369
 
 
370
    gf_set_so_writec(&pc, (STORE_S *) msgtext);
 
371
 
 
372
    /*---- Include the original text if requested ----*/
 
373
    if(include_text && totalm > 1L){
 
374
        char *sig;
 
375
        int   impl, template_len = 0, leave_cursor_at_top = 0;
 
376
 
 
377
 
 
378
        env = NULL;
 
379
        if(role && role->template){
 
380
            char *filtered;
 
381
 
 
382
            impl = 0;
 
383
            filtered = detoken(role, env, 0,
 
384
                               F_ON(F_SIG_AT_BOTTOM, ps_global) ? 1 : 0,
 
385
                               0, &redraft_pos, &impl);
 
386
            if(filtered){
 
387
                if(*filtered){
 
388
                    so_puts((STORE_S *)msgtext, filtered);
 
389
                    if(impl == 1)
 
390
                      template_len = strlen(filtered);
 
391
                    else if(impl == 2)
 
392
                      leave_cursor_at_top++;
 
393
                }
 
394
 
 
395
                fs_give((void **)&filtered);
 
396
            }
 
397
            else
 
398
              impl = 1;
 
399
        }
 
400
        else
 
401
          impl = 1;
 
402
 
 
403
        if((sig = reply_signature(role, env, &redraft_pos, &impl)) &&
 
404
           F_OFF(F_SIG_AT_BOTTOM, ps_global)){
 
405
 
 
406
            /*
 
407
             * If CURSORPOS was set explicitly in sig_file, and there was a
 
408
             * template file before that, we need to adjust the offset by the
 
409
             * length of the template file. However, if the template had
 
410
             * a set CURSORPOS in it then impl was 2 before getting to the
 
411
             * signature, so offset wouldn't have been reset by the signature
 
412
             * CURSORPOS and offset would already be correct. That case will
 
413
             * be ok here because template_len will be 0 and adding it does
 
414
             * nothing. If template
 
415
             * didn't have CURSORPOS in it, then impl was 1 and got set to 2
 
416
             * by the CURSORPOS in the sig. In that case we have to adjust the
 
417
             * offset. That's what the next line does. It adjusts it if
 
418
             * template_len is nonzero and if CURSORPOS was set in sig_file.
 
419
             */
 
420
            if(impl == 2)
 
421
              redraft_pos->offset += template_len;
 
422
            
 
423
            if(*sig)
 
424
              so_puts((STORE_S *)msgtext, sig);
 
425
            
 
426
            /*
 
427
             * Set sig to NULL because we've already used it. If SIG_AT_BOTTOM
 
428
             * is set, we won't have used it yet and want it to be non-NULL.
 
429
             */
 
430
            fs_give((void **)&sig);
 
431
        }
 
432
 
 
433
        /*
 
434
         * Only put cursor in sig if there is a cursorpos there but not
 
435
         * one in the template, and sig-at-bottom.
 
436
         */
 
437
         if(!(sig && impl == 2 && !leave_cursor_at_top))
 
438
           leave_cursor_at_top++;
 
439
 
 
440
        body                  = mail_newbody();
 
441
        body->type            = TYPETEXT;
 
442
        body->contents.text.data = msgtext;
 
443
 
 
444
        for(msgno = mn_first_cur(pine_state->msgmap);
 
445
            msgno > 0L;
 
446
            msgno = mn_next_cur(pine_state->msgmap)){
 
447
 
 
448
            if(env){                    /* put 2 between messages */
 
449
                gf_puts(NEWLINE, pc);
 
450
                gf_puts(NEWLINE, pc);
 
451
            }
 
452
 
 
453
            /*--- Grab current envelope ---*/
 
454
            env = pine_mail_fetchstructure(pine_state->mail_stream,
 
455
                                           mn_m2raw(pine_state->msgmap, msgno),
 
456
                                           &orig_body);
 
457
            if(!env){
 
458
                q_status_message1(SM_ORDER,3,4,
 
459
                          _("Error fetching message %s. Can't reply to it."),
 
460
                              long2string(mn_get_cur(pine_state->msgmap)));
 
461
                goto done_early;
 
462
            }
 
463
 
 
464
            if(orig_body == NULL || orig_body->type == TYPETEXT || reply_raw_body) {
 
465
                reply_delimiter(env, role, pc);
 
466
                if(F_ON(F_INCLUDE_HEADER, pine_state))
 
467
                  reply_forward_header(pine_state->mail_stream,
 
468
                                       mn_m2raw(pine_state->msgmap,msgno),
 
469
                                       NULL, env, pc, prefix);
 
470
 
 
471
                get_body_part_text(pine_state->mail_stream, reply_raw_body ? NULL : orig_body,
 
472
                                   mn_m2raw(pine_state->msgmap, msgno),
 
473
                                   reply_raw_body ? NULL : "1", 0L, pc, prefix, NULL);
 
474
            }
 
475
            else if(orig_body->type == TYPEMULTIPART) {
 
476
                if(!warned++)
 
477
                  q_status_message(SM_ORDER,3,7,
 
478
                      _("WARNING!  Attachments not included in multiple reply."));
 
479
 
 
480
                if(orig_body->nested.part
 
481
                   && orig_body->nested.part->body.type == TYPETEXT) {
 
482
                    /*---- First part of the message is text -----*/
 
483
                    reply_delimiter(env, role, pc);
 
484
                    if(F_ON(F_INCLUDE_HEADER, pine_state))
 
485
                      reply_forward_header(pine_state->mail_stream,
 
486
                                           mn_m2raw(pine_state->msgmap,
 
487
                                                    msgno),
 
488
                                           NULL, env, pc, prefix);
 
489
 
 
490
                    get_body_part_text(pine_state->mail_stream,
 
491
                                       &orig_body->nested.part->body,
 
492
                                       mn_m2raw(pine_state->msgmap, msgno),
 
493
                                       "1", 0L, pc, prefix, NULL);
 
494
                }
 
495
                else{
 
496
                    q_status_message(SM_ORDER,0,3,
 
497
                                     _("Multipart with no leading text part."));
 
498
                }
 
499
            }
 
500
            else{
 
501
                /*---- Single non-text message of some sort ----*/
 
502
                q_status_message(SM_ORDER,3,3,
 
503
                                 _("Non-text message not included."));
 
504
            }
 
505
        }
 
506
 
 
507
        if(!leave_cursor_at_top){
 
508
            long  cnt = 0L;
 
509
            unsigned char c;
 
510
 
 
511
            /* rewind and count chars to start of sig file */
 
512
            so_seek((STORE_S *)msgtext, 0L, 0);
 
513
            while(so_readc(&c, (STORE_S *)msgtext))
 
514
              cnt++;
 
515
 
 
516
            if(!redraft_pos){
 
517
                redraft_pos = (REDRAFT_POS_S *)fs_get(sizeof(*redraft_pos));
 
518
                memset((void *)redraft_pos, 0,sizeof(*redraft_pos));
 
519
                redraft_pos->hdrname = cpystr(":");
 
520
            }
 
521
 
 
522
            /*
 
523
             * If explicit cursor positioning in sig file,
 
524
             * add offset to start of sig file plus offset into sig file.
 
525
             * Else, just offset to start of sig file.
 
526
             */
 
527
            redraft_pos->offset += cnt;
 
528
        }
 
529
 
 
530
        if(sig){
 
531
            if(*sig)
 
532
              so_puts((STORE_S *)msgtext, sig);
 
533
            
 
534
            fs_give((void **)&sig);
 
535
        }
 
536
    }
 
537
    else{
 
538
        msgno = mn_m2raw(pine_state->msgmap,
 
539
                         mn_get_cur(pine_state->msgmap));
 
540
 
 
541
        /*--- Grab current envelope ---*/
 
542
        env = pine_mail_fetchstructure(pine_state->mail_stream, msgno,
 
543
                                       &orig_body);
 
544
 
 
545
        /*
 
546
         * If the charset of the body part is different from ascii and
 
547
         * charset conversion is _not_ happening, then preserve the original
 
548
         * charset from the message so that if we don't enter any new
 
549
         * chars with the hibit set we can use the original charset.
 
550
         * If not all those things, then don't try to preserve it.
 
551
         */
 
552
        if(orig_body){
 
553
            char *charset;
 
554
 
 
555
            charset = rfc2231_get_param(orig_body->parameter,
 
556
                                        "charset", NULL, NULL);
 
557
            if(charset && strucmp(charset, "us-ascii") != 0){
 
558
                CONV_TABLE *ct;
 
559
 
 
560
                /*
 
561
                 * There is a non-ascii charset, is there conversion happening?
 
562
                 */
 
563
                if(!(ct=conversion_table(charset, ps_global->posting_charmap)) || !ct->table){
 
564
                    reply.orig_charset = charset;
 
565
                    charset = NULL;
 
566
                }
 
567
            }
 
568
 
 
569
            if(charset)
 
570
              fs_give((void **) &charset);
 
571
        }
 
572
 
 
573
        if(env) {
 
574
            if(!(body = reply_body(pine_state->mail_stream, env, orig_body,
 
575
                                   msgno, NULL, msgtext, prefix,
 
576
                                   include_text, role, 1, &redraft_pos)))
 
577
               goto done_early;
 
578
        }
 
579
        else{
 
580
            q_status_message1(SM_ORDER,3,4,
 
581
                          _("Error fetching message %s. Can't reply to it."),
 
582
                              long2string(mn_get_cur(pine_state->msgmap)));
 
583
            goto done_early;
 
584
        }
 
585
    }
 
586
 
 
587
    /* fill in reply structure */
 
588
    reply.prefix        = prefix;
 
589
    reply.mailbox       = cpystr(pine_state->mail_stream->mailbox);
 
590
    reply.origmbox      = cpystr(pine_state->mail_stream->original_mailbox
 
591
                                    ? pine_state->mail_stream->original_mailbox
 
592
                                    : pine_state->mail_stream->mailbox);
 
593
    reply.data.uid.msgs = (imapuid_t *) fs_get((times + 1) * sizeof(imapuid_t));
 
594
    if(reply.data.uid.validity = pine_state->mail_stream->uid_validity){
 
595
        reply.flags = REPLY_UID;
 
596
        for(i = 0; i < times ; i++)
 
597
          reply.data.uid.msgs[i] = mail_uid(pine_state->mail_stream, seq[i]);
 
598
    }
 
599
    else{
 
600
        reply.flags = REPLY_MSGNO;
 
601
        for(i = 0; i < times ; i++)
 
602
          reply.data.uid.msgs[i] = seq[i];
 
603
    }
 
604
 
 
605
    reply.data.uid.msgs[i] = 0;                 /* tie off list */
 
606
 
 
607
#if     defined(DOS) && !defined(_WINDOWS)
 
608
    free((void *)reserve);
 
609
#endif
 
610
 
 
611
    /* partially formatted outgoing message */
 
612
    pine_send(outgoing, &body, _("COMPOSE MESSAGE REPLY"),
 
613
              role, fcc, &reply, redraft_pos, NULL, NULL, 0);
 
614
  done:
 
615
    rv++;
 
616
    pine_free_body(&body);
 
617
    if(reply.mailbox)
 
618
      fs_give((void **) &reply.mailbox);
 
619
    if(reply.origmbox)
 
620
      fs_give((void **) &reply.origmbox);
 
621
    if(reply.orig_charset)
 
622
      fs_give((void **) &reply.orig_charset);
 
623
    fs_give((void **) &reply.data.uid.msgs);
 
624
  done_early:
 
625
    if((STORE_S *) msgtext)
 
626
      gf_clear_so_writec((STORE_S *) msgtext);
 
627
 
 
628
    mail_free_envelope(&outgoing);
 
629
    mail_free_address(&saved_from);
 
630
    mail_free_address(&saved_to);
 
631
    mail_free_address(&saved_cc);
 
632
    mail_free_address(&saved_resent);
 
633
 
 
634
    fs_give((void **)&seq);
 
635
 
 
636
    if(prefix)
 
637
      fs_give((void **)&prefix);
 
638
 
 
639
    if(fcc)
 
640
      fs_give((void **) &fcc);
 
641
 
 
642
    free_redraft_pos(&redraft_pos);
 
643
    free_action(&role);
 
644
    return rv;
 
645
}
 
646
 
 
647
 
 
648
/*
 
649
 * Ask user to confirm role choice, or choose another role.
 
650
 *
 
651
 * Args    role -- A pointer into the pattern_h space at the default
 
652
 *                    role to use. This can't be a copy, the comparison
 
653
 *                    relies on it pointing at the actual role.
 
654
 *                    This arg is also used to return a pointer to the
 
655
 *                    chosen role.
 
656
 *
 
657
 * Returns   1 -- Yes, use role which is now in *role. This may not be
 
658
 *                the same as the role passed in and it may even be NULL.
 
659
 *           0 -- Cancel reply.
 
660
 */
 
661
int
 
662
confirm_role(long int rflags, ACTION_S **role)
 
663
{
 
664
    ACTION_S       *role_p = NULL;
 
665
    char            prompt[80], *prompt_fodder;
 
666
    int             cmd, done, ret = 1;
 
667
    void (*prev_screen)(struct pine *) = ps_global->prev_screen,
 
668
         (*redraw)(void) = ps_global->redrawer;
 
669
    PAT_S          *curpat, *pat;
 
670
    PAT_STATE       pstate;
 
671
    HelpType        help;
 
672
    ESCKEY_S        ekey[4];
 
673
 
 
674
    if(!nonempty_patterns(ROLE_DO_ROLES, &pstate) || !role)
 
675
      return(ret);
 
676
    
 
677
    /*
 
678
     * If this is a reply or forward and the role doesn't require confirmation,
 
679
     * then we just return with what was passed in.
 
680
     */
 
681
    if(((rflags & ROLE_REPLY) &&
 
682
        *role && (*role)->repl_type == ROLE_REPL_NOCONF) ||
 
683
       ((rflags & ROLE_FORWARD) &&
 
684
        *role && (*role)->forw_type == ROLE_FORW_NOCONF) ||
 
685
       ((rflags & ROLE_COMPOSE) &&
 
686
        *role && (*role)->comp_type == ROLE_COMP_NOCONF) ||
 
687
       (!*role && F_OFF(F_ROLE_CONFIRM_DEFAULT, ps_global) &&
 
688
         !(rflags & ROLE_DEFAULTOK)))
 
689
      return(ret);
 
690
 
 
691
    /*
 
692
     * Check that there is at least one role available. This is among all
 
693
     * roles, not just the reply roles or just the forward roles. That's
 
694
     * because we have ^T take us to all the roles, not the category-specific
 
695
     * roles.
 
696
     */
 
697
    if(!(pat = last_pattern(&pstate)))
 
698
      return(ret);
 
699
    
 
700
    ekey[0].ch    = 'y';
 
701
    ekey[0].rval  = 'y';
 
702
 
 
703
    ekey[1].ch    = 'n';
 
704
    ekey[1].rval  = 'n';
 
705
 
 
706
    ekey[2].ch    = ctrl('T');
 
707
    ekey[2].rval  = 2;
 
708
    ekey[2].name  = "^T";
 
709
 
 
710
    ekey[3].ch    = -1;
 
711
 
 
712
    /* check for more than one role available (or no role set) */
 
713
    if(pat == first_pattern(&pstate) && *role)  /* no ^T */
 
714
      ekey[2].ch    = -1;
 
715
    
 
716
    /* Setup default */
 
717
    curpat = NULL;
 
718
    if(*role){
 
719
        for(pat = first_pattern(&pstate);
 
720
            pat;
 
721
            pat = next_pattern(&pstate)){
 
722
            if(pat->action == *role){
 
723
                curpat = pat;
 
724
                break;
 
725
            }
 
726
        }
 
727
    }
 
728
 
 
729
    if(rflags & ROLE_REPLY)
 
730
      prompt_fodder = _("Reply");
 
731
    else if(rflags & ROLE_FORWARD)
 
732
      prompt_fodder = _("Forward");
 
733
    else
 
734
      prompt_fodder = _("Compose");
 
735
 
 
736
    done = 0;
 
737
    while(!done){
 
738
        if(curpat){
 
739
            char buf[100];
 
740
 
 
741
            help = h_role_confirm;
 
742
            ekey[0].name  = "Y";
 
743
            ekey[0].label = N_("Yes");
 
744
            ekey[1].name  = "N";
 
745
            ekey[1].label = N_("No, use default settings");
 
746
            ekey[2].label = N_("To Select Alternate Role");
 
747
            if(curpat->patgrp && curpat->patgrp->nick)
 
748
              /* TRANSLATORS: This is something like Use role <nickname of role> for Reply? */
 
749
              snprintf(prompt, sizeof(prompt), _("Use role \"%s\" for %s? "),
 
750
                      short_str(curpat->patgrp->nick, buf, sizeof(buf), 50, MidDots),
 
751
                      prompt_fodder);
 
752
            else
 
753
              snprintf(prompt, sizeof(prompt),
 
754
                      _("Use role \"<a role without a nickname>\" for %s? "),
 
755
                      prompt_fodder);
 
756
        }
 
757
        else{
 
758
            help = h_norole_confirm;
 
759
            ekey[0].name  = "Ret";
 
760
            ekey[0].label = prompt_fodder;
 
761
            ekey[1].name  = "";
 
762
            ekey[1].label = "";
 
763
            ekey[2].label = N_("To Select Role");
 
764
            snprintf(prompt, sizeof(prompt),
 
765
                    _("Press Return to %s using no role, or ^T to select a role "),
 
766
                    prompt_fodder);
 
767
        }
 
768
 
 
769
        prompt[sizeof(prompt)-1] = '\0';
 
770
 
 
771
        cmd = radio_buttons(prompt, -FOOTER_ROWS(ps_global), ekey,
 
772
                            'y', 'x', help, RB_NORM);
 
773
 
 
774
        switch(cmd){
 
775
          case 'y':                                     /* Accept */
 
776
            done++;
 
777
            *role = curpat ? curpat->action : NULL;
 
778
            break;
 
779
 
 
780
          case 'x':                                     /* Cancel */
 
781
            ret = 0;
 
782
            /* fall through */
 
783
 
 
784
          case 'n':                                     /* NoRole */
 
785
            done++;
 
786
            *role = NULL;
 
787
            break;
 
788
 
 
789
          case 2:                                       /* ^T */
 
790
            if(role_select_screen(ps_global, &role_p, 0) >= 0){
 
791
                if(role_p){
 
792
                    for(pat = first_pattern(&pstate);
 
793
                        pat;
 
794
                        pat = next_pattern(&pstate)){
 
795
                        if(pat->action == role_p){
 
796
                            curpat = pat;
 
797
                            break;
 
798
                        }
 
799
                    }
 
800
                }
 
801
                else
 
802
                  curpat = NULL;
 
803
            }
 
804
 
 
805
            ClearBody();
 
806
            ps_global->mangled_body = 1;
 
807
            ps_global->prev_screen = prev_screen;
 
808
            ps_global->redrawer = redraw;
 
809
            break;
 
810
        }
 
811
    }
 
812
 
 
813
    return(ret);
 
814
}
 
815
 
 
816
 
 
817
/*
 
818
 * reply_to_all_query - Ask user about replying to all recipients
 
819
 *
 
820
 * Returns:  -1 if cancel, 0 otherwise
 
821
 *           by reference: flagp
 
822
 */
 
823
int
 
824
reply_to_all_query(int *flagp)
 
825
{
 
826
    switch(want_to("Reply to all recipients",
 
827
                   'n', 'x', NO_HELP, WT_SEQ_SENSITIVE)){
 
828
      case 'x' :
 
829
        return(-1);
 
830
 
 
831
      case 'y' :                /* set reply-all bit */
 
832
        (*flagp) |= RSF_FORCE_REPLY_ALL;
 
833
        break;
 
834
 
 
835
      case 'n' :                /* clear reply-all bit */
 
836
        (*flagp) &= ~RSF_FORCE_REPLY_ALL;
 
837
        break;
 
838
    }
 
839
 
 
840
    return(0);
 
841
}
 
842
 
 
843
 
 
844
/*
 
845
 * reply_using_replyto_query - Ask user about replying with reply-to value
 
846
 *
 
847
 * Returns:  'y' if yes
 
848
 *           'x' if cancel
 
849
 */
 
850
int
 
851
reply_using_replyto_query(void)
 
852
{
 
853
    return(want_to("Use \"Reply-To:\" address instead of \"From:\" address",
 
854
                   'y', 'x', NO_HELP,WT_SEQ_SENSITIVE));
 
855
}
 
856
 
 
857
 
 
858
/*
 
859
 * reply_text_query - Ask user about replying with text...
 
860
 *
 
861
 * Returns:  1 if include the text
 
862
 *           0 if we're NOT to include the text
 
863
 *          -1 on cancel or error
 
864
 */
 
865
int
 
866
reply_text_query(struct pine *ps, long int many, char **prefix)
 
867
{
 
868
    int ret, edited = 0;
 
869
    static ESCKEY_S rtq_opts[] = {
 
870
        {'y', 'y', "Y", N_("Yes")},
 
871
        {'n', 'n', "N", N_("No")},
 
872
        {-1, 0, NULL, NULL},                      /* may be overridden below */
 
873
        {-1, 0, NULL, NULL}
 
874
    };
 
875
 
 
876
    if(F_ON(F_AUTO_INCLUDE_IN_REPLY, ps)
 
877
       && F_OFF(F_ENABLE_EDIT_REPLY_INDENT, ps))
 
878
      return(1);
 
879
 
 
880
    while(1){
 
881
        if(many > 1L)
 
882
          /* TRANSLATORS: The final three %s's can probably be safely ignored */
 
883
          snprintf(tmp_20k_buf, SIZEOF_20KBUF, _("Include %s original messages in Reply%s%s%s? "),
 
884
                comatose(many),
 
885
                F_ON(F_ENABLE_EDIT_REPLY_INDENT, ps) ? " (using \"" : "",
 
886
                F_ON(F_ENABLE_EDIT_REPLY_INDENT, ps) ? *prefix : "",
 
887
                F_ON(F_ENABLE_EDIT_REPLY_INDENT, ps) ? "\")" : "");
 
888
        else
 
889
          snprintf(tmp_20k_buf, SIZEOF_20KBUF, _("Include original message in Reply%s%s%s? "),
 
890
                F_ON(F_ENABLE_EDIT_REPLY_INDENT, ps) ? " (using \"" : "",
 
891
                F_ON(F_ENABLE_EDIT_REPLY_INDENT, ps) ? *prefix : "",
 
892
                F_ON(F_ENABLE_EDIT_REPLY_INDENT, ps) ? "\")" : "");
 
893
 
 
894
        if(F_ON(F_ENABLE_EDIT_REPLY_INDENT, ps)){
 
895
            rtq_opts[2].ch    = ctrl('R');
 
896
            rtq_opts[2].rval  = 'r';
 
897
            rtq_opts[2].name  = "^R";
 
898
            rtq_opts[2].label = N_("Edit Indent String");
 
899
        }
 
900
        else
 
901
          rtq_opts[2].ch    = -1;
 
902
 
 
903
        switch(ret = radio_buttons(tmp_20k_buf, 
 
904
                                   ps->ttyo->screen_rows > 4
 
905
                                     ? -FOOTER_ROWS(ps_global) : -1,
 
906
                                   rtq_opts,
 
907
                                   (edited || F_ON(F_AUTO_INCLUDE_IN_REPLY, ps))
 
908
                                       ? 'y' : 'n',
 
909
                                   'x', NO_HELP, RB_SEQ_SENSITIVE)){
 
910
          case 'x':
 
911
            cmd_cancelled("Reply");
 
912
            return(-1);
 
913
 
 
914
          case 'r':
 
915
            if(prefix && *prefix){
 
916
                int  done = 0;
 
917
                char buf[64];
 
918
                int  flags;
 
919
 
 
920
                while(!done){
 
921
                    strncpy(buf, *prefix, sizeof(buf)-1);
 
922
                    buf[sizeof(buf)-1] = '\0';
 
923
 
 
924
                    flags = OE_APPEND_CURRENT |
 
925
                            OE_KEEP_TRAILING_SPACE |
 
926
                            OE_DISALLOW_HELP |
 
927
                            OE_SEQ_SENSITIVE;
 
928
 
 
929
                    switch(optionally_enter(buf, ps->ttyo->screen_rows > 4
 
930
                                            ? -FOOTER_ROWS(ps_global) : -1,
 
931
                                            0, sizeof(buf), "Reply prefix : ", 
 
932
                                            NULL, NO_HELP, &flags)){
 
933
                      case 0:           /* entry successful, continue */
 
934
                        if(flags & OE_USER_MODIFIED){
 
935
                            fs_give((void **)prefix);
 
936
                            *prefix = removing_quotes(cpystr(buf));
 
937
                            edited = 1;
 
938
                        }
 
939
 
 
940
                        done++;
 
941
                        break;
 
942
 
 
943
                      case 1:
 
944
                        cmd_cancelled("Reply");
 
945
 
 
946
                      case -1:
 
947
                        return(-1);
 
948
 
 
949
                      case 4:
 
950
                        EndInverse();
 
951
                        ClearScreen();
 
952
                        redraw_titlebar();
 
953
                        if(ps_global->redrawer != NULL)
 
954
                          (*ps_global->redrawer)();
 
955
 
 
956
                        redraw_keymenu();
 
957
                        break;
 
958
 
 
959
                      case 3:
 
960
                        break;
 
961
 
 
962
                      case 2:
 
963
                      default:
 
964
                        q_status_message(SM_ORDER, 3, 4,
 
965
                                 "Programmer botch in reply_text_query()");
 
966
                        return(-1);
 
967
                    }
 
968
                }
 
969
            }
 
970
 
 
971
            break;
 
972
 
 
973
          case 'y':
 
974
            return(1);
 
975
 
 
976
          case 'n':
 
977
            return(0);
 
978
 
 
979
          default:
 
980
            q_status_message1(SM_ORDER, 3, 4,
 
981
                              "Invalid rval \'%s\'", pretty_command(ret));
 
982
            return(-1);
 
983
        }
 
984
    }
 
985
}
 
986
 
 
987
 
 
988
/*
 
989
 * reply_poster_followup - return TRUE if "followup-to" set to "poster"
 
990
 *
 
991
 * NOTE: queues status message indicating such
 
992
 */
 
993
int
 
994
reply_poster_followup(ENVELOPE *e)
 
995
{
 
996
    if(e && e->followup_to && !strucmp(e->followup_to, "poster")){
 
997
        q_status_message(SM_ORDER, 2, 3,
 
998
                         _("Replying to Poster as specified in \"Followup-To\""));
 
999
        return(1);
 
1000
    }
 
1001
 
 
1002
    return(0);
 
1003
}
 
1004
 
 
1005
 
 
1006
/*
 
1007
 * reply_news_test - Test given envelope for newsgroup data and copy
 
1008
 *                   it at the users request
 
1009
 *      RETURNS:
 
1010
 *           0  if error or cancel
 
1011
 *           1     reply via email
 
1012
 *           2     follow-up via news
 
1013
 *           3     do both
 
1014
 */
 
1015
int
 
1016
reply_news_test(ENVELOPE *env, ENVELOPE *outgoing)
 
1017
{
 
1018
    int    ret = 1;
 
1019
    static ESCKEY_S news_opt[] = { {'f', 'f', "F", N_("Follow-up")},
 
1020
                                   {'r', 'r', "R", N_("Reply")},
 
1021
                                   {'b', 'b', "B", N_("Both")},
 
1022
                                   {-1, 0, NULL, NULL} };
 
1023
 
 
1024
    if(env->newsgroups && *env->newsgroups && !reply_poster_followup(env))
 
1025
      /*
 
1026
       * Now that we know a newsgroups field is present, 
 
1027
       * ask if the user is posting a follow-up article...
 
1028
       */
 
1029
      switch(radio_buttons(
 
1030
             _("Follow-up to news group(s), Reply via email to author or Both? "),
 
1031
                           -FOOTER_ROWS(ps_global), news_opt, 'r', 'x',
 
1032
                           NO_HELP, RB_NORM)){
 
1033
        case 'r' :              /* Reply */
 
1034
          ret = 1;
 
1035
          break;
 
1036
 
 
1037
        case 'f' :              /* Follow-Up via news ONLY! */
 
1038
          ret = 2;
 
1039
          break;
 
1040
 
 
1041
        case 'b' :              /* BOTH */
 
1042
          ret = 3;
 
1043
          break;
 
1044
 
 
1045
        case 'x' :              /* cancel or unknown response */
 
1046
        default  :
 
1047
          cmd_cancelled("Reply");
 
1048
          ret = 0;
 
1049
          break;
 
1050
      }
 
1051
 
 
1052
    if(ret > 1){
 
1053
        if(env->followup_to){
 
1054
            q_status_message(SM_ORDER, 2, 3,
 
1055
                             _("Posting to specified Followup-To groups"));
 
1056
            outgoing->newsgroups = cpystr(env->followup_to);
 
1057
        }
 
1058
        else if(!outgoing->newsgroups)
 
1059
          outgoing->newsgroups = cpystr(env->newsgroups);
 
1060
        if(!IS_NEWS(ps_global->mail_stream))
 
1061
          q_status_message(SM_ORDER, 2, 3,
 
1062
 _("Replying to message that MAY or MAY NOT have been posted to newsgroup"));
 
1063
    }
 
1064
 
 
1065
    return(ret);
 
1066
}
 
1067
 
 
1068
 
 
1069
/*----------------------------------------------------------------------
 
1070
  Acquire the pinerc defined signature file
 
1071
  It is allocated here and freed by the caller.
 
1072
 
 
1073
          file -- use this file
 
1074
   prenewlines -- prefix the file contents with this many newlines
 
1075
  postnewlines -- postfix the file contents with this many newlines
 
1076
        is_sig -- this is a signature (not a template)
 
1077
  ----*/
 
1078
char *
 
1079
get_signature_file(char *file, int prenewlines, int postnewlines, int is_sig)
 
1080
{
 
1081
    char     *sig, *tmp_sig = NULL, sig_path[MAXPATH+1];
 
1082
    int       len, do_the_pipe_thang = 0;
 
1083
    long      sigsize = 0L, cntdown;
 
1084
 
 
1085
    sig_path[0] = '\0';
 
1086
    if(!signature_path(file, sig_path, MAXPATH))
 
1087
      return(NULL);
 
1088
 
 
1089
    dprint((5, "get_signature(%s)\n", sig_path));
 
1090
 
 
1091
    if(sig_path[(len=strlen(sig_path))-1] == '|'){
 
1092
        if(is_sig && F_ON(F_DISABLE_PIPES_IN_SIGS, ps_global)){
 
1093
            q_status_message(SM_ORDER | SM_DING, 3, 4,
 
1094
                         _("Pipes for signatures are administratively disabled"));
 
1095
            return(NULL);
 
1096
        }
 
1097
        else if(!is_sig && F_ON(F_DISABLE_PIPES_IN_TEMPLATES, ps_global)){
 
1098
            q_status_message(SM_ORDER | SM_DING, 3, 4,
 
1099
                         _("Pipes for templates are administratively disabled"));
 
1100
            return(NULL);
 
1101
        }
 
1102
            
 
1103
        sig_path[len-1] = '\0';
 
1104
        removing_trailing_white_space(sig_path);
 
1105
        do_the_pipe_thang++;
 
1106
    }
 
1107
 
 
1108
    if(!IS_REMOTE(sig_path) && ps_global->VAR_OPER_DIR &&
 
1109
       !in_dir(ps_global->VAR_OPER_DIR, sig_path)){
 
1110
        q_status_message2(SM_ORDER | SM_DING, 3, 4,
 
1111
                          /* TRANSLATORS: First arg is the directory name, second is
 
1112
                             the file user wants to read but can't. */
 
1113
                          _("Can't read file outside %s: %s"),
 
1114
                          ps_global->VAR_OPER_DIR, file);
 
1115
        
 
1116
        return(NULL);
 
1117
    }
 
1118
 
 
1119
    if(IS_REMOTE(sig_path) || can_access(sig_path, ACCESS_EXISTS) == 0){
 
1120
        if(do_the_pipe_thang){
 
1121
            if(can_access(sig_path, EXECUTE_ACCESS) == 0){
 
1122
                STORE_S  *store;
 
1123
                int       flags;
 
1124
                PIPE_S   *syspipe;
 
1125
                gf_io_t   pc, gc;
 
1126
                long      start;
 
1127
 
 
1128
                if((store = so_get(CharStar, NULL, EDIT_ACCESS)) != NULL){
 
1129
 
 
1130
                    flags = PIPE_READ | PIPE_STDERR | PIPE_NOSHELL;
 
1131
 
 
1132
                    start = time(0);
 
1133
 
 
1134
                    if(syspipe = open_system_pipe(sig_path, NULL, NULL, flags, 5,
 
1135
                                                  pipe_callback, pipe_report_error)){
 
1136
                        unsigned char c;
 
1137
                        char         *error, *q;
 
1138
 
 
1139
                        gf_set_so_writec(&pc, store);
 
1140
                        gf_set_readc(&gc, (void *)syspipe, 0, PipeStar);
 
1141
                        gf_filter_init();
 
1142
 
 
1143
                        if((error = gf_pipe(gc, pc)) != NULL){
 
1144
                            (void)close_system_pipe(&syspipe, NULL, NULL);
 
1145
                            gf_clear_so_writec(store);
 
1146
                            so_give(&store);
 
1147
                            q_status_message1(SM_ORDER | SM_DING, 3, 4,
 
1148
                                              _("Can't get file: %s"), error);
 
1149
                            return(NULL);
 
1150
                        }
 
1151
 
 
1152
                        if(close_system_pipe(&syspipe, NULL, NULL)){
 
1153
                            long now;
 
1154
 
 
1155
                            now = time(0);
 
1156
                            q_status_message2(SM_ORDER, 3, 4,
 
1157
                                    _("Error running program \"%s\"%s"),
 
1158
                                    file,
 
1159
                                    (now - start > 4) ? ": timed out" : "");
 
1160
                        }
 
1161
 
 
1162
                        gf_clear_so_writec(store);
 
1163
 
 
1164
                        /* rewind and count chars */
 
1165
                        so_seek(store, 0L, 0);
 
1166
                        while(so_readc(&c, store) && sigsize < 100000L)
 
1167
                          sigsize++;
 
1168
 
 
1169
                        /* allocate space */
 
1170
                        tmp_sig = fs_get((sigsize + 1) * sizeof(char));
 
1171
                        tmp_sig[0] = '\0';
 
1172
                        q = tmp_sig;
 
1173
 
 
1174
                        /* rewind and copy chars, no prenewlines... */
 
1175
                        so_seek(store, 0L, 0);
 
1176
                        cntdown = sigsize;
 
1177
                        while(so_readc(&c, store) && cntdown-- > 0L)
 
1178
                          *q++ = c;
 
1179
                        
 
1180
                        *q = '\0';
 
1181
                        so_give(&store);
 
1182
                    }
 
1183
                    else{
 
1184
                        so_give(&store);
 
1185
                        q_status_message1(SM_ORDER | SM_DING, 3, 4,
 
1186
                                     _("Error running program \"%s\""),
 
1187
                                     file);
 
1188
                    }
 
1189
                }
 
1190
                else
 
1191
                  q_status_message(SM_ORDER | SM_DING, 3, 4,
 
1192
                          "Error allocating space for sig or template program");
 
1193
            }
 
1194
            else
 
1195
              q_status_message1(SM_ORDER | SM_DING, 3, 4,
 
1196
                                /* TRANSLATORS: Arg is a program name */
 
1197
                                _("Can't execute \"%s\": Permission denied"),
 
1198
                                sig_path);
 
1199
        }
 
1200
        else if((IS_REMOTE(sig_path) &&
 
1201
                 (tmp_sig = read_remote_sigfile(sig_path))) ||
 
1202
                (tmp_sig = read_file(sig_path, READ_FROM_LOCALE)))
 
1203
          sigsize = strlen(tmp_sig);
 
1204
        else
 
1205
          q_status_message2(SM_ORDER | SM_DING, 3, 4,
 
1206
                            /* TRANSLATORS: First arg is error description, 2nd is
 
1207
                               filename */
 
1208
                            _("Error \"%s\" reading file \"%s\""),
 
1209
                            error_description(errno), sig_path);
 
1210
    }
 
1211
 
 
1212
    sig = get_signature_lit(tmp_sig, prenewlines, postnewlines, is_sig, 0);
 
1213
    if(tmp_sig)
 
1214
      fs_give((void **)&tmp_sig);
 
1215
 
 
1216
    return(sig);
 
1217
}
 
1218
 
 
1219
 
 
1220
 
 
1221
/*----------------------------------------------------------------------
 
1222
       Partially set up message to forward and pass off to composer/mailer
 
1223
 
 
1224
    Args: pine_state -- The usual pine structure
 
1225
 
 
1226
  Result: outgoing envelope and body created and passed off to composer/mailer
 
1227
 
 
1228
   Create the outgoing envelope for the mail being forwarded, which is 
 
1229
not much more than filling in the subject, and create the message body
 
1230
of the outgoing message which requires formatting the header from the
 
1231
envelope of the original messasge.
 
1232
  ----------------------------------------------------------------------*/
 
1233
int
 
1234
forward(struct pine *ps, ACTION_S *role_arg)
 
1235
{
 
1236
    char          *sig;
 
1237
    int            ret, forward_raw_body = 0, rv = 0;
 
1238
    long           msgno, j, totalmsgs, rflags;
 
1239
    ENVELOPE      *env, *outgoing;
 
1240
    BODY          *orig_body, *body = NULL;
 
1241
    REPLY_S        reply;
 
1242
    void          *msgtext = NULL;
 
1243
    gf_io_t        pc;
 
1244
    int            impl, template_len = 0;
 
1245
    PAT_STATE      dummy;
 
1246
    REDRAFT_POS_S *redraft_pos = NULL;
 
1247
    ACTION_S      *role = NULL, *nrole;
 
1248
#if     defined(DOS) && !defined(_WINDOWS)
 
1249
    char          *reserve;
 
1250
#endif
 
1251
 
 
1252
    dprint((4, "\n - forward -\n"));
 
1253
 
 
1254
    memset((void *)&reply, 0, sizeof(reply));
 
1255
    outgoing              = mail_newenvelope();
 
1256
    outgoing->message_id  = generate_message_id();
 
1257
 
 
1258
    if(ps_global->full_header == 2
 
1259
       && F_ON(F_ENABLE_FULL_HDR_AND_TEXT, ps_global))
 
1260
      forward_raw_body = 1;
 
1261
 
 
1262
    if((totalmsgs = mn_total_cur(ps->msgmap)) > 1L){
 
1263
        snprintf(tmp_20k_buf, SIZEOF_20KBUF, "%s forwarded messages...", comatose(totalmsgs));
 
1264
        tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
 
1265
        outgoing->subject = cpystr(tmp_20k_buf);
 
1266
    }
 
1267
    else{
 
1268
        /*---------- Get the envelope of message we're forwarding ------*/
 
1269
        msgno = mn_m2raw(ps->msgmap, mn_get_cur(ps->msgmap));
 
1270
        if(!((env = pine_mail_fetchstructure(ps->mail_stream, msgno, NULL))
 
1271
             && (outgoing->subject = forward_subject(env, 0)))){
 
1272
            q_status_message1(SM_ORDER,3,4,
 
1273
                          _("Error fetching message %s. Can't forward it."),
 
1274
                              long2string(msgno));
 
1275
            goto clean;
 
1276
        }
 
1277
    }
 
1278
 
 
1279
    /*
 
1280
     * as with all text bound for the composer, build it in 
 
1281
     * a storage object of the type it understands...
 
1282
     */
 
1283
    if((msgtext = (void *)so_get(PicoText, NULL, EDIT_ACCESS)) == NULL){
 
1284
        q_status_message(SM_ORDER | SM_DING, 3, 4,
 
1285
                         _("Error allocating message text"));
 
1286
        goto clean;
 
1287
    }
 
1288
 
 
1289
    ret = (totalmsgs > 1L)
 
1290
           ? want_to(_("Forward messages as a MIME digest"), 'y', 'x',
 
1291
                     NO_HELP, WT_SEQ_SENSITIVE)
 
1292
           : (ps->full_header == 2)
 
1293
             ? want_to(_("Forward message as an attachment"), 'n', 'x',
 
1294
                       NO_HELP, WT_SEQ_SENSITIVE)
 
1295
             : 0;
 
1296
 
 
1297
    if(ret == 'x'){
 
1298
        cmd_cancelled("Forward");
 
1299
        so_give((STORE_S **)&msgtext);
 
1300
        goto clean;
 
1301
    }
 
1302
 
 
1303
    /* Setup possible role */
 
1304
    if(role_arg)
 
1305
      role = copy_action(role_arg);
 
1306
 
 
1307
    if(!role){
 
1308
        rflags = ROLE_FORWARD;
 
1309
        if(nonempty_patterns(rflags, &dummy)){
 
1310
            /* setup default role */
 
1311
            nrole = NULL;
 
1312
            j = mn_first_cur(ps->msgmap);
 
1313
            do {
 
1314
                role = nrole;
 
1315
                nrole = set_role_from_msg(ps, rflags,
 
1316
                                          mn_m2raw(ps->msgmap, j), NULL);
 
1317
            } while(nrole && (!role || nrole == role)
 
1318
                    && (j=mn_next_cur(ps->msgmap)) > 0L);
 
1319
 
 
1320
            if(!role || nrole == role)
 
1321
              role = nrole;
 
1322
            else
 
1323
              role = NULL;
 
1324
 
 
1325
            if(confirm_role(rflags, &role))
 
1326
              role = combine_inherited_role(role);
 
1327
            else{                               /* cancel reply */
 
1328
                role = NULL;
 
1329
                cmd_cancelled("Forward");
 
1330
                so_give((STORE_S **)&msgtext);
 
1331
                goto clean;
 
1332
            }
 
1333
        }
 
1334
    }
 
1335
 
 
1336
    if(role)
 
1337
      q_status_message1(SM_ORDER, 3, 4,
 
1338
                        _("Forwarding using role \"%s\""), role->nick);
 
1339
 
 
1340
    if(role && role->template){
 
1341
        char *filtered;
 
1342
 
 
1343
        impl = 1;
 
1344
        filtered = detoken(role, (totalmsgs == 1L) ? env : NULL,
 
1345
                           0, 0, 0, &redraft_pos, &impl);
 
1346
        if(filtered){
 
1347
            if(*filtered){
 
1348
                so_puts((STORE_S *)msgtext, filtered);
 
1349
                if(impl == 1)
 
1350
                  template_len = strlen(filtered);
 
1351
            }
 
1352
            
 
1353
            fs_give((void **)&filtered);
 
1354
        }
 
1355
    }
 
1356
    else
 
1357
      impl = 1;
 
1358
     
 
1359
    if(sig = detoken(role, NULL, 2, 0, 1, &redraft_pos, &impl)){
 
1360
        if(impl == 2)
 
1361
          redraft_pos->offset += template_len;
 
1362
 
 
1363
        so_puts((STORE_S *)msgtext, *sig ? sig : NEWLINE);
 
1364
 
 
1365
        fs_give((void **)&sig);
 
1366
    }
 
1367
    else
 
1368
      so_puts((STORE_S *)msgtext, NEWLINE);
 
1369
 
 
1370
    gf_set_so_writec(&pc, (STORE_S *)msgtext);
 
1371
 
 
1372
#if     defined(DOS) && !defined(_WINDOWS)
 
1373
#if     defined(LWP) || defined(PCTCP) || defined(PCNFS)
 
1374
#define IN_RESERVE      8192
 
1375
#else
 
1376
#define IN_RESERVE      16384
 
1377
#endif
 
1378
    if((reserve=(char *)malloc(IN_RESERVE)) == NULL){
 
1379
        gf_clear_so_writec((STORE_S *) msgtext);
 
1380
        so_give((STORE_S **)&msgtext);
 
1381
        q_status_message(SM_ORDER | SM_DING, 3, 4,
 
1382
                         _("Insufficient memory for message text"));
 
1383
        goto clean;
 
1384
    }
 
1385
#endif
 
1386
 
 
1387
    /*
 
1388
     * If we're forwarding multiple messages *or* the forward-as-mime
 
1389
     * is turned on and the users wants it done that way, package things
 
1390
     * up...
 
1391
     */
 
1392
    if(ret == 'y'){                     /* attach message[s]!!! */
 
1393
        PART **pp;
 
1394
        long   totalsize = 0L;
 
1395
 
 
1396
        /*---- New Body to start with ----*/
 
1397
        body       = mail_newbody();
 
1398
        body->type = TYPEMULTIPART;
 
1399
 
 
1400
        /*---- The TEXT part/body ----*/
 
1401
        body->nested.part                       = mail_newbody_part();
 
1402
        body->nested.part->body.type            = TYPETEXT;
 
1403
        body->nested.part->body.contents.text.data = msgtext;
 
1404
 
 
1405
        if(totalmsgs > 1L){
 
1406
            /*---- The MULTIPART/DIGEST part ----*/
 
1407
            body->nested.part->next               = mail_newbody_part();
 
1408
            body->nested.part->next->body.type    = TYPEMULTIPART;
 
1409
            body->nested.part->next->body.subtype = cpystr("Digest");
 
1410
            snprintf(tmp_20k_buf, SIZEOF_20KBUF, "Digest of %s messages", comatose(totalmsgs));
 
1411
            tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
 
1412
            body->nested.part->next->body.description = cpystr(tmp_20k_buf);
 
1413
            pp = &(body->nested.part->next->body.nested.part);
 
1414
        }
 
1415
        else
 
1416
          pp = &(body->nested.part->next);
 
1417
 
 
1418
        /*---- The Message body subparts ----*/
 
1419
        for(msgno = mn_first_cur(ps->msgmap);
 
1420
            msgno > 0L;
 
1421
            msgno = mn_next_cur(ps->msgmap)){
 
1422
 
 
1423
            msgno = mn_m2raw(ps->msgmap, msgno);
 
1424
            env   = pine_mail_fetchstructure(ps->mail_stream, msgno, NULL);
 
1425
 
 
1426
            if(forward_mime_msg(ps->mail_stream,msgno,NULL,env,pp,msgtext)){
 
1427
                totalsize += (*pp)->body.size.bytes;
 
1428
                pp = &((*pp)->next);
 
1429
            }
 
1430
            else
 
1431
            goto bomb;
 
1432
        }
 
1433
 
 
1434
        if(totalmsgs > 1L)
 
1435
          body->nested.part->next->body.size.bytes = totalsize;
 
1436
    }
 
1437
    else if(totalmsgs > 1L){
 
1438
        int                     warned = 0;
 
1439
        body                  = mail_newbody();
 
1440
        body->type            = TYPETEXT;
 
1441
        body->contents.text.data = msgtext;
 
1442
        env                   = NULL;
 
1443
 
 
1444
        for(msgno = mn_first_cur(ps->msgmap);
 
1445
            msgno > 0L;
 
1446
            msgno = mn_next_cur(ps->msgmap)){
 
1447
 
 
1448
            if(env){                    /* put 2 between messages */
 
1449
                gf_puts(NEWLINE, pc);
 
1450
                gf_puts(NEWLINE, pc);
 
1451
            }
 
1452
 
 
1453
            /*--- Grab current envelope ---*/
 
1454
            env = pine_mail_fetchstructure(ps->mail_stream,
 
1455
                                           mn_m2raw(ps->msgmap, msgno),
 
1456
                                           &orig_body);
 
1457
            if(!env || !orig_body){
 
1458
                q_status_message1(SM_ORDER,3,4,
 
1459
                           _("Error fetching message %s. Can't forward it."),
 
1460
                               long2string(msgno));
 
1461
                goto bomb;
 
1462
            }
 
1463
 
 
1464
            if(orig_body == NULL || orig_body->type == TYPETEXT || forward_raw_body) {
 
1465
                forward_delimiter(pc);
 
1466
                reply_forward_header(ps->mail_stream,
 
1467
                                     mn_m2raw(ps->msgmap, msgno),
 
1468
                                     NULL, env, pc, "");
 
1469
 
 
1470
                if(!get_body_part_text(ps->mail_stream, forward_raw_body ? NULL : orig_body,
 
1471
                                       mn_m2raw(ps->msgmap, msgno),
 
1472
                                       forward_raw_body ? NULL : "1", 0L, pc, NULL, NULL))
 
1473
                  goto bomb;
 
1474
            } else if(orig_body->type == TYPEMULTIPART) {
 
1475
                if(!warned++)
 
1476
                  q_status_message(SM_ORDER,3,7,
 
1477
                    _("WARNING!  Attachments not included in multiple forward."));
 
1478
 
 
1479
                if(orig_body->nested.part &&
 
1480
                   orig_body->nested.part->body.type == TYPETEXT) {
 
1481
                    /*---- First part of the message is text -----*/
 
1482
                    forward_delimiter(pc);
 
1483
                    reply_forward_header(ps->mail_stream,
 
1484
                                         mn_m2raw(ps->msgmap,msgno),
 
1485
                                         NULL, env, pc, "");
 
1486
 
 
1487
                    if(!get_body_part_text(ps->mail_stream,
 
1488
                                           &orig_body->nested.part->body,
 
1489
                                           mn_m2raw(ps->msgmap, msgno),
 
1490
                                           "1", 0L, pc, NULL, NULL))
 
1491
                      goto bomb;
 
1492
                } else {
 
1493
                    q_status_message(SM_ORDER,0,3,
 
1494
                                     _("Multipart with no leading text part!"));
 
1495
                }
 
1496
            } else {
 
1497
                /*---- Single non-text message of some sort ----*/
 
1498
                q_status_message(SM_ORDER,0,3,
 
1499
                                 _("Non-text message not included!"));
 
1500
            }
 
1501
        }
 
1502
    }
 
1503
    else if(!((env = pine_mail_fetchstructure(ps->mail_stream, msgno,
 
1504
                                              &orig_body))
 
1505
              && (body = forward_body(ps->mail_stream, env, orig_body, msgno,
 
1506
                                      NULL, msgtext,
 
1507
                                      FWD_NONE)))){
 
1508
        q_status_message1(SM_ORDER,3,4,
 
1509
                      _("Error fetching message %s. Can't forward it."),
 
1510
                          long2string(msgno));
 
1511
        goto clean;
 
1512
    }
 
1513
 
 
1514
    if(ret != 'y' && totalmsgs == 1L && orig_body){
 
1515
        char *charset;
 
1516
 
 
1517
        charset = rfc2231_get_param(orig_body->parameter,
 
1518
                                    "charset", NULL, NULL);
 
1519
        if(charset && strucmp(charset, "us-ascii") != 0){
 
1520
            CONV_TABLE *ct;
 
1521
 
 
1522
            /*
 
1523
             * There is a non-ascii charset, is there conversion happening?
 
1524
             */
 
1525
            if(!(ct=conversion_table(charset, ps_global->posting_charmap)) || !ct->table){
 
1526
                reply.orig_charset = charset;
 
1527
                charset = NULL;
 
1528
            }
 
1529
        }
 
1530
 
 
1531
        if(charset)
 
1532
          fs_give((void **) &charset);
 
1533
 
 
1534
        if(reply.orig_charset)
 
1535
          reply.flags = REPLY_FORW;
 
1536
    }
 
1537
 
 
1538
#if     defined(DOS) && !defined(_WINDOWS)
 
1539
    free((void *)reserve);
 
1540
#endif
 
1541
    pine_send(outgoing, &body, "FORWARD MESSAGE",
 
1542
              role, NULL, reply.flags ? &reply : NULL, redraft_pos,
 
1543
              NULL, NULL, FALSE);
 
1544
    rv++;
 
1545
 
 
1546
  clean:
 
1547
    if(body)
 
1548
      pine_free_body(&body);
 
1549
 
 
1550
    if((STORE_S *) msgtext)
 
1551
      gf_clear_so_writec((STORE_S *) msgtext);
 
1552
 
 
1553
    mail_free_envelope(&outgoing);
 
1554
    free_redraft_pos(&redraft_pos);
 
1555
    free_action(&role);
 
1556
 
 
1557
    if(reply.orig_charset)
 
1558
      fs_give((void **)&reply.orig_charset);
 
1559
 
 
1560
    return rv;
 
1561
 
 
1562
  bomb:
 
1563
#if     defined(DOS) && !defined(WIN32)
 
1564
    mail_parameters(ps->mail_stream, SET_GETS, (void *) NULL);
 
1565
    append_file = NULL;
 
1566
    mail_gc(ps->mail_stream, GC_TEXTS);
 
1567
#endif
 
1568
    q_status_message(SM_ORDER | SM_DING, 4, 5,
 
1569
                   _("Error fetching message contents.  Can't forward message."));
 
1570
    goto clean;
 
1571
}
 
1572
 
 
1573
 
 
1574
/*----------------------------------------------------------------------
 
1575
       Partially set up message to forward and pass off to composer/mailer
 
1576
 
 
1577
    Args: pine_state -- The usual pine structure
 
1578
          message    -- The MESSAGECACHE of entry to reply to 
 
1579
 
 
1580
  Result: outgoing envelope and body created and passed off to composer/mailer
 
1581
 
 
1582
   Create the outgoing envelope for the mail being forwarded, which is 
 
1583
not much more than filling in the subject, and create the message body
 
1584
of the outgoing message which requires formatting the header from the
 
1585
envelope of the original messasge.
 
1586
  ----------------------------------------------------------------------*/
 
1587
void
 
1588
forward_text(struct pine *pine_state, void *text, SourceType source)
 
1589
{
 
1590
    ENVELOPE *env;
 
1591
    BODY     *body;
 
1592
    gf_io_t   pc, gc;
 
1593
    STORE_S  *msgtext;
 
1594
    char     *enc_error, *sig;
 
1595
    ACTION_S *role = NULL;
 
1596
    PAT_STATE dummy;
 
1597
    long      rflags = ROLE_COMPOSE;
 
1598
 
 
1599
    if(msgtext = so_get(PicoText, NULL, EDIT_ACCESS)){
 
1600
        env                   = mail_newenvelope();
 
1601
        env->message_id       = generate_message_id();
 
1602
        body                  = mail_newbody();
 
1603
        body->type            = TYPETEXT;
 
1604
        body->contents.text.data = (void *) msgtext;
 
1605
 
 
1606
        if(nonempty_patterns(rflags, &dummy)){
 
1607
            /*
 
1608
             * This is really more like Compose, even though it
 
1609
             * is called Forward.
 
1610
             */
 
1611
            if(confirm_role(rflags, &role))
 
1612
              role = combine_inherited_role(role);
 
1613
            else{                       /* cancel */
 
1614
                cmd_cancelled("Composition");
 
1615
                display_message('x');
 
1616
                mail_free_envelope(&env);
 
1617
                pine_free_body(&body);
 
1618
                return;
 
1619
            }
 
1620
        }
 
1621
 
 
1622
        if(role)
 
1623
          q_status_message1(SM_ORDER, 3, 4, _("Composing using role \"%s\""),
 
1624
                            role->nick);
 
1625
 
 
1626
        sig = detoken(role, NULL, 2, 0, 1, NULL, NULL);
 
1627
        so_puts(msgtext, (sig && *sig) ? sig : NEWLINE);
 
1628
        so_puts(msgtext, NEWLINE);
 
1629
        so_puts(msgtext, "----- Included text -----");
 
1630
        so_puts(msgtext, NEWLINE);
 
1631
        if(sig)
 
1632
          fs_give((void **)&sig);
 
1633
 
 
1634
        gf_filter_init();
 
1635
        gf_set_so_writec(&pc, msgtext);
 
1636
        gf_set_readc(&gc,text,(source == CharStar) ? strlen((char *)text) : 0L,
 
1637
                     source);
 
1638
 
 
1639
        if((enc_error = gf_pipe(gc, pc)) == NULL){
 
1640
            pine_send(env, &body, "SEND MESSAGE", role, NULL, NULL, NULL,
 
1641
                      NULL, NULL, FALSE);
 
1642
            pine_state->mangled_screen = 1;
 
1643
        }
 
1644
        else{
 
1645
            q_status_message1(SM_ORDER | SM_DING, 3, 5,
 
1646
                              _("Error reading text \"%s\""),enc_error);
 
1647
            display_message('x');
 
1648
        }
 
1649
 
 
1650
        gf_clear_so_writec(msgtext);
 
1651
        mail_free_envelope(&env);
 
1652
        pine_free_body(&body);
 
1653
    }
 
1654
    else {
 
1655
        q_status_message(SM_ORDER | SM_DING, 3, 4,
 
1656
                         _("Error allocating message text"));
 
1657
        display_message('x');
 
1658
    }
 
1659
 
 
1660
    free_action(&role);
 
1661
}
 
1662
 
 
1663
 
 
1664
/*----------------------------------------------------------------------
 
1665
       Partially set up message to resend and pass off to mailer
 
1666
 
 
1667
    Args: pine_state -- The usual pine structure
 
1668
 
 
1669
  Result: outgoing envelope and body created and passed off to mailer
 
1670
 
 
1671
   Create the outgoing envelope for the mail being resent, which is 
 
1672
not much more than filling in the subject, and create the message body
 
1673
of the outgoing message which requires formatting the header from the
 
1674
envelope of the original messasge.
 
1675
  ----------------------------------------------------------------------*/
 
1676
int
 
1677
bounce(struct pine *pine_state, ACTION_S *role)
 
1678
{
 
1679
    ENVELOPE      *env;
 
1680
    long           msgno, rawno;
 
1681
    char          *save_to = NULL, **save_toptr = NULL, *errstr = NULL,
 
1682
                  *prmpt_who = NULL, *prmpt_cnf = NULL;
 
1683
 
 
1684
    dprint((4, "\n - bounce -\n"));
 
1685
 
 
1686
    if(mn_total_cur(pine_state->msgmap) > 1L){
 
1687
        save_toptr = &save_to;
 
1688
        snprintf(tmp_20k_buf, SIZEOF_20KBUF, _("BOUNCE (redirect) %d messages to : "),
 
1689
                mn_total_cur(pine_state->msgmap));
 
1690
        tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
 
1691
        prmpt_who = cpystr(tmp_20k_buf);
 
1692
        snprintf(tmp_20k_buf, SIZEOF_20KBUF, _("Send %d messages "),
 
1693
                mn_total_cur(pine_state->msgmap));
 
1694
        tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
 
1695
        prmpt_cnf = cpystr(tmp_20k_buf);
 
1696
    }
 
1697
 
 
1698
    for(msgno = mn_first_cur(pine_state->msgmap);
 
1699
        msgno > 0L;
 
1700
        msgno = mn_next_cur(pine_state->msgmap)){
 
1701
 
 
1702
        rawno = mn_m2raw(pine_state->msgmap, msgno);
 
1703
        if(env = pine_mail_fetchstructure(pine_state->mail_stream, rawno, NULL))
 
1704
          errstr = bounce_msg(pine_state->mail_stream, rawno, NULL, role,
 
1705
                              save_toptr, env->subject, prmpt_who, prmpt_cnf);
 
1706
        else
 
1707
          errstr = _("Can't fetch Subject for Bounce");
 
1708
 
 
1709
 
 
1710
        if(errstr){
 
1711
            if(*errstr)
 
1712
              q_status_message(SM_ORDER | SM_DING, 4, 7, errstr);
 
1713
 
 
1714
            break;
 
1715
        }
 
1716
    }
 
1717
 
 
1718
    if(save_to)
 
1719
      fs_give((void **)&save_to);
 
1720
 
 
1721
    if(prmpt_who)
 
1722
      fs_give((void **) &prmpt_who);
 
1723
 
 
1724
    if(prmpt_cnf)
 
1725
      fs_give((void **) &prmpt_cnf);
 
1726
 
 
1727
    return(errstr ? 0 : 1);
 
1728
}
 
1729
 
 
1730
 
 
1731
 
 
1732
char *
 
1733
bounce_msg(MAILSTREAM *stream,
 
1734
           long int rawno,
 
1735
           char *part,
 
1736
           ACTION_S *role,
 
1737
           char **to,
 
1738
           char *subject,
 
1739
           char *pmt_who,
 
1740
           char *pmt_cnf)
 
1741
{
 
1742
    char     *errstr = NULL;
 
1743
    int       was_seen = -1;
 
1744
    ENVELOPE *outgoing;
 
1745
    BODY     *body = NULL;
 
1746
    MESSAGECACHE *mc;
 
1747
 
 
1748
    if((errstr = bounce_msg_body(stream, rawno, part, to, subject, &outgoing, &body, &was_seen)) == NULL){
 
1749
        if(pine_simple_send(outgoing, &body, role, pmt_who, pmt_cnf, to,
 
1750
                            !(to && *to) ? SS_PROMPTFORTO : 0) < 0){
 
1751
            errstr = "";                /* p_s_s() better have explained! */
 
1752
            /* clear seen flag */
 
1753
            if(was_seen == 0 && rawno > 0L
 
1754
               && stream && rawno <= stream->nmsgs
 
1755
               && (mc = mail_elt(stream,  rawno)) && mc->seen)
 
1756
              mail_flag(stream, long2string(rawno), "\\SEEN", 0);
 
1757
        }
 
1758
    }
 
1759
 
 
1760
    /* Just for good measure... */
 
1761
    mail_free_envelope(&outgoing);
 
1762
    pine_free_body(&body);
 
1763
 
 
1764
    return(errstr);             /* no problem-o */
 
1765
}
 
1766
 
 
1767
 
 
1768
/*----------------------------------------------------------------------
 
1769
    Serve up the current signature within pico for editing
 
1770
 
 
1771
    Args: file to edit
 
1772
 
 
1773
  Result: signature changed or not.
 
1774
  ---*/
 
1775
char *
 
1776
signature_edit(char *sigfile, char *title)
 
1777
{
 
1778
    int      editor_result;
 
1779
    char     sig_path[MAXPATH+1], errbuf[2000], *errstr = NULL;
 
1780
    char    *ret = NULL;
 
1781
    STORE_S *msgso, *tmpso = NULL;
 
1782
    gf_io_t  gc, pc;
 
1783
    PICO     pbf;
 
1784
    struct variable *vars = ps_global->vars;
 
1785
    REMDATA_S *rd = NULL;
 
1786
 
 
1787
    if(!signature_path(sigfile, sig_path, MAXPATH))
 
1788
      return(cpystr(_("No signature file defined.")));
 
1789
    
 
1790
    if(IS_REMOTE(sigfile)){
 
1791
        rd = rd_create_remote(RemImap, sig_path, (void *)REMOTE_SIG_SUBTYPE,
 
1792
                              NULL, "Error: ",
 
1793
                              _("Can't access remote configuration."));
 
1794
        if(!rd)
 
1795
          return(cpystr(_("Error attempting to edit remote configuration")));
 
1796
        
 
1797
        (void)rd_read_metadata(rd);
 
1798
 
 
1799
        if(rd->access == MaybeRorW){
 
1800
            if(rd->read_status == 'R')
 
1801
              rd->access = ReadOnly;
 
1802
            else
 
1803
              rd->access = ReadWrite;
 
1804
        }
 
1805
 
 
1806
        if(rd->access != NoExists){
 
1807
 
 
1808
            rd_check_remvalid(rd, 1L);
 
1809
 
 
1810
            /*
 
1811
             * If the cached info says it is readonly but
 
1812
             * it looks like it's been fixed now, change it to readwrite.
 
1813
             */
 
1814
            if(rd->read_status == 'R'){
 
1815
                rd_check_readonly_access(rd);
 
1816
                if(rd->read_status == 'W'){
 
1817
                    rd->access = ReadWrite;
 
1818
                    rd->flags |= REM_OUTOFDATE;
 
1819
                }
 
1820
                else
 
1821
                  rd->access = ReadOnly;
 
1822
            }
 
1823
        }
 
1824
 
 
1825
        if(rd->flags & REM_OUTOFDATE){
 
1826
            if(rd_update_local(rd) != 0){
 
1827
 
 
1828
                dprint((1,
 
1829
                       "signature_edit: rd_update_local failed\n"));
 
1830
                rd_close_remdata(&rd);
 
1831
                return(cpystr(_("Can't access remote sig")));
 
1832
            }
 
1833
        }
 
1834
        else
 
1835
          rd_open_remote(rd);
 
1836
 
 
1837
        if(rd->access != ReadWrite || rd_remote_is_readonly(rd)){
 
1838
            rd_close_remdata(&rd);
 
1839
            return(cpystr(_("Can't get write permission for remote sig")));
 
1840
        }
 
1841
 
 
1842
        rd->flags |= DO_REMTRIM;
 
1843
 
 
1844
        strncpy(sig_path, rd->lf, sizeof(sig_path)-1);
 
1845
        sig_path[sizeof(sig_path)-1] = '\0';
 
1846
    }
 
1847
 
 
1848
    standard_picobuf_setup(&pbf);
 
1849
    pbf.tty_fix       = PineRaw;
 
1850
    pbf.composer_help = h_composer_sigedit;
 
1851
    pbf.exittest      = sigedit_exit_for_pico;
 
1852
    pbf.upload         = (VAR_UPLOAD_CMD && VAR_UPLOAD_CMD[0])
 
1853
                           ? upload_msg_to_pico : NULL;
 
1854
    pbf.alt_ed        = (VAR_EDITOR && VAR_EDITOR[0] && VAR_EDITOR[0][0])
 
1855
                            ? VAR_EDITOR : NULL;
 
1856
    pbf.alt_spell     = (VAR_SPELLER && VAR_SPELLER[0]) ? VAR_SPELLER : NULL;
 
1857
    pbf.always_spell_check = F_ON(F_ALWAYS_SPELL_CHECK, ps_global);
 
1858
    pbf.strip_ws_before_send = F_ON(F_STRIP_WS_BEFORE_SEND, ps_global);
 
1859
    pbf.allow_flowed_text = 0;
 
1860
 
 
1861
    pbf.pine_anchor   = set_titlebar(title,
 
1862
                                      ps_global->mail_stream,
 
1863
                                      ps_global->context_current,
 
1864
                                      ps_global->cur_folder,
 
1865
                                      ps_global->msgmap,
 
1866
                                      0, FolderName, 0, 0, NULL);
 
1867
 
 
1868
    /* NOTE: at this point, alot of pico struct fields are null'd out
 
1869
     * thanks to the leading memset; in particular "headents" which tells
 
1870
     * pico to behave like a normal editor (though modified slightly to
 
1871
     * let the caller dictate the file to edit and such)...
 
1872
     */
 
1873
 
 
1874
    if(VAR_OPER_DIR && !in_dir(VAR_OPER_DIR, sig_path)){
 
1875
        size_t l;
 
1876
 
 
1877
        l = strlen(VAR_OPER_DIR) + 100;
 
1878
        ret = (char *) fs_get((l+1) * sizeof(char));
 
1879
        snprintf(ret, l+1, _("Can't edit file outside of %s"), VAR_OPER_DIR);
 
1880
        ret[l] = '\0';
 
1881
        return(ret);
 
1882
    }
 
1883
 
 
1884
    /*
 
1885
     * Now alloc and init the text to pass pico
 
1886
     */
 
1887
    if(!(msgso = so_get(PicoText, NULL, EDIT_ACCESS))){
 
1888
        ret = cpystr(_("Error allocating space for file"));
 
1889
        dprint((1, "Can't alloc space for signature_edit"));
 
1890
        return(ret);
 
1891
    }
 
1892
    else
 
1893
      pbf.msgtext = so_text(msgso);
 
1894
 
 
1895
    if(can_access(sig_path, READ_ACCESS) == 0
 
1896
       && !(tmpso = so_get(FileStar, sig_path, READ_ACCESS|READ_FROM_LOCALE))){
 
1897
        char *problem = error_description(errno);
 
1898
 
 
1899
        snprintf(errbuf, sizeof(errbuf), _("Error editing \"%s\": %s"),
 
1900
                sig_path, problem ? problem : "<NULL>");
 
1901
        errbuf[sizeof(errbuf)-1] = '\0';
 
1902
        ret = cpystr(errbuf);
 
1903
 
 
1904
        dprint((1, "signature_edit: can't open %s: %s", sig_path,
 
1905
                   problem ? problem : "<NULL>"));
 
1906
        return(ret);
 
1907
    }
 
1908
    else if(tmpso){                     /* else, fill pico's edit buffer */
 
1909
        gf_set_so_readc(&gc, tmpso);    /* read from file, write pico buf */
 
1910
        gf_set_so_writec(&pc, msgso);
 
1911
        gf_filter_init();               /* no filters needed */
 
1912
        if(errstr = gf_pipe(gc, pc)){
 
1913
            snprintf(errbuf, sizeof(errbuf), _("Error reading file: \"%s\""), errstr);
 
1914
            errbuf[sizeof(errbuf)-1] = '\0';
 
1915
            ret = cpystr(errbuf);
 
1916
        }
 
1917
 
 
1918
        gf_clear_so_readc(tmpso);
 
1919
        gf_clear_so_writec(msgso);
 
1920
        so_give(&tmpso);
 
1921
    }
 
1922
 
 
1923
    if(!errstr){
 
1924
#ifdef _WINDOWS
 
1925
        mswin_setwindowmenu (MENU_COMPOSER);
 
1926
#endif
 
1927
 
 
1928
        /*------ OK, Go edit the signature ------*/
 
1929
        editor_result = pico(&pbf);
 
1930
 
 
1931
#ifdef _WINDOWS
 
1932
        mswin_setwindowmenu (MENU_DEFAULT);
 
1933
#endif
 
1934
        if(editor_result & COMP_GOTHUP){
 
1935
            hup_signal();               /* do what's normal for a hup */
 
1936
        }
 
1937
        else{
 
1938
            fix_windsize(ps_global);
 
1939
            init_signals();
 
1940
        }
 
1941
 
 
1942
        if(editor_result & (COMP_SUSPEND | COMP_GOTHUP | COMP_CANCEL)){
 
1943
        }
 
1944
        else{
 
1945
            /*------ Must have an edited buffer, write it to .sig -----*/
 
1946
            our_unlink(sig_path);       /* blast old copy */
 
1947
            if(tmpso = so_get(FileStar, sig_path, WRITE_ACCESS|WRITE_TO_LOCALE)){
 
1948
                so_seek(msgso, 0L, 0);
 
1949
                gf_set_so_readc(&gc, msgso);    /* read from pico buf */
 
1950
                gf_set_so_writec(&pc, tmpso);   /* write sig file */
 
1951
                gf_filter_init();               /* no filters needed */
 
1952
                if(errstr = gf_pipe(gc, pc)){
 
1953
                    snprintf(errbuf, sizeof(errbuf), _("Error writing file: \"%s\""),
 
1954
                                      errstr);
 
1955
                    errbuf[sizeof(errbuf)-1] = '\0';
 
1956
                    ret = cpystr(errbuf);
 
1957
                }
 
1958
 
 
1959
                gf_clear_so_readc(msgso);
 
1960
                gf_clear_so_writec(tmpso);
 
1961
                if(so_give(&tmpso)){
 
1962
                    errstr = error_description(errno);
 
1963
                    snprintf(errbuf, sizeof(errbuf), _("Error writing file: \"%s\""),
 
1964
                                      errstr);
 
1965
                    errbuf[sizeof(errbuf)-1] = '\0';
 
1966
                    ret = cpystr(errbuf);
 
1967
                }
 
1968
 
 
1969
                if(IS_REMOTE(sigfile)){
 
1970
                    int   e, we_cancel;
 
1971
                    char datebuf[200];
 
1972
 
 
1973
                    datebuf[0] = '\0';
 
1974
 
 
1975
                    we_cancel = busy_cue("Copying to remote sig", NULL, 1);
 
1976
                    if((e = rd_update_remote(rd, datebuf)) != 0){
 
1977
                        if(e == -1){
 
1978
                            q_status_message2(SM_ORDER | SM_DING, 3, 5,
 
1979
                              _("Error opening temporary sig file %s: %s"),
 
1980
                                rd->lf, error_description(errno));
 
1981
                            dprint((1,
 
1982
                               "write_remote_sig: error opening temp file %s\n",
 
1983
                               rd->lf ? rd->lf : "?"));
 
1984
                        }
 
1985
                        else{
 
1986
                            q_status_message2(SM_ORDER | SM_DING, 3, 5,
 
1987
                                            _("Error copying to %s: %s"),
 
1988
                                            rd->rn, error_description(errno));
 
1989
                            dprint((1,
 
1990
                              "write_remote_sig: error copying from %s to %s\n",
 
1991
                              rd->lf ? rd->lf : "?", rd->rn ? rd->rn : "?"));
 
1992
                        }
 
1993
                        
 
1994
                        q_status_message(SM_ORDER | SM_DING, 5, 5,
 
1995
           _("Copy of sig to remote folder failed, changes NOT saved remotely"));
 
1996
                    }
 
1997
                    else{
 
1998
                        rd_update_metadata(rd, datebuf);
 
1999
                        rd->read_status = 'W';
 
2000
                    }
 
2001
 
 
2002
                    rd_close_remdata(&rd);
 
2003
 
 
2004
                    if(we_cancel)
 
2005
                      cancel_busy_cue(-1);
 
2006
                }
 
2007
            }
 
2008
            else{
 
2009
                snprintf(errbuf, sizeof(errbuf), _("Error writing \"%s\""), sig_path);
 
2010
                errbuf[sizeof(errbuf)-1] = '\0';
 
2011
                ret = cpystr(errbuf);
 
2012
                dprint((1, "signature_edit: can't write %s",
 
2013
                           sig_path));
 
2014
            }
 
2015
        }
 
2016
    }
 
2017
    
 
2018
    standard_picobuf_teardown(&pbf);
 
2019
    so_give(&msgso);
 
2020
    return(ret);
 
2021
}
 
2022
 
 
2023
 
 
2024
/*----------------------------------------------------------------------
 
2025
    Serve up the current signature within pico for editing
 
2026
 
 
2027
    Args: literal signature to edit
 
2028
 
 
2029
  Result: raw edited signature is returned in result arg
 
2030
  ---*/
 
2031
char *
 
2032
signature_edit_lit(char *litsig, char **result, char *title, HelpType composer_help)
 
2033
{
 
2034
    int      editor_result;
 
2035
    char    *errstr = NULL;
 
2036
    char    *ret = NULL;
 
2037
    STORE_S *msgso;
 
2038
    PICO     pbf;
 
2039
    struct variable *vars = ps_global->vars;
 
2040
 
 
2041
    standard_picobuf_setup(&pbf);
 
2042
    pbf.tty_fix       = PineRaw;
 
2043
    pbf.search_help   = h_sigedit_search;
 
2044
    pbf.composer_help = composer_help;
 
2045
    pbf.exittest      = sigedit_exit_for_pico;
 
2046
    pbf.upload         = (VAR_UPLOAD_CMD && VAR_UPLOAD_CMD[0])
 
2047
                           ? upload_msg_to_pico : NULL;
 
2048
    pbf.alt_ed        = (VAR_EDITOR && VAR_EDITOR[0] && VAR_EDITOR[0][0])
 
2049
                            ? VAR_EDITOR : NULL;
 
2050
    pbf.alt_spell     = (VAR_SPELLER && VAR_SPELLER[0]) ? VAR_SPELLER : NULL;
 
2051
    pbf.always_spell_check = F_ON(F_ALWAYS_SPELL_CHECK, ps_global);
 
2052
    pbf.strip_ws_before_send = F_ON(F_STRIP_WS_BEFORE_SEND, ps_global);
 
2053
    pbf.allow_flowed_text = 0;
 
2054
 
 
2055
    pbf.pine_anchor   = set_titlebar(title,
 
2056
                                      ps_global->mail_stream,
 
2057
                                      ps_global->context_current,
 
2058
                                      ps_global->cur_folder,
 
2059
                                      ps_global->msgmap,
 
2060
                                      0, FolderName, 0, 0, NULL);
 
2061
 
 
2062
    /* NOTE: at this point, alot of pico struct fields are null'd out
 
2063
     * thanks to the leading memset; in particular "headents" which tells
 
2064
     * pico to behave like a normal editor (though modified slightly to
 
2065
     * let the caller dictate the file to edit and such)...
 
2066
     */
 
2067
 
 
2068
    /*
 
2069
     * Now alloc and init the text to pass pico
 
2070
     */
 
2071
    if(!(msgso = so_get(PicoText, NULL, EDIT_ACCESS))){
 
2072
        ret = cpystr(_("Error allocating space"));
 
2073
        dprint((1, "Can't alloc space for signature_edit_lit"));
 
2074
        return(ret);
 
2075
    }
 
2076
    else
 
2077
      pbf.msgtext = so_text(msgso);
 
2078
    
 
2079
    so_puts(msgso, litsig ? litsig : "");
 
2080
 
 
2081
 
 
2082
    if(!errstr){
 
2083
#ifdef _WINDOWS
 
2084
        mswin_setwindowmenu (MENU_COMPOSER);
 
2085
#endif
 
2086
 
 
2087
        /*------ OK, Go edit the signature ------*/
 
2088
        editor_result = pico(&pbf);
 
2089
 
 
2090
#ifdef _WINDOWS
 
2091
        mswin_setwindowmenu (MENU_DEFAULT);
 
2092
#endif
 
2093
        if(editor_result & COMP_GOTHUP){
 
2094
            hup_signal();               /* do what's normal for a hup */
 
2095
        }
 
2096
        else{
 
2097
            fix_windsize(ps_global);
 
2098
            init_signals();
 
2099
        }
 
2100
 
 
2101
        if(editor_result & (COMP_SUSPEND | COMP_GOTHUP | COMP_CANCEL)){
 
2102
            ret = cpystr(_("Signature Edit Cancelled"));
 
2103
        }
 
2104
        else{
 
2105
            /*------ Must have an edited buffer, write it to .sig -----*/
 
2106
            unsigned char c;
 
2107
            int cnt = 0;
 
2108
            char *p;
 
2109
 
 
2110
            so_seek(msgso, 0L, 0);
 
2111
            while(so_readc(&c, msgso))
 
2112
              cnt++;
 
2113
            
 
2114
            *result = (char *)fs_get((cnt+1) * sizeof(char));
 
2115
            p = *result;
 
2116
            so_seek(msgso, 0L, 0);
 
2117
            while(so_readc(&c, msgso))
 
2118
              *p++ = c;
 
2119
            
 
2120
            *p = '\0';
 
2121
        }
 
2122
    }
 
2123
    
 
2124
    standard_picobuf_teardown(&pbf);
 
2125
    so_give(&msgso);
 
2126
    return(ret);
 
2127
}
 
2128
 
 
2129
 
 
2130
/*
 
2131
 *
 
2132
 */
 
2133
char *
 
2134
sigedit_exit_for_pico(struct headerentry *he, void (*redraw_pico)(void), int allow_flowed)
 
2135
{
 
2136
    int       rv;
 
2137
    char     *rstr = NULL;
 
2138
    void    (*redraw)(void) = ps_global->redrawer;
 
2139
    static ESCKEY_S opts[] = {
 
2140
        {'y', 'y', "Y", N_("Yes")},
 
2141
        {'n', 'n', "N", N_("No")},
 
2142
        {-1, 0, NULL, NULL}
 
2143
    };
 
2144
 
 
2145
    ps_global->redrawer = redraw_pico;
 
2146
    fix_windsize(ps_global);
 
2147
 
 
2148
    while(1){
 
2149
        rv = radio_buttons(_("Exit editor and apply changes? "),
 
2150
                           -FOOTER_ROWS(ps_global), opts,
 
2151
                           'y', 'x', NO_HELP, RB_NORM);
 
2152
        if(rv == 'y'){                          /* user ACCEPTS! */
 
2153
            break;
 
2154
        }
 
2155
        else if(rv == 'n'){                     /* Declined! */
 
2156
            rstr = _("No Changes Saved");
 
2157
            break;
 
2158
        }
 
2159
        else if(rv == 'x'){                     /* Cancelled! */
 
2160
            rstr = _("Exit Cancelled");
 
2161
            break;
 
2162
        }
 
2163
    }
 
2164
 
 
2165
    ps_global->redrawer = redraw;
 
2166
    return(rstr);
 
2167
}
 
2168
 
 
2169
 
 
2170
/*
 
2171
 * Common stuff we almost always want to set when calling pico.
 
2172
 */
 
2173
void
 
2174
standard_picobuf_setup(PICO *pbf)
 
2175
{
 
2176
    memset(pbf, 0, sizeof(*pbf));
 
2177
 
 
2178
    pbf->pine_version   = ALPINE_VERSION;
 
2179
    pbf->fillcolumn     = ps_global->composer_fillcol;
 
2180
    pbf->menu_rows      = FOOTER_ROWS(ps_global) - 1;
 
2181
    pbf->colors         = colors_for_pico();
 
2182
    pbf->helper         = helper;
 
2183
    pbf->showmsg        = display_message_for_pico;
 
2184
    pbf->suspend        = do_suspend;
 
2185
    pbf->keybinput      = cmd_input_for_pico;
 
2186
    pbf->tty_fix        = ttyfix;               /* watch out for this one */
 
2187
    pbf->newmail        = new_mail_for_pico;
 
2188
    pbf->ckptdir        = checkpoint_dir_for_pico;
 
2189
    pbf->resize         = resize_for_pico;
 
2190
    pbf->input_cs       = ps_global->input_cs;
 
2191
    pbf->winch_cleanup  = winch_cleanup;
 
2192
    pbf->search_help    = h_composer_search;
 
2193
    pbf->ins_help       = h_composer_ins;
 
2194
    pbf->ins_m_help     = h_composer_ins_m;
 
2195
    pbf->composer_help  = h_composer;
 
2196
    pbf->browse_help    = h_composer_browse;
 
2197
    pbf->attach_help    = h_composer_ctrl_j;
 
2198
 
 
2199
    pbf->pine_flags =
 
2200
       ( (F_ON(F_CAN_SUSPEND,ps_global)                 ? P_SUSPEND     : 0L)
 
2201
       | (F_ON(F_USE_FK,ps_global)                      ? P_FKEYS       : 0L)
 
2202
       | (ps_global->restricted                         ? P_SECURE      : 0L)
 
2203
       | (F_ON(F_ALT_ED_NOW,ps_global)                  ? P_ALTNOW      : 0L)
 
2204
       | (F_ON(F_USE_CURRENT_DIR,ps_global)             ? P_CURDIR      : 0L)
 
2205
       | (F_ON(F_SUSPEND_SPAWNS,ps_global)              ? P_SUBSHELL    : 0L)
 
2206
       | (F_ON(F_COMPOSE_MAPS_DEL,ps_global)            ? P_DELRUBS     : 0L)
 
2207
       | (F_ON(F_ENABLE_TAB_COMPLETE,ps_global)         ? P_COMPLETE    : 0L)
 
2208
       | (F_ON(F_SHOW_CURSOR,ps_global)                 ? P_SHOCUR      : 0L)
 
2209
       | (F_ON(F_DEL_FROM_DOT,ps_global)                ? P_DOTKILL     : 0L)
 
2210
       | (F_ON(F_ENABLE_DOT_FILES,ps_global)            ? P_DOTFILES    : 0L)
 
2211
       | (F_ON(F_ALLOW_GOTO,ps_global)                  ? P_ALLOW_GOTO  : 0L)
 
2212
       | (F_ON(F_ENABLE_SEARCH_AND_REPL,ps_global)      ? P_REPLACE     : 0L)
 
2213
       | (!ps_global->pass_ctrl_chars
 
2214
          && !ps_global->pass_c1_ctrl_chars             ? P_HICTRL      : 0L)
 
2215
       | ((F_ON(F_ENABLE_ALT_ED,ps_global)
 
2216
           || F_ON(F_ALT_ED_NOW,ps_global)
 
2217
           || (ps_global->VAR_EDITOR
 
2218
               && ps_global->VAR_EDITOR[0]
 
2219
               && ps_global->VAR_EDITOR[0][0]))
 
2220
                                                        ? P_ADVANCED    : 0L)
 
2221
       | ((!ps_global->keyboard_charmap
 
2222
           || !strucmp(ps_global->keyboard_charmap, "US-ASCII"))
 
2223
                                                        ? P_HIBITIGN    : 0L));
 
2224
 
 
2225
    if(ps_global->VAR_OPER_DIR){
 
2226
        pbf->oper_dir    = ps_global->VAR_OPER_DIR;
 
2227
        pbf->pine_flags |= P_TREE;
 
2228
    }
 
2229
    pbf->home_dir = ps_global->home_dir;
 
2230
}
 
2231
 
 
2232
 
 
2233
void
 
2234
standard_picobuf_teardown(PICO *pbf)
 
2235
{
 
2236
    if(pbf){
 
2237
        if(pbf->colors)
 
2238
          free_pcolors(&pbf->colors);
 
2239
    }
 
2240
}
 
2241
 
 
2242
 
 
2243
/*----------------------------------------------------------------------
 
2244
    Call back for pico to use to check for new mail.
 
2245
     
 
2246
Args: cursor -- pointer to in to tell caller if cursor location changed
 
2247
                if NULL, turn off cursor positioning.
 
2248
      timing -- whether or not it's a good time to check 
 
2249
 
 
2250
 
 
2251
Returns: returns 1 on success, zero on error.
 
2252
----*/      
 
2253
long
 
2254
new_mail_for_pico(int timing, int status)
 
2255
{
 
2256
    /*
 
2257
     * If we're not interested in the status, don't display the busy
 
2258
     * cue either...
 
2259
     */
 
2260
    /* don't know where the cursor's been, reset it */
 
2261
    clear_cursor_pos();
 
2262
    return(new_mail(0, timing,
 
2263
                    (status ? NM_STATUS_MSG : NM_NONE) | NM_DEFER_SORT
 
2264
                                                       | NM_FROM_COMPOSER));
 
2265
}
 
2266
 
 
2267
 
 
2268
void
 
2269
cmd_input_for_pico(void)
 
2270
{
 
2271
    zero_new_mail_count();
 
2272
}
 
2273
 
 
2274
 
 
2275
/*----------------------------------------------------------------------
 
2276
    Call back for pico to get newmail status messages displayed
 
2277
 
 
2278
Args: x -- char processed
 
2279
 
 
2280
Returns: 
 
2281
----*/      
 
2282
int
 
2283
display_message_for_pico(int x)
 
2284
{
 
2285
    int rv;
 
2286
    
 
2287
    clear_cursor_pos();                 /* can't know where cursor is */
 
2288
    mark_status_dirty();                /* don't count on cached text */
 
2289
    fix_windsize(ps_global);
 
2290
    init_sigwinch();
 
2291
    display_message(x);
 
2292
    rv = ps_global->mangled_screen;
 
2293
    ps_global->mangled_screen = 0;
 
2294
    return(rv);
 
2295
}
 
2296
 
 
2297
 
 
2298
/*----------------------------------------------------------------------
 
2299
    Call back for pico to get desired directory for its check point file
 
2300
     
 
2301
  Args: s -- buffer to write directory name
 
2302
        n -- length of that buffer
 
2303
 
 
2304
  Returns: pointer to static buffer
 
2305
----*/      
 
2306
char *
 
2307
checkpoint_dir_for_pico(char *s, size_t n)
 
2308
{
 
2309
#if defined(DOS) || defined(OS2)
 
2310
    /*
 
2311
     * we can't assume anything about root or home dirs, so
 
2312
     * just plunk it down in the same place as the pinerc
 
2313
     */
 
2314
    if(!getenv("HOME")){
 
2315
        char *lc = last_cmpnt(ps_global->pinerc);
 
2316
 
 
2317
        if(lc != NULL){
 
2318
            strncpy(s, ps_global->pinerc, MIN(n-1,lc-ps_global->pinerc));
 
2319
            s[MIN(n-1,lc-ps_global->pinerc)] = '\0';
 
2320
        }
 
2321
        else{
 
2322
            strncpy(s, ".\\", n-1);
 
2323
            s[n-1] = '\0';
 
2324
        }
 
2325
    }
 
2326
    else
 
2327
#endif
 
2328
    strncpy(s, ps_global->home_dir, n-1);
 
2329
    s[n-1] = '\0';
 
2330
 
 
2331
    return(s);
 
2332
}
 
2333
 
 
2334
 
 
2335
/*----------------------------------------------------------------------
 
2336
  Call back for pico to tell us the window size's changed
 
2337
 
 
2338
  Args: none
 
2339
 
 
2340
  Returns: none (but pine's ttyo structure may have been updated)
 
2341
----*/
 
2342
void
 
2343
resize_for_pico(void)
 
2344
{
 
2345
    fix_windsize(ps_global);
 
2346
}
 
2347
 
 
2348
 
 
2349
PCOLORS *
 
2350
colors_for_pico(void)
 
2351
{
 
2352
    PCOLORS *colors = NULL;
 
2353
    struct variable *vars = ps_global->vars;
 
2354
 
 
2355
    if (pico_usingcolor()){
 
2356
      colors = (PCOLORS *)fs_get(sizeof(PCOLORS));
 
2357
      if (VAR_TITLE_FORE_COLOR && VAR_TITLE_BACK_COLOR){
 
2358
        colors->tbcp = new_color_pair(VAR_TITLE_FORE_COLOR,
 
2359
                                      VAR_TITLE_BACK_COLOR);
 
2360
      }
 
2361
      else colors->tbcp = NULL;
 
2362
 
 
2363
      if (VAR_KEYLABEL_FORE_COLOR && VAR_KEYLABEL_BACK_COLOR){
 
2364
        colors->klcp = new_color_pair(VAR_KEYLABEL_FORE_COLOR,
 
2365
                                      VAR_KEYLABEL_BACK_COLOR);
 
2366
        if (!pico_is_good_colorpair(colors->klcp))
 
2367
          free_color_pair(&colors->klcp);
 
2368
      }
 
2369
      else colors->klcp = NULL;
 
2370
 
 
2371
      if (colors->klcp && VAR_KEYNAME_FORE_COLOR && VAR_KEYNAME_BACK_COLOR){
 
2372
        colors->kncp = new_color_pair(VAR_KEYNAME_FORE_COLOR, 
 
2373
                                      VAR_KEYNAME_BACK_COLOR);
 
2374
      }
 
2375
      else colors->kncp = NULL;
 
2376
      if (VAR_STATUS_FORE_COLOR && VAR_STATUS_BACK_COLOR){
 
2377
        colors->stcp = new_color_pair(VAR_STATUS_FORE_COLOR, 
 
2378
                                      VAR_STATUS_BACK_COLOR);
 
2379
      }
 
2380
      else colors->stcp = NULL;
 
2381
    }
 
2382
    
 
2383
    return colors;
 
2384
}
 
2385
 
 
2386
 
 
2387
void
 
2388
free_pcolors(PCOLORS **colors)
 
2389
{
 
2390
    if (*colors){
 
2391
          if ((*colors)->tbcp)
 
2392
                free_color_pair(&(*colors)->tbcp);
 
2393
          if ((*colors)->kncp)
 
2394
                free_color_pair(&(*colors)->kncp);
 
2395
          if ((*colors)->klcp)
 
2396
                free_color_pair(&(*colors)->klcp);
 
2397
          if ((*colors)->stcp)
 
2398
                free_color_pair(&(*colors)->stcp);
 
2399
          fs_give((void **)colors);
 
2400
          *colors = NULL;
 
2401
        }
 
2402
}