1 #if !defined(lint) && !defined(DOS)
2 static char rcsid
[] = "$Id: mailpart.c 1074 2008-06-04 00:08:43Z hubert@u.washington.edu $";
6 * ========================================================================
7 * Copyright 2006-2008 University of Washington
8 * Copyright 2013-2015 Eduardo Chappa
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
14 * http://www.apache.org/licenses/LICENSE-2.0
16 * ========================================================================
19 /*======================================================================
21 The meat and pototoes of attachment processing here.
42 #include "../pith/state.h"
43 #include "../pith/conf.h"
44 #include "../pith/store.h"
45 #include "../pith/msgno.h"
46 #include "../pith/detach.h"
47 #include "../pith/handle.h"
48 #include "../pith/filter.h"
49 #include "../pith/bitmap.h"
50 #include "../pith/charset.h"
51 #include "../pith/mimedesc.h"
52 #include "../pith/mailcap.h"
53 #include "../pith/newmail.h"
54 #include "../pith/rfc2231.h"
55 #include "../pith/flag.h"
56 #include "../pith/text.h"
57 #include "../pith/editorial.h"
58 #include "../pith/save.h"
59 #include "../pith/pipe.h"
60 #include "../pith/util.h"
61 #include "../pith/detoken.h"
62 #include "../pith/busy.h"
63 #include "../pith/mimetype.h"
64 #include "../pith/icache.h"
65 #include "../pith/list.h"
66 #include "../pith/ablookup.h"
67 #include "../pith/options.h"
68 #include "../pith/smime.h"
72 * Information used to paint and maintain a line on the attachment
75 typedef struct atdisp_line
{
76 char *dstring
; /* alloc'd var value string */
77 ATTACH_S
*attp
; /* actual attachment pointer */
78 struct atdisp_line
*next
, *prev
;
83 * struct defining attachment screen's current state
85 typedef struct att_screen
{
88 COLOR_PAIR
*titlecolor
;
91 static ATT_SCREEN_S
*att_screen
;
94 #define next_attline(p) ((p) ? (p)->next : NULL)
95 #define prev_attline(p) ((p) ? (p)->prev : NULL)
100 * local global pointer to scroll attachment popup menu
102 static ATTACH_S
*scrat_attachp
;
106 #define FETCH_READC g_fr_desc->readc
109 /* used to keep track of detached MIME segments total length */
110 static long save_att_length
;
113 * Internal Prototypes
115 ATDISP_S
*new_attline(ATDISP_S
**);
116 void free_attline(ATDISP_S
**);
117 int attachment_screen_updater(struct pine
*, ATDISP_S
*, ATT_SCREEN_S
*);
118 void attachment_screen_redrawer(void);
119 void update_att_screen_titlebar(void);
120 ATDISP_S
*first_attline(ATDISP_S
*);
121 int init_att_progress(char *, MAILSTREAM
*, BODY
*);
122 long save_att_piped(int);
123 int save_att_percent(void);
124 void save_attachment(int, long, ATTACH_S
*);
125 void export_attachment(int, long, ATTACH_S
*);
126 char *write_attached_msg(long, ATTACH_S
**, STORE_S
*, int);
127 void save_msg_att(long, ATTACH_S
*);
128 void save_digest_att(long, ATTACH_S
*);
129 int save_msg_att_work(long int, ATTACH_S
*, MAILSTREAM
*, char *,
130 CONTEXT_S
*, char *);
131 void export_msg_att(long, ATTACH_S
*);
132 void export_digest_att(long, ATTACH_S
*);
133 void print_attachment(int, long, ATTACH_S
*);
134 int print_msg_att(long, ATTACH_S
*, int);
135 void print_digest_att(long, ATTACH_S
*);
136 void run_viewer(char *, BODY
*, int);
137 STORE_S
*format_text_att(long, ATTACH_S
*, HANDLE_S
**);
138 int display_text_att(long, ATTACH_S
*, int);
139 int display_msg_att(long, ATTACH_S
*, int);
140 void display_digest_att(long, ATTACH_S
*, int);
141 int scroll_attachment(char *, STORE_S
*, SourceType
, HANDLE_S
*, ATTACH_S
*, int);
142 int process_attachment_cmd(int, MSGNO_S
*, SCROLL_S
*);
143 int format_msg_att(long, ATTACH_S
**, HANDLE_S
**, gf_io_t
, int);
144 void display_vcard_att(long, ATTACH_S
*, int);
145 void display_attach_info(long, ATTACH_S
*);
146 void forward_attachment(MAILSTREAM
*, long, ATTACH_S
*);
147 void forward_msg_att(MAILSTREAM
*, long, ATTACH_S
*);
148 void reply_msg_att(MAILSTREAM
*, long, ATTACH_S
*);
149 void bounce_msg_att(MAILSTREAM
*, long, char *, char *);
150 void pipe_attachment(long, ATTACH_S
*);
151 int delete_attachment(long, ATTACH_S
*);
152 int undelete_attachment(long, ATTACH_S
*, int *);
154 int scroll_att_popup(SCROLL_S
*, int);
155 void display_text_att_window(ATTACH_S
*);
156 void display_msg_att_window(ATTACH_S
*);
160 /*----------------------------------------------------------------------
161 Provide attachments in browser for selected action
163 Args: ps -- pointer to pine structure
164 msgmap -- struct containing current message to display
168 Handle painting and navigation of attachment index. It would be nice
169 to someday handle message/rfc822 segments in a neat way (i.e., enable
170 forwarding, take address, etc.).
173 attachment_screen(struct pine
*ps
)
177 maxnumwid
= 0, maxsizewid
= 0, old_cols
= -1, km_popped
= 0, expbits
,
178 last_type
= TYPEOTHER
;
180 char *q
, *last_subtype
= NULL
, backtag
[64], *utf8str
;
183 ATDISP_S
*current
= NULL
, *ctmp
= NULL
;
186 ps
->prev_screen
= attachment_screen
;
187 ps
->next_screen
= SCREEN_FUN_NULL
;
189 ps
->some_quoting_was_suppressed
= 0;
191 if(ps
->ttyo
->screen_rows
- HEADER_ROWS(ps
) - FOOTER_ROWS(ps
) < 1){
192 q_status_message(SM_ORDER
| SM_DING
, 0, 3,
193 _("Screen too small to view attachment"));
194 ps
->next_screen
= mail_view_screen
;
198 if(mn_total_cur(ps
->msgmap
) > 1L){
199 q_status_message(SM_ORDER
| SM_DING
, 0, 3,
200 _("Can only view one message's attachments at a time."));
203 else if(ps
->atmts
&& ps
->atmts
->description
&& !(ps
->atmts
+ 1)->description
)
204 q_status_message1(SM_ASYNC
, 0, 3,
205 _("Message %s has only one part (the message body), and no attachments."),
206 long2string(mn_get_cur(ps
->msgmap
)));
208 /*----- Figure max display widths -----*/
209 for(a
= ps
->atmts
; a
&& a
->description
!= NULL
; a
++){
210 if((n
= utf8_width(a
->number
)) > maxnumwid
)
213 if((n
= utf8_width(a
->size
)) > maxsizewid
)
218 * Then, allocate and initialize attachment line list...
220 for(a
= ps
->atmts
; a
&& a
->description
; a
++)
221 new_attline(¤t
)->attp
= a
;
223 memset(&screen
, 0, sizeof(screen
));
224 msgno
= mn_m2raw(ps
->msgmap
, mn_get_cur(ps
->msgmap
));
225 ps
->mangled_screen
= 1; /* build display */
226 ps
->redrawer
= attachment_screen_redrawer
;
227 att_screen
= &screen
;
228 current
= first_attline(current
);
232 * Advance to next attachment if it's likely that we've already
233 * shown it to the user...
236 if (current
== NULL
){
237 q_status_message1(SM_ORDER
| SM_DING
, 0, 3,
238 _("Malformed message: %s"),
239 ps
->c_client_error
? ps
->c_client_error
: "?");
240 ps
->next_screen
= mail_view_screen
;
242 else if(current
->attp
->shown
&& (ctmp
= next_attline(current
)))
245 while(ps
->next_screen
== SCREEN_FUN_NULL
){
246 ps
->user_says_cancel
= 0;
251 ps
->mangled_body
= 1;
255 if(ps
->mangled_screen
){
257 * build/rebuild display lines
259 if(old_cols
!= ps
->ttyo
->screen_cols
){
260 int avail
, s1
, s2
, s4
, s5
, dwid
, sizewid
, descwid
;
262 avail
= ps_global
->ttyo
->screen_cols
;
264 s1
= MAX(MIN(1, avail
), 0);
267 dwid
= MAX(MIN(1, avail
), 0);
270 s2
= MAX(MIN(1, avail
), 0);
273 /* Only give up a third of the display to part numbers */
274 maxnumwid
= MIN(maxnumwid
, (ps_global
->ttyo
->screen_cols
/3));
275 maxnumwid
= MAX(MIN(maxnumwid
, avail
), 0);
278 s4
= MAX(MIN(3, avail
), 0);
281 sizewid
= MAX(MIN(maxsizewid
, avail
), 0);
284 s5
= MAX(MIN(3, avail
), 0);
287 descwid
= MAX(0, avail
);
289 old_cols
= ps
->ttyo
->screen_cols
;
291 for(ctmp
= first_attline(current
);
292 ctmp
&& (a
= ctmp
->attp
) && a
->description
;
293 ctmp
= next_attline(ctmp
)){
296 char description
[1000];
299 fs_give((void **)&ctmp
->dstring
);
301 len
= 6 * MAX(80, ps
->ttyo
->screen_cols
) * sizeof(char);
302 ctmp
->dstring
= (char *)fs_get(len
+ 1);
307 q
= a
->body
->description
;
308 if(!(q
&& q
[0]) && (MIME_MSG_A(a
) && a
->body
->nested
.msg
->env
))
309 q
= a
->body
->nested
.msg
->env
->subject
;
314 strncpy(buftmp
, q
, sizeof(buftmp
));
315 buftmp
[sizeof(buftmp
)-1] = '\0';
317 q
= (char *) rfc1522_decode_to_utf8((unsigned char *) tmp_20k_buf
,
318 SIZEOF_20KBUF
, buftmp
);
324 snprintf(description
, sizeof(description
), "%s%s%s%s", type_desc(a
->body
->type
, a
->body
->subtype
, a
->body
->parameter
, a
->body
->disposition
.type
? a
->body
->disposition
.parameter
: NULL
, 1), q
? ", \"" : "", q
? q
: "", q
? "\"" : "");
325 description
[sizeof(description
)-1] = '\0';
327 utf8_snprintf(ctmp
->dstring
, len
+1,
328 "%*.*s%*.*w%*.*s%-*.*w%*.*s%*.*w%*.*s%-*.*w",
331 msgno_part_deleted(ps
->mail_stream
, msgno
, a
->number
) ? "D" : "",
333 maxnumwid
, maxnumwid
,
335 ? short_str(a
->number
, numbuf
, sizeof(numbuf
), maxnumwid
, FrontDots
)
339 a
->size
? a
->size
: "",
341 descwid
, descwid
, description
);
343 ctmp
->dstring
[len
] = '\0';
347 ps
->mangled_header
= 1;
348 ps
->mangled_footer
= 1;
349 ps
->mangled_body
= 1;
352 /*----------- Check for new mail -----------*/
353 if(new_mail(0, NM_TIMING(ch
), NM_STATUS_MSG
| NM_DEFER_SORT
) >= 0)
354 ps
->mangled_header
= 1;
357 * If an expunge of the current message happened during the
358 * new mail check we want to bail out of here. See mm_expunged.
360 if(ps
->next_screen
!= SCREEN_FUN_NULL
)
363 if(ps
->mangled_header
){
364 update_att_screen_titlebar();
365 ps
->mangled_header
= 0;
368 if(ps
->mangled_screen
){
370 ps
->mangled_screen
= 0;
373 dline
= attachment_screen_updater(ps
, current
, &screen
);
375 /*---- This displays new mail notification, or errors ---*/
378 mark_status_unknown();
384 mark_status_unknown();
387 if(ps
->mangled_footer
388 || current
->attp
->body
->type
!= last_type
389 || !(last_subtype
&& current
->attp
->body
->subtype
)
390 || strucmp(last_subtype
, current
->attp
->body
->subtype
)){
392 struct key_menu
*km
= &att_index_keymenu
;
396 ps
->mangled_footer
= 0;
397 last_type
= current
->attp
->body
->type
;
398 last_subtype
= current
->attp
->body
->subtype
;
400 snprintf(backtag
, sizeof(backtag
), "Msg #%ld", mn_get_cur(ps
->msgmap
));
401 backtag
[sizeof(backtag
)-1] = '\0';
402 km
->keys
[ATT_PARENT_KEY
].label
= backtag
;
404 if(F_OFF(F_ENABLE_PIPE
, ps
))
405 clrbitn(ATT_PIPE_KEY
, bitmap
);
408 * If message or digest, leave Reply and Save and,
409 * conditionally, Bounce on...
411 if(MIME_MSG(last_type
, last_subtype
)){
412 if(F_OFF(F_ENABLE_BOUNCE
, ps
))
413 clrbitn(ATT_BOUNCE_KEY
, bitmap
);
415 km
->keys
[ATT_EXPORT_KEY
].name
= "";
416 km
->keys
[ATT_EXPORT_KEY
].label
= "";
418 else if(MIME_DGST(last_type
, last_subtype
)){
419 clrbitn(ATT_BOUNCE_KEY
, bitmap
);
420 clrbitn(ATT_REPLY_KEY
, bitmap
);
422 km
->keys
[ATT_EXPORT_KEY
].name
= "";
423 km
->keys
[ATT_EXPORT_KEY
].label
= "";
426 clrbitn(ATT_BOUNCE_KEY
, bitmap
);
427 clrbitn(ATT_REPLY_KEY
, bitmap
);
429 if(last_type
!= TYPETEXT
)
430 clrbitn(ATT_PRINT_KEY
, bitmap
);
432 km
->keys
[ATT_EXPORT_KEY
].name
= "E";
433 km
->keys
[ATT_EXPORT_KEY
].label
= N_("Export");
441 if(F_ON(F_ARROW_NAV
, ps
)){
442 menu_add_binding(km
, KEY_LEFT
, MC_EXIT
);
443 menu_add_binding(km
, KEY_RIGHT
, MC_VIEW_ATCH
);
446 menu_clear_binding(km
, KEY_LEFT
);
447 menu_clear_binding(km
, KEY_RIGHT
);
450 draw_keymenu(km
, bitmap
, ps
->ttyo
->screen_cols
, 1-FOOTER_ROWS(ps
),
455 mark_keymenu_dirty();
459 if(F_ON(F_SHOW_CURSOR
, ps
))
460 MoveCursor(dline
, 0);
462 MoveCursor(MAX(0, ps
->ttyo
->screen_rows
- FOOTER_ROWS(ps
)), 0);
464 /*------ Prepare to read the command from the keyboard ----*/
466 mouse_in_content(KEY_MOUSE
, -1, -1, 0, 0); /* prime the handler */
467 register_mfunc(mouse_in_content
, HEADER_ROWS(ps_global
), 0,
468 ps_global
->ttyo
->screen_rows
-(FOOTER_ROWS(ps_global
)+1),
469 ps_global
->ttyo
->screen_cols
);
471 ch
= READ_COMMAND(&utf8str
);
473 clear_mfunc(mouse_in_content
);
476 cmd
= menu_command(ch
, &att_index_keymenu
);
494 if(FOOTER_ROWS(ps
) == 1 && km_popped
== 0){
496 ps
->mangled_footer
= 1;
500 helper(h_attachment_screen
, _("HELP FOR ATTACHMENT INDEX"), 0);
501 ps
->mangled_screen
= 1;
506 ps
->mangled_footer
= 1;
511 if(ps
->full_header
== 1){
512 if(!(ps
->quote_suppression_threshold
513 && (ps
->some_quoting_was_suppressed
/* || in_index != View */)))
516 else if(ps
->full_header
> 2)
519 switch(ps
->full_header
){
521 q_status_message(SM_ORDER
, 0, 3,
522 _("Display of full headers is now off."));
526 q_status_message1(SM_ORDER
, 0, 3,
527 _("Quotes displayed, use %s to see full headers"),
528 F_ON(F_USE_FK
, ps
) ? "F9" : "H");
532 q_status_message(SM_ORDER
, 0, 3,
533 _("Display of full headers is now on."));
540 case MC_EXIT
: /* exit attachment screen */
541 ps
->next_screen
= mail_view_screen
;
545 ps
->next_screen
= quit_screen
;
549 ps
->next_screen
= main_menu_screen
;
553 ps
->next_screen
= mail_index_screen
;
557 if((ctmp
= next_attline(current
)) != NULL
)
560 q_status_message(SM_ORDER
, 0, 1, _("Already on last attachment"));
565 if((ctmp
= prev_attline(current
)) != NULL
)
568 q_status_message(SM_ORDER
, 0, 1, _("Already on first attachment"));
572 case MC_PAGEDN
: /* page forward */
573 if(next_attline(current
)){
574 while(dline
++ < ps
->ttyo
->screen_rows
- FOOTER_ROWS(ps
))
575 if((ctmp
= next_attline(current
)) != NULL
)
581 q_status_message(SM_ORDER
, 0, 1,
582 _("Already on last page of attachments"));
586 case MC_PAGEUP
: /* page backward */
587 if(prev_attline(current
)){
588 while(dline
-- > HEADER_ROWS(ps
))
589 if((ctmp
= prev_attline(current
)) != NULL
)
594 while(++dline
< ps
->ttyo
->screen_rows
- FOOTER_ROWS(ps
))
595 if((ctmp
= prev_attline(current
)) != NULL
)
601 q_status_message(SM_ORDER
, 0, 1,
602 _("Already on first page of attachments"));
611 mouse_get_last (NULL
, &mp
);
612 mp
.row
-= HEADER_ROWS(ps
);
613 ctmp
= screen
.top_line
;
614 while (mp
.row
&& ctmp
!= NULL
) {
623 if(mp
.button
== M_BUTTON_LEFT
)
624 display_attachment(msgno
, current
->attp
, DA_SAVE
);
627 else if(mp
.button
== M_BUTTON_RIGHT
){
628 MPopup atmt_popup
[20];
629 int i
= -1, exoffer
= 0;
631 dline
= attachment_screen_updater(ps
,current
,&screen
);
633 if(dispatch_attachment(current
->attp
) != MCD_NONE
){
634 atmt_popup
[++i
].type
= tQueue
;
635 atmt_popup
[i
].data
.val
= 'V';
636 atmt_popup
[i
].label
.style
= lNormal
;
637 atmt_popup
[i
].label
.string
= "&View";
639 if(!(current
->attp
->can_display
& MCD_EXTERNAL
)
640 && (current
->attp
->body
->type
== TYPETEXT
641 || MIME_MSG_A(current
->attp
)
642 || MIME_DGST_A(current
->attp
))){
644 atmt_popup
[++i
].type
= tIndex
;
645 atmt_popup
[i
].label
.style
= lNormal
;
646 atmt_popup
[i
].label
.string
=
647 "View in New Window";
651 atmt_popup
[++i
].type
= tQueue
;
652 atmt_popup
[i
].data
.val
= 'S';
653 atmt_popup
[i
].label
.style
= lNormal
;
654 atmt_popup
[i
].label
.string
= "&Save";
656 atmt_popup
[++i
].type
= tQueue
;
657 atmt_popup
[i
].label
.style
= lNormal
;
658 if(current
->dstring
[1] == 'D'){
659 atmt_popup
[i
].data
.val
= 'U';
660 atmt_popup
[i
].label
.string
= "&Undelete";
663 atmt_popup
[i
].data
.val
= 'D';
664 atmt_popup
[i
].label
.string
= "&Delete";
667 if(MIME_MSG_A(current
->attp
)){
668 atmt_popup
[++i
].type
= tQueue
;
669 atmt_popup
[i
].label
.style
= lNormal
;
670 atmt_popup
[i
].label
.string
= "&Reply...";
671 atmt_popup
[i
].data
.val
= 'R';
673 atmt_popup
[++i
].type
= tQueue
;
674 atmt_popup
[i
].label
.style
= lNormal
;
675 atmt_popup
[i
].label
.string
= "&Forward...";
676 atmt_popup
[i
].data
.val
= 'F';
679 atmt_popup
[++i
].type
= tQueue
;
680 atmt_popup
[i
].label
.style
= lNormal
;
681 atmt_popup
[i
].label
.string
= "&About...";
682 atmt_popup
[i
].data
.val
= 'A';
684 atmt_popup
[++i
].type
= tSeparator
;
686 atmt_popup
[++i
].type
= tQueue
;
687 snprintf(backtag
, sizeof(backtag
), "View Message #%ld",
688 mn_get_cur(ps
->msgmap
));
689 backtag
[sizeof(backtag
)-1] = '\0';
690 atmt_popup
[i
].label
.string
= backtag
;
691 atmt_popup
[i
].label
.style
= lNormal
;
692 atmt_popup
[i
].data
.val
= '<';
694 atmt_popup
[++i
].type
= tTail
;
696 if(mswin_popup(atmt_popup
) == 1 && exoffer
)
697 display_att_window(current
->attp
);
700 else if(mp
.button
== M_BUTTON_RIGHT
){
701 MPopup atmt_popup
[2];
703 atmt_popup
[0].type
= tQueue
;
704 snprintf(backtag
, sizeof(backtag
), "View Message #%ld",
705 mn_get_cur(ps
->msgmap
));
706 backtag
[sizeof(backtag
)-1] = '\0';
707 atmt_popup
[0].label
.string
= backtag
;
708 atmt_popup
[0].label
.style
= lNormal
;
709 atmt_popup
[0].data
.val
= '<';
711 atmt_popup
[1].type
= tTail
;
713 mswin_popup(atmt_popup
);
720 case MC_WHEREIS
: /* whereis */
721 /*--- get string ---*/
723 char *result
= NULL
, buf
[64];
724 static char last
[64], tmp
[64];
727 ps
->mangled_footer
= 1;
729 snprintf(tmp
, sizeof(tmp
), "Word to find %s%s%s: ",
730 (last
[0]) ? "[" : "",
731 (last
[0]) ? last
: "",
732 (last
[0]) ? "]" : "");
733 tmp
[sizeof(tmp
)-1] = '\0';
736 int flags
= OE_APPEND_CURRENT
| OE_SEQ_SENSITIVE
;
738 rc
= optionally_enter(buf
,-FOOTER_ROWS(ps
),0,sizeof(buf
),
739 tmp
,NULL
,help
,&flags
);
741 help
= help
== NO_HELP
? h_attach_index_whereis
: NO_HELP
;
742 else if(rc
== 0 || rc
== 1 || !buf
[0]){
743 if(rc
== 0 && !buf
[0] && last
[0]){
744 strncpy(buf
, last
, sizeof(buf
));
745 buf
[sizeof(buf
)-1] = '\0';
752 if(rc
== 0 && buf
[0]){
754 while((ctmp
= next_attline(ctmp
)) != NULL
)
755 if(srchstr(ctmp
->dstring
, buf
)){
761 ctmp
= first_attline(current
);
763 while(ctmp
!= current
)
764 if(srchstr(ctmp
->dstring
, buf
)){
769 ctmp
= next_attline(ctmp
);
773 result
= _("WhereIs cancelled");
776 strncpy(last
, buf
, sizeof(last
));
777 last
[sizeof(last
)-1] = '\0';
778 result
= "Word found";
782 q_status_message(SM_ORDER
, 0, 3,
783 result
? result
: _("Word not found"));
789 if(delete_attachment(msgno
, current
->attp
)){
790 int l
= current
? strlen(current
->attp
->number
) : 0;
792 current
->dstring
[1] = 'D';
794 /* Also indicate any children that will be deleted */
796 for(ctmp
= current
; ctmp
; ctmp
= next_attline(ctmp
))
797 if(!strncmp(ctmp
->attp
->number
, current
->attp
->number
, l
)
798 && ctmp
->attp
->number
[l
] == '.'){
799 ctmp
->dstring
[1] = 'D';
800 ps
->mangled_screen
= 1;
807 if(undelete_attachment(msgno
, current
->attp
, &expbits
)){
808 int l
= current
? strlen(current
->attp
->number
) : 0;
810 current
->dstring
[1] = ' ';
812 /* And unflag anything implicitly undeleted */
813 for(ctmp
= current
; ctmp
; ctmp
= next_attline(ctmp
))
814 if(!strncmp(ctmp
->attp
->number
, current
->attp
->number
, l
)
815 && ctmp
->attp
->number
[l
] == '.'
816 && (!msgno_exceptions(ps
->mail_stream
, msgno
,
817 ctmp
->attp
->number
, &expbits
, FALSE
)
818 || !(expbits
& MSG_EX_DELETE
))){
819 ctmp
->dstring
[1] = ' ';
820 ps
->mangled_screen
= 1;
827 reply_msg_att(ps
->mail_stream
, msgno
, current
->attp
);
831 forward_attachment(ps
->mail_stream
, msgno
, current
->attp
);
835 bounce_msg_att(ps
->mail_stream
, msgno
, current
->attp
->number
,
836 current
->attp
->body
->nested
.msg
->env
->subject
);
837 ps
->mangled_footer
= 1;
841 display_attach_info(msgno
, current
->attp
);
844 case MC_VIEW_ATCH
: /* View command */
845 display_attachment(msgno
, current
->attp
, DA_SAVE
);
847 /* fall thru to repaint */
849 case MC_REPAINT
: /* redraw */
851 ps
->mangled_screen
= 1;
855 export_attachment(-FOOTER_ROWS(ps
), msgno
, current
->attp
);
856 ps
->mangled_footer
= 1;
859 case MC_SAVETEXT
: /* Save command */
860 save_attachment(-FOOTER_ROWS(ps
), msgno
, current
->attp
);
861 ps
->mangled_footer
= 1;
864 case MC_PRINTMSG
: /* Save command */
865 print_attachment(-FOOTER_ROWS(ps
), msgno
, current
->attp
);
866 ps
->mangled_footer
= 1;
869 case MC_PIPE
: /* Pipe command */
870 if(F_ON(F_ENABLE_PIPE
, ps
)){
871 pipe_attachment(msgno
, current
->attp
);
872 ps
->mangled_footer
= 1;
874 } /* fall thru to complain */
876 case MC_NONE
: /* simple timeout */
880 bogus_utf8_command(utf8str
, F_ON(F_USE_FK
, ps
) ? "F1" : "?");
891 bogus_command(ch
, F_ON(F_USE_FK
, ps
) ? "F1" : "?");
896 for(current
= first_attline(current
); current
;){ /* clean up */
897 ctmp
= current
->next
;
898 free_attline(¤t
);
902 if(screen
.titlecolor
)
903 free_color_pair(&screen
.titlecolor
);
907 /*----------------------------------------------------------------------
908 allocate and attach a fresh attachment line struct
910 Args: current -- display line to attache new struct to
912 Returns: newly alloc'd attachment display line
915 new_attline(ATDISP_S
**current
)
919 p
= (ATDISP_S
*)fs_get(sizeof(ATDISP_S
));
920 memset((void *)p
, 0, sizeof(ATDISP_S
));
923 p
->next
= (*current
)->next
;
924 (*current
)->next
= p
;
937 /*----------------------------------------------------------------------
938 Release system resources associated with attachment display line
940 Args: p -- line to free
945 free_attline(ATDISP_S
**p
)
949 fs_give((void **)&(*p
)->dstring
);
956 /*----------------------------------------------------------------------
957 Manage display of the attachment screen menu body.
959 Args: ps -- pine struct pointer
960 current -- currently selected display line
961 screen -- reference points for display painting
966 attachment_screen_updater(struct pine
*ps
, ATDISP_S
*current
, ATT_SCREEN_S
*screen
)
968 int dline
, return_line
= HEADER_ROWS(ps
);
969 ATDISP_S
*top_line
, *ctmp
;
971 /* calculate top line of display */
973 ctmp
= top_line
= first_attline(current
);
975 if(((dline
++)%(ps
->ttyo
->screen_rows
-HEADER_ROWS(ps
)-FOOTER_ROWS(ps
)))==0)
977 while(ctmp
!= current
&& (ctmp
= next_attline(ctmp
)));
980 /* Don't know how to manage scroll bar for attachment screen yet. */
981 scroll_setrange (0L, 0L);
984 /* mangled body or new page, force redraw */
985 if(ps
->mangled_body
|| screen
->top_line
!= top_line
)
986 screen
->current
= NULL
;
988 /* loop thru painting what's needed */
989 for(dline
= 0, ctmp
= top_line
;
990 dline
< ps
->ttyo
->screen_rows
- FOOTER_ROWS(ps
) - HEADER_ROWS(ps
);
991 dline
++, ctmp
= next_attline(ctmp
)){
994 * only fall thru painting if something needs painting...
996 if(!(!screen
->current
|| ctmp
== screen
->current
|| ctmp
== current
))
999 if(ctmp
&& ctmp
->dstring
){
1000 char *p
= tmp_20k_buf
;
1001 int i
, col
, x
= 0, totlen
;
1003 if(F_ON(F_FORCE_LOW_SPEED
,ps
) || ps
->low_speed
){
1005 if(ctmp
== current
){
1006 return_line
= dline
+ HEADER_ROWS(ps
);
1007 PutLine0(dline
+ HEADER_ROWS(ps
), 0, "->");
1010 PutLine0(dline
+ HEADER_ROWS(ps
), 0, " ");
1013 * Only paint lines if we have to...
1018 else if(ctmp
== current
){
1019 return_line
= dline
+ HEADER_ROWS(ps
);
1023 totlen
= strlen(ctmp
->dstring
);
1026 * Copy the value to a temp buffer expanding tabs.
1027 * Assume the caller set the widths so as not to overflow the
1030 for(i
=0,col
=x
; ctmp
->dstring
[i
]; i
++){
1031 if(ctmp
->dstring
[i
] == TAB
){
1032 if((p
-tmp_20k_buf
) < SIZEOF_20KBUF
-8)
1035 while((++col
)&0x07);
1038 col
+= width_at_this_position((unsigned char *) &ctmp
->dstring
[i
], totlen
-i
);
1039 if((p
-tmp_20k_buf
) < SIZEOF_20KBUF
)
1040 *p
++ = ctmp
->dstring
[i
];
1045 if((p
-tmp_20k_buf
) < SIZEOF_20KBUF
)
1048 PutLine0(dline
+ HEADER_ROWS(ps
), x
, tmp_20k_buf
+ x
);
1051 && !(F_ON(F_FORCE_LOW_SPEED
,ps
) || ps
->low_speed
))
1055 ClearLine(dline
+ HEADER_ROWS(ps
));
1058 ps
->mangled_body
= 0;
1059 screen
->top_line
= top_line
;
1060 screen
->current
= current
;
1061 return(return_line
);
1065 /*----------------------------------------------------------------------
1066 Redraw the attachment screen based on the global "att_screen" struct
1073 attachment_screen_redrawer(void)
1077 update_att_screen_titlebar();
1078 ps_global
->mangled_header
= 0;
1081 ps_global
->mangled_body
= 1;
1082 (void)attachment_screen_updater(ps_global
,att_screen
->current
,att_screen
);
1085 draw_keymenu(&att_index_keymenu
, bitmap
, ps_global
->ttyo
->screen_cols
,
1086 1-FOOTER_ROWS(ps_global
), 0, SameMenu
);
1091 update_att_screen_titlebar(void)
1094 COLOR_PAIR
*returned_color
= NULL
;
1095 COLOR_PAIR
*titlecolor
= NULL
;
1097 SEARCHSET
*ss
= NULL
;
1098 PAT_STATE
*pstate
= NULL
;
1100 if(ps_global
->titlebar_color_style
!= TBAR_COLOR_DEFAULT
){
1101 raw_msgno
= mn_m2raw(ps_global
->msgmap
, mn_get_cur(ps_global
->msgmap
));
1102 ss
= mail_newsearchset();
1103 ss
->first
= ss
->last
= (unsigned long) raw_msgno
;
1106 colormatch
= get_index_line_color(ps_global
->mail_stream
,
1107 ss
, &pstate
, &returned_color
);
1108 mail_free_searchset(&ss
);
1111 * This is a bit tricky. If there is a colormatch but
1113 * is NULL, that means that the user explicitly wanted the
1114 * Normal color used in this index line, so that is what we
1115 * use. If no colormatch then we will use the TITLE color
1116 * instead of Normal.
1120 titlecolor
= returned_color
;
1122 titlecolor
= new_color_pair(ps_global
->VAR_NORM_FORE_COLOR
,
1123 ps_global
->VAR_NORM_BACK_COLOR
);
1127 && ps_global
->titlebar_color_style
== TBAR_COLOR_REV_INDEXLINE
){
1128 char cbuf
[MAXCOLORLEN
+1];
1130 strncpy(cbuf
, titlecolor
->fg
, sizeof(cbuf
));
1131 cbuf
[sizeof(cbuf
)-1] = '\0';
1132 strncpy(titlecolor
->fg
, titlecolor
->bg
, MAXCOLORLEN
);
1133 titlecolor
->fg
[MAXCOLORLEN
] = '\0';
1134 strncpy(titlecolor
->bg
, cbuf
, MAXCOLORLEN
);
1135 titlecolor
->bg
[MAXCOLORLEN
] = '\0';
1139 /* Did the color change? */
1140 if((!titlecolor
&& att_screen
->titlecolor
)
1142 (titlecolor
&& !att_screen
->titlecolor
)
1144 (titlecolor
&& att_screen
->titlecolor
1145 && (strcmp(titlecolor
->fg
, att_screen
->titlecolor
->fg
)
1146 || strcmp(titlecolor
->bg
, att_screen
->titlecolor
->bg
)))){
1148 if(att_screen
->titlecolor
)
1149 free_color_pair(&att_screen
->titlecolor
);
1151 att_screen
->titlecolor
= titlecolor
;
1156 free_color_pair(&titlecolor
);
1159 set_titlebar(_("ATTACHMENT INDEX"), ps_global
->mail_stream
,
1160 ps_global
->context_current
, ps_global
->cur_folder
,
1161 ps_global
->msgmap
, 1, MessageNumber
, 0, 0,
1162 att_screen
->titlecolor
);
1166 /*----------------------------------------------------------------------
1167 Seek back from the given display line to the beginning of the list
1169 Args: p -- display linked list
1174 first_attline(ATDISP_S
*p
)
1184 init_att_progress(char *msg
, MAILSTREAM
*stream
, struct mail_bodystruct
*body
)
1186 if((save_att_length
= body
->size
.bytes
) != 0){
1187 /* if there are display filters, factor in extra copy */
1188 if(body
->type
== TYPETEXT
&& ps_global
->VAR_DISPLAY_FILTERS
)
1189 save_att_length
+= body
->size
.bytes
;
1191 /* if remote folder and segment not cached, factor in IMAP fetch */
1192 if(stream
&& stream
->mailbox
&& IS_REMOTE(stream
->mailbox
)
1193 && !((body
->type
== TYPETEXT
&& body
->contents
.text
.data
)
1194 || ((body
->type
== TYPEMESSAGE
)
1195 && body
->nested
.msg
&& body
->nested
.msg
->text
.text
.data
)
1196 || body
->contents
.text
.data
))
1197 save_att_length
+= body
->size
.bytes
;
1199 gf_filter_init(); /* reset counters */
1202 return(busy_cue(msg
, save_att_percent
, 0));
1210 save_att_piped(int reset
)
1218 else if((y
= gf_bytes_piped()) >= x
){
1228 save_att_percent(void)
1230 int i
= (int) (((pine_gets_bytes(0) + save_att_piped(0)) * 100)
1232 return(MIN(i
, 100));
1236 /*----------------------------------------------------------------------
1237 Save the given attachment associated with the given message no
1244 save_attachment(int qline
, long int msgno
, ATTACH_S
*a
)
1246 if(ps_global
->restricted
){
1247 q_status_message(SM_ORDER
| SM_DING
, 0, 4,
1248 "Alpine demo can't save attachments");
1253 save_msg_att(msgno
, a
);
1254 else if(MIME_DGST_A(a
))
1255 save_digest_att(msgno
, a
);
1256 else if(MIME_VCARD_A(a
))
1257 save_vcard_att(ps_global
, qline
, msgno
, a
);
1259 write_attachment(qline
, msgno
, a
, "SAVE");
1263 /*----------------------------------------------------------------------
1264 Save the given attachment associated with the given message no
1271 export_attachment(int qline
, long int msgno
, ATTACH_S
*a
)
1273 if(ps_global
->restricted
){
1274 q_status_message(SM_ORDER
| SM_DING
, 0, 4,
1275 "Alpine demo can't export attachments");
1280 export_msg_att(msgno
, a
);
1281 else if(MIME_DGST_A(a
))
1282 export_digest_att(msgno
, a
);
1284 q_status_message1(SM_ORDER
, 0, 3,
1285 _("Can't Export %s. Use \"Save\" to write file, \"<\" to leave index."),
1286 body_type_names(a
->body
->type
));
1291 write_attachment(int qline
, long int msgno
, ATTACH_S
*a
, char *method
)
1293 char filename
[MAXPATH
+1], full_filename
[MAXPATH
+1],
1294 title_buf
[64], *err
;
1295 int r
, rflags
= GER_NONE
, we_cancel
= 0;
1296 static HISTORY_S
*history
= NULL
;
1297 static ESCKEY_S att_save_opts
[] = {
1298 {ctrl('T'), 10, "^T", N_("To Files")},
1299 {-1, 0, NULL
, NULL
},
1300 {-1, 0, NULL
, NULL
},
1301 {-1, 0, NULL
, NULL
}};
1303 /*------- Figure out suggested file name ----*/
1304 filename
[0] = full_filename
[0] = '\0';
1305 (void) get_filename_parameter(filename
, sizeof(filename
), a
->body
, NULL
);
1307 dprint((9, "export_attachment(name: %s)\n",
1308 filename
? filename
: "?"));
1311 #if !defined(DOS) && !defined(MAC) && !defined(OS2)
1312 if(ps_global
->VAR_DOWNLOAD_CMD
&& ps_global
->VAR_DOWNLOAD_CMD
[0]){
1313 att_save_opts
[++r
].ch
= ctrl('V');
1314 att_save_opts
[r
].rval
= 12;
1315 att_save_opts
[r
].name
= "^V";
1316 att_save_opts
[r
].label
= N_("Downld Msg");
1318 #endif /* !(DOS || MAC) */
1320 if(F_ON(F_ENABLE_TAB_COMPLETE
,ps_global
)){
1321 att_save_opts
[++r
].ch
= ctrl('I');
1322 att_save_opts
[r
].rval
= 11;
1323 att_save_opts
[r
].name
= "TAB";
1324 att_save_opts
[r
].label
= N_("Complete");
1327 att_save_opts
[++r
].ch
= -1;
1329 snprintf(title_buf
, sizeof(title_buf
), "%s ATTACHMENT", method
);
1330 title_buf
[sizeof(title_buf
)-1] = '\0';
1332 r
= get_export_filename(ps_global
, filename
, NULL
, full_filename
,
1333 sizeof(filename
), "attachment", title_buf
,
1334 att_save_opts
, &rflags
, qline
, GE_SEQ_SENSITIVE
, &history
);
1339 cmd_cancelled((char *) lcase((unsigned char *) title_buf
+ 1) - 1);
1343 q_status_message1(SM_ORDER
, 0, 2,
1344 _("Can't save to file outside of %s"),
1345 ps_global
->VAR_OPER_DIR
);
1351 #if !defined(DOS) && !defined(MAC) && !defined(OS2)
1352 else if(r
== 12){ /* Download */
1353 char cmd
[MAXPATH
], *tfp
= NULL
;
1358 char prompt_buf
[256];
1360 if(ps_global
->restricted
){
1361 q_status_message(SM_ORDER
| SM_DING
, 3, 3,
1362 "Download disallowed in restricted mode");
1367 tfp
= temp_nam(NULL
, "pd");
1368 dprint((1, "Download attachment called!\n"));
1369 if((store
= so_get(FileStar
, tfp
, WRITE_ACCESS
|OWNER_ONLY
|WRITE_TO_LOCALE
)) != NULL
){
1371 snprintf(prompt_buf
, sizeof(prompt_buf
), "Saving to \"%s\"", tfp
);
1372 prompt_buf
[sizeof(prompt_buf
)-1] = '\0';
1373 we_cancel
= init_att_progress(prompt_buf
,
1374 ps_global
->mail_stream
,
1377 gf_set_so_writec(&pc
, store
);
1378 if((err
= detach(ps_global
->mail_stream
, msgno
,
1379 a
->number
, 0L, &len
, pc
, NULL
, 0)) != NULL
)
1380 q_status_message2(SM_ORDER
| SM_DING
, 3, 5,
1381 "%s: Error writing attachment to \"%s\"",
1384 /* cancel regardless, so it doesn't get in way of xfer */
1387 gf_clear_so_writec(store
);
1388 if(so_give(&store
)) /* close file */
1389 err
= "Error writing tempfile for download";
1392 build_updown_cmd(cmd
, sizeof(cmd
), ps_global
->VAR_DOWNLOAD_CMD_PREFIX
,
1393 ps_global
->VAR_DOWNLOAD_CMD
, tfp
);
1394 if((syspipe
= open_system_pipe(cmd
, NULL
, NULL
,
1395 PIPE_USER
| PIPE_RESET
,
1396 0, pipe_callback
, pipe_report_error
)) != NULL
)
1397 (void)close_system_pipe(&syspipe
, NULL
, pipe_callback
);
1399 q_status_message(SM_ORDER
| SM_DING
, 3, 3,
1400 err
= "Error running download command");
1404 q_status_message(SM_ORDER
| SM_DING
, 3, 3,
1405 err
= "Error building temp file for download");
1409 fs_give((void **)&tfp
);
1413 q_status_message1(SM_ORDER
, 0, 4, "Part %s downloaded",
1418 #endif /* !(DOS || MAC) */
1420 (void) write_attachment_to_file(ps_global
->mail_stream
, msgno
, a
,
1421 rflags
, full_filename
);
1427 * msgno -- raw message number
1428 * a -- attachment struct
1429 * flags -- comes from get_export_filename
1430 * GER_OVER -- the file was truncated before we wrote
1431 * GER_APPEND -- the file was not truncated prior to our writing,
1432 * so we were appending
1433 * else -- the file didn't previously exist
1434 * file -- the full pathname of the file
1436 * Returns 1 for successful write, 0 for nothing to write, -1 for error
1439 write_attachment_to_file(MAILSTREAM
*stream
, long int msgno
, ATTACH_S
*a
, int flags
, char *file
)
1441 char *l_string
, sbuf
[256], *err
;
1442 int is_text
, we_cancel
= 0;
1443 long len
, orig_size
;
1447 if(!(a
&& a
->body
&& a
->number
&& a
->number
[0] && file
&& file
[0]
1451 is_text
= (a
&& a
->body
&& a
->body
->type
== TYPETEXT
);
1453 if(flags
& GER_APPEND
)
1454 orig_size
= name_file_size(file
);
1456 store
= so_get(FileStar
, file
, WRITE_ACCESS
| (is_text
? WRITE_TO_LOCALE
: 0));
1458 q_status_message2(SM_ORDER
| SM_DING
, 3, 5,
1459 /* TRANSLATORS: Error opening destination <filename>: <error text> */
1460 _("Error opening destination %s: %s"),
1461 file
, error_description(errno
));
1465 snprintf(sbuf
, sizeof(sbuf
), "Saving to \"%s\"", file
);
1466 sbuf
[sizeof(sbuf
)-1] = '\0';
1467 we_cancel
= init_att_progress(sbuf
, stream
, a
->body
);
1469 gf_set_so_writec(&pc
, store
);
1470 err
= detach(stream
, msgno
, a
->number
, 0L, &len
, pc
, NULL
, 0);
1471 gf_clear_so_writec(store
);
1476 if(so_give(&store
)) /* close file */
1477 err
= error_description(errno
);
1480 if(!(flags
& (GER_APPEND
| GER_OVER
)))
1483 our_truncate(file
, (flags
& GER_APPEND
) ? (off_t
) orig_size
: (off_t
) 0);
1485 q_status_message2(SM_ORDER
| SM_DING
, 3, 5,
1486 /* TRANSLATORS: <error text>: Error writing attachment to <filename> */
1487 _("%s: Error writing attachment to \"%s\""),
1492 l_string
= cpystr(byte_string(len
));
1493 q_status_message8(SM_ORDER
, 0, 4,
1494 "Part %s, %s%s %s to \"%s\"%s%s%s",
1497 ? comatose(a
->body
->size
.lines
) : l_string
,
1498 is_text
? " lines" : "",
1501 : flags
& GER_APPEND
? "appended" : "written",
1503 (is_text
|| len
== a
->body
->size
.bytes
)
1504 ? "" : "(decoded from ",
1505 (is_text
|| len
== a
->body
->size
.bytes
)
1506 ? "" : byte_string(a
->body
->size
.bytes
),
1507 is_text
|| len
== a
->body
->size
.bytes
1509 fs_give((void **)&l_string
);
1516 write_attached_msg(long int msgno
, ATTACH_S
**ap
, STORE_S
*store
, int newfile
)
1519 long start_of_append
;
1523 if(ap
&& *ap
&& (*ap
)->body
&& (*ap
)->body
->nested
.msg
1524 && (*ap
)->body
->nested
.msg
->env
){
1525 start_of_append
= so_tell(store
);
1527 gf_set_so_writec(&pc
, store
);
1528 if(!(ps_global
->mail_stream
&& msgno
> 0L
1529 && msgno
<= ps_global
->mail_stream
->nmsgs
1530 && (mc
= mail_elt(ps_global
->mail_stream
, msgno
)) && mc
->valid
))
1533 if(!bezerk_delimiter((*ap
)->body
->nested
.msg
->env
, mc
, pc
, newfile
)
1534 || !format_msg_att(msgno
, ap
, NULL
, pc
, FM_NOINDENT
))
1535 err
= error_description(errno
);
1537 gf_clear_so_writec(store
);
1540 ftruncate(fileno((FILE *)store
->txt
), (off_t
) start_of_append
);
1543 err
= "Can't export message. Missing Envelope data";
1549 /*----------------------------------------------------------------------
1550 Save the attachment message/rfc822 to specified folder
1557 save_msg_att(long int msgno
, ATTACH_S
*a
)
1559 char newfolder
[MAILTMPLEN
], *save_folder
, *flags
= NULL
;
1560 char date
[64], nmsgs
[80];
1561 CONTEXT_S
*cntxt
= NULL
;
1562 int our_stream
= 0, rv
;
1563 MAILSTREAM
*save_stream
;
1566 snprintf(nmsgs
, sizeof(nmsgs
), _("Attached Msg (part %s) "), a
->number
);
1567 nmsgs
[sizeof(nmsgs
)-1] = '\0';
1568 if(save_prompt(ps_global
, &cntxt
, newfolder
, sizeof(newfolder
), nmsgs
,
1569 a
->body
->nested
.msg
->env
, msgno
, a
->number
, NULL
, NULL
)){
1570 if(strucmp(newfolder
, ps_global
->inbox_name
) == 0){
1571 save_folder
= ps_global
->VAR_INBOX_PATH
;
1575 save_folder
= newfolder
;
1577 save_stream
= save_msg_stream(cntxt
, save_folder
, &our_stream
);
1579 mc
= (msgno
> 0L && ps_global
->mail_stream
1580 && msgno
<= ps_global
->mail_stream
->nmsgs
)
1581 ? mail_elt(ps_global
->mail_stream
, msgno
) : NULL
;
1582 flags
= flag_string(ps_global
->mail_stream
, msgno
, F_ANS
|F_FLAG
|F_SEEN
|F_KEYWORD
);
1584 mail_date(date
, mc
);
1588 if(pith_opt_save_size_changed_prompt
)
1589 (*pith_opt_save_size_changed_prompt
)(0L, SSCP_INIT
);
1591 rv
= save_msg_att_work(msgno
, a
, save_stream
, save_folder
, cntxt
, date
);
1593 if(pith_opt_save_size_changed_prompt
)
1594 (*pith_opt_save_size_changed_prompt
)(0L, SSCP_END
);
1597 fs_give((void **) &flags
);
1600 q_status_message2(SM_ORDER
, 0, 4,
1601 _("Attached message (part %s) saved to \"%s\""),
1605 cmd_cancelled("Attached message Save");
1606 /* else whatever broke in save_fetch_append shoulda bitched */
1609 mail_close(save_stream
);
1614 /*----------------------------------------------------------------------
1615 Save the message/rfc822 in the given digest to the specified folder
1622 save_digest_att(long int msgno
, ATTACH_S
*a
)
1624 char newfolder
[MAILTMPLEN
], *save_folder
,
1625 date
[64], nmsgs
[80];
1626 CONTEXT_S
*cntxt
= NULL
;
1627 int our_stream
= 0, rv
, cnt
= 0;
1628 MAILSTREAM
*save_stream
;
1633 && !strncmp(a
->number
, ap
->number
, strlen(a
->number
));
1635 if(MIME_MSG(ap
->body
->type
, ap
->body
->subtype
))
1638 snprintf(nmsgs
, sizeof(nmsgs
), "%d Msg Digest (part %s) ", cnt
, a
->number
);
1639 nmsgs
[sizeof(nmsgs
)-1] = '\0';
1641 if(save_prompt(ps_global
, &cntxt
, newfolder
, sizeof(newfolder
),
1642 nmsgs
, NULL
, 0, NULL
, NULL
, NULL
)){
1643 save_folder
= (strucmp(newfolder
, ps_global
->inbox_name
) == 0)
1644 ? ps_global
->VAR_INBOX_PATH
: newfolder
;
1646 save_stream
= save_msg_stream(cntxt
, save_folder
, &our_stream
);
1648 if(pith_opt_save_size_changed_prompt
)
1649 (*pith_opt_save_size_changed_prompt
)(0L, SSCP_INIT
);
1653 && !strncmp(a
->number
, ap
->number
, strlen(a
->number
));
1655 if(MIME_MSG(ap
->body
->type
, ap
->body
->subtype
)){
1657 rv
= save_msg_att_work(msgno
, ap
, save_stream
, save_folder
, cntxt
, date
);
1662 if(pith_opt_save_size_changed_prompt
)
1663 (*pith_opt_save_size_changed_prompt
)(0L, SSCP_END
);
1666 q_status_message2(SM_ORDER
, 0, 4,
1667 _("Attached digest (part %s) saved to \"%s\""),
1671 cmd_cancelled("Attached digest Save");
1672 /* else whatever broke in save_fetch_append shoulda bitched */
1675 mail_close(save_stream
);
1681 save_msg_att_work(long int msgno
, ATTACH_S
*a
, MAILSTREAM
*save_stream
,
1682 char *save_folder
, CONTEXT_S
*cntxt
, char *date
)
1687 if(a
&& a
->body
&& MIME_MSG(a
->body
->type
, a
->body
->subtype
)){
1688 if((so
= so_get(CharStar
, NULL
, WRITE_ACCESS
)) != NULL
){
1690 rv
= save_fetch_append(ps_global
->mail_stream
, msgno
,
1692 save_stream
, save_folder
, cntxt
,
1693 a
->body
->size
.bytes
,
1697 dprint((1, "Can't allocate store for save: %s\n",
1698 error_description(errno
)));
1699 q_status_message(SM_ORDER
| SM_DING
, 3, 4,
1700 _("Problem creating space for message text."));
1709 /*----------------------------------------------------------------------
1710 Export the attachment message/rfc822 to specified file
1717 export_msg_att(long int msgno
, ATTACH_S
*a
)
1719 char filename
[MAXPATH
+1], full_filename
[MAXPATH
+1], *err
;
1720 int rv
, rflags
= GER_NONE
, i
= 1;
1723 static HISTORY_S
*history
= NULL
;
1724 static ESCKEY_S opts
[] = {
1725 {ctrl('T'), 10, "^T", N_("To Files")},
1726 {-1, 0, NULL
, NULL
},
1727 {-1, 0, NULL
, NULL
}};
1729 if(F_ON(F_ENABLE_TAB_COMPLETE
,ps_global
)){
1730 opts
[i
].ch
= ctrl('I');
1732 opts
[i
].name
= "TAB";
1733 opts
[i
].label
= N_("Complete");
1736 filename
[0] = full_filename
[0] = '\0';
1738 rv
= get_export_filename(ps_global
, filename
, NULL
, full_filename
,
1739 sizeof(filename
), "msg attachment",
1740 /* TRANSLATORS: Message Attachment (a screen title) */
1741 _("MSG ATTACHMENT"), opts
,
1742 &rflags
, -FOOTER_ROWS(ps_global
),
1743 GE_IS_EXPORT
| GE_SEQ_SENSITIVE
, &history
);
1748 cmd_cancelled("Export");
1752 q_status_message1(SM_ORDER
, 0, 2,
1753 _("Can't export to file outside of %s"),
1754 ps_global
->VAR_OPER_DIR
);
1761 /* With name in hand, allocate storage object and save away... */
1762 if((store
= so_get(FileStar
, full_filename
, WRITE_ACCESS
)) != NULL
){
1763 if((err
= write_attached_msg(msgno
, &ap
, store
, !(rflags
& GER_APPEND
))) != NULL
)
1764 q_status_message(SM_ORDER
| SM_DING
, 3, 4, err
);
1766 q_status_message3(SM_ORDER
, 0, 4,
1767 _("Attached message (part %s) %s to \"%s\""),
1771 : rflags
& GER_APPEND
? _("appended") : _("written"),
1775 q_status_message2(SM_ORDER
| SM_DING
, 3, 4,
1776 _("Error writing %s: %s"),
1777 full_filename
, error_description(errno
));
1780 q_status_message2(SM_ORDER
| SM_DING
, 3, 4,
1781 /* TRANSLATORS: Error opening file <filename> to export message: <error text> */
1782 _("Error opening file \"%s\" to export message: %s"),
1783 full_filename
, error_description(errno
));
1787 /*----------------------------------------------------------------------
1788 Export the message/rfc822 in the given digest to the specified file
1795 export_digest_att(long int msgno
, ATTACH_S
*a
)
1797 char filename
[MAXPATH
+1], full_filename
[MAXPATH
+1], *err
= NULL
;
1798 int rv
, rflags
= GER_NONE
, i
= 1;
1801 static HISTORY_S
*history
= NULL
;
1803 static ESCKEY_S opts
[] = {
1804 {ctrl('T'), 10, "^T", N_("To Files")},
1805 {-1, 0, NULL
, NULL
},
1806 {-1, 0, NULL
, NULL
}};
1808 if(F_ON(F_ENABLE_TAB_COMPLETE
,ps_global
)){
1809 opts
[i
].ch
= ctrl('I');
1811 opts
[i
].name
= "TAB";
1812 opts
[i
].label
= N_("Complete");
1815 filename
[0] = full_filename
[0] = '\0';
1817 rv
= get_export_filename(ps_global
, filename
, NULL
, full_filename
,
1818 sizeof(filename
), "digest", _("DIGEST ATTACHMENT"),
1819 opts
, &rflags
, -FOOTER_ROWS(ps_global
),
1820 GE_IS_EXPORT
| GE_SEQ_SENSITIVE
, &history
);
1825 cmd_cancelled("Export");
1829 q_status_message1(SM_ORDER
, 0, 2,
1830 _("Can't export to file outside of %s"),
1831 ps_global
->VAR_OPER_DIR
);
1838 /* With name in hand, allocate storage object and save away... */
1839 if((store
= so_get(FileStar
, full_filename
, WRITE_ACCESS
)) != NULL
){
1844 && !strncmp(a
->number
, ap
->number
, strlen(a
->number
))
1847 if(MIME_MSG(ap
->body
->type
, ap
->body
->subtype
)){
1849 err
= write_attached_msg(msgno
, &ap
, store
,
1850 !count
&& !(rflags
& GER_APPEND
));
1855 err
= error_description(errno
);
1858 q_status_message1(SM_ORDER
| SM_DING
, 3, 3,
1859 _("Error exporting: %s"), err
);
1860 q_status_message1(SM_ORDER
| SM_DING
, 3, 3,
1861 _("%s messages exported before error occurred"), err
);
1864 q_status_message4(SM_ORDER
, 0, 4,
1865 "%s messages in digest (part %s) %s to \"%s\"",
1870 : rflags
& GER_APPEND
? "appended" : "written",
1874 q_status_message2(SM_ORDER
| SM_DING
, 3, 4,
1875 _("Error opening file \"%s\" to export digest: %s"),
1876 full_filename
, error_description(errno
));
1880 /*----------------------------------------------------------------------
1881 Print the given attachment associated with the given message no
1888 print_attachment(int qline
, long int msgno
, ATTACH_S
*a
)
1892 if(ps_global
->restricted
){
1893 q_status_message(SM_ORDER
| SM_DING
, 0, 4,
1894 "Alpine demo can't Print attachments");
1898 snprintf(prompt
, sizeof(prompt
), "attach%s %s",
1899 (a
->body
->type
== TYPETEXT
) ? "ment" : "ed message",
1900 MIME_DGST_A(a
) ? "digest" : a
->number
);
1901 prompt
[sizeof(prompt
)-1] = '\0';
1902 if(open_printer(prompt
) >= 0){
1904 (void) print_msg_att(msgno
, a
, 1);
1905 else if(MIME_DGST_A(a
))
1906 print_digest_att(msgno
, a
);
1908 (void) decode_text(a
, msgno
, print_char
, NULL
, QStatus
, FM_NOINDENT
);
1916 * Print the attachment message/rfc822 to specified file
1918 * Returns 1 on success, 0 on failure.
1921 print_msg_att(long int msgno
, ATTACH_S
*a
, int first
)
1926 if(!(ps_global
->mail_stream
&& msgno
> 0L
1927 && msgno
<= ps_global
->mail_stream
->nmsgs
1928 && (mc
= mail_elt(ps_global
->mail_stream
, msgno
)) && mc
->valid
))
1931 if(((!first
&& F_ON(F_AGG_PRINT_FF
, ps_global
)) ? print_char(FORMFEED
) : 1)
1932 && pine_mail_fetchstructure(ps_global
->mail_stream
, msgno
, NULL
)
1933 && (F_ON(F_FROM_DELIM_IN_PRINT
, ps_global
)
1934 ? bezerk_delimiter(a
->body
->nested
.msg
->env
, mc
, print_char
, !first
)
1936 && format_msg_att(msgno
, &ap
, NULL
, print_char
, FM_NOINDENT
))
1940 q_status_message2(SM_ORDER
| SM_DING
, 3, 3,
1941 _("Error printing message %s, part %s"),
1942 long2string(msgno
), a
->number
);
1947 /*----------------------------------------------------------------------
1948 Print the attachment message/rfc822 to specified file
1955 print_digest_att(long int msgno
, ATTACH_S
*a
)
1962 && !strncmp(a
->number
, ap
->number
, strlen(a
->number
));
1964 if(MIME_MSG(ap
->body
->type
, ap
->body
->subtype
)){
1965 char *p
= part_desc(ap
->number
, ap
->body
->nested
.msg
->body
,
1966 0, 80, FM_NOINDENT
, print_char
);
1968 q_status_message1(SM_ORDER
| SM_DING
, 3, 3,
1969 _("Can't print digest: %s"), p
);
1972 else if(!print_msg_att(msgno
, ap
, !next
))
1981 /*----------------------------------------------------------------------
1982 Unpack and display the given attachment associated with given message no.
1984 Args: msgno -- message no attachment is part of
1985 a -- attachment to display
1987 Returns: 0 on success, non-zero (and error message queued) otherwise
1990 display_attachment(long int msgno
, ATTACH_S
*a
, int flags
)
1992 char *filename
= NULL
;
1993 char sender_filename
[1000];
1998 int we_cancel
= 0, rv
;
2003 /*------- Display the attachment -------*/
2004 if(dispatch_attachment(a
) == MCD_NONE
){
2005 /*----- Can't display this type ------*/
2006 if(a
->body
->encoding
< ENCOTHER
)
2007 q_status_message4(SM_ORDER
| SM_DING
, 3, 5,
2008 /* TRANSLATORS: Don't know how to display <certain type> attachments. <might say Try Save.> */
2009 _("Don't know how to display %s%s%s attachments.%s"),
2010 body_type_names(a
->body
->type
),
2011 a
->body
->subtype
? "/" : "",
2012 a
->body
->subtype
? a
->body
->subtype
:"",
2013 (flags
& DA_SAVE
) ? _(" Try Save.") : "");
2015 q_status_message1(SM_ORDER
| SM_DING
, 3, 5,
2016 _("Don't know how to unpack \"%s\" encoding"),
2017 body_encodings
[(a
->body
->encoding
<= ENCMAX
)
2018 ? a
->body
->encoding
: ENCOTHER
]);
2022 else if(!(a
->can_display
& MCD_EXTERNAL
)){
2023 if(a
->body
->type
== TYPEMULTIPART
){
2024 if(a
->body
->subtype
){
2025 if(!strucmp(a
->body
->subtype
, "digest"))
2026 display_digest_att(msgno
, a
, flags
);
2028 q_status_message1(SM_ORDER
, 3, 5,
2029 _("Can't display Multipart/%s"),
2033 q_status_message(SM_ORDER
, 3, 5,
2034 _("Can't display unknown Multipart Subtype"));
2036 else if(MIME_VCARD_A(a
))
2037 display_vcard_att(msgno
, a
, flags
);
2038 else if(a
->body
->type
== TYPETEXT
){
2040 rv
= display_text_att(msgno
, a
, flags
);
2041 } while(rv
== MC_FULLHDR
);
2043 else if(a
->body
->type
== TYPEMESSAGE
){
2045 rv
= display_msg_att(msgno
, a
, flags
);
2046 } while(rv
== MC_FULLHDR
);
2049 ps_global
->mangled_screen
= 1;
2053 /* arrive here if MCD_EXTERNAL */
2055 if(F_OFF(F_QUELL_ATTACH_EXTRA_PROMPT
, ps_global
)
2056 && (!(flags
& DA_DIDPROMPT
)))
2057 if(want_to(_("View selected Attachment"), 'y',
2058 0, NO_HELP
, WT_NORM
) == 'n'){
2059 cmd_cancelled(NULL
);
2063 sender_filename
[0] = '\0';
2067 if(F_OFF(F_QUELL_ATTACH_EXT_WARN
, ps_global
)
2068 && (a
->can_display
& MCD_EXT_PROMPT
)){
2071 (void) get_filename_parameter(sender_filename
, sizeof(sender_filename
),
2073 snprintf(prompt
, sizeof(prompt
),
2074 "Attachment %s%s unrecognized. %s%s%s",
2076 strlen(a
->body
->subtype
) > 12 ? "..." : "",
2077 (extp
&& extp
[0]) ? "Try open by file extension (." : "Try opening anyway",
2078 (extp
&& extp
[0]) ? extp
: "",
2079 (extp
&& extp
[0]) ? ")" : "");
2081 if(want_to(prompt
, 'n', 0, NO_HELP
, WT_NORM
) == 'n'){
2082 cmd_cancelled(NULL
);
2087 /*------ Write the image to a temporary file ------*/
2089 /* create type/subtype in mtype */
2090 strncpy(mtype
, body_type_names(a
->body
->type
), sizeof(mtype
));
2091 mtype
[sizeof(mtype
)-1] = '\0';
2092 if(a
->body
->subtype
){
2093 strncat(mtype
, "/", sizeof(mtype
)-strlen(mtype
)-1);
2094 mtype
[sizeof(mtype
)-1] = '\0';
2095 strncat(mtype
, a
->body
->subtype
, sizeof(mtype
)-strlen(mtype
)-1);
2096 mtype
[sizeof(mtype
)-1] = '\0';
2100 * If we haven't already gotten the filename parameter, get it
2101 * now. It may be used in the temporary filename and possibly
2102 * for its extension.
2104 if(!sender_filename
[0])
2105 (void) get_filename_parameter(sender_filename
, sizeof(sender_filename
),
2108 if(!set_mime_extension_by_type(ext
, mtype
)){ /* extension from type */
2109 if(extp
&& extp
[0]){ /* extension from filename */
2110 strncpy(ext
, extp
, sizeof(ext
));
2111 ext
[sizeof(ext
)-1] = '\0';
2115 /* create a temp file */
2116 if(sender_filename
){
2119 /* get rid of any extension */
2120 if(mt_get_file_ext(sender_filename
, &q
) && q
&& q
> sender_filename
)
2123 /* be careful about what is allowed in the filename */
2124 for(p
= sender_filename
; *p
; p
++)
2125 if(!(isascii((unsigned char) *p
)
2126 && (isalnum((unsigned char) *p
)
2127 || *p
== '-' || *p
== '_' || *p
== '+' || *p
== '.' || *p
== '=')))
2130 if(!*p
) /* filename was ok to use */
2131 snprintf(prefix
, sizeof(prefix
), "img-%s-", sender_filename
);
2134 /* didn't get it yet */
2136 snprintf(prefix
, sizeof(prefix
), "img-%s-", (a
->body
->subtype
)
2137 ? a
->body
->subtype
: "unk");
2140 /* We are creating a temporary name. This is just a prefix. If you
2141 * need the original name, use the save command, so if the prefix
2142 * is too long, shorten it.
2144 if (strlen(prefix
) > 9){
2149 filename
= temp_nam_ext(NULL
, prefix
, ext
);
2152 q_status_message1(SM_ORDER
| SM_DING
, 3, 5,
2153 _("Error \"%s\", Can't create temporary file"),
2154 error_description(errno
));
2158 if((store
= so_get(FileStar
, filename
, WRITE_ACCESS
|OWNER_ONLY
)) == NULL
){
2159 q_status_message2(SM_ORDER
| SM_DING
, 3, 5,
2160 _("Error \"%s\", Can't write file %s"),
2161 error_description(errno
), filename
);
2163 our_unlink(filename
);
2164 fs_give((void **)&filename
);
2171 if(a
->body
->size
.bytes
){
2174 snprintf(msg_buf
, sizeof(msg_buf
), "Decoding %s%s%s%s",
2175 a
->description
? "\"" : "",
2176 a
->description
? a
->description
: "attachment number ",
2177 a
->description
? "" : a
->number
,
2178 a
->description
? "\"" : "");
2179 msg_buf
[sizeof(msg_buf
)-1] = '\0';
2180 we_cancel
= init_att_progress(msg_buf
, ps_global
->mail_stream
,
2184 if(a
->body
->type
== TYPEMULTIPART
){
2185 char *h
= mail_fetch_mime(ps_global
->mail_stream
, msgno
, a
->number
,
2188 /* Write to store while converting newlines */
2190 if(*h
== '\015' && *(h
+1) == '\012'){
2191 so_puts(store
, NEWLINE
);
2195 so_writec(*h
++, store
);
2198 gf_set_so_writec(&pc
, store
);
2200 err
= detach(ps_global
->mail_stream
, msgno
, a
->number
, 0L, NULL
, pc
, NULL
, 0);
2202 gf_clear_so_writec(store
);
2210 q_status_message2(SM_ORDER
| SM_DING
, 3, 5,
2211 "%s: Error saving image to temp file %s",
2214 our_unlink(filename
);
2215 fs_give((void **)&filename
);
2221 /*----- Run the viewer process ----*/
2222 run_viewer(filename
, a
->body
, a
->can_display
& MCD_EXT_PROMPT
);
2224 fs_give((void **)&filename
);
2230 /*----------------------------------------------------------------------
2231 Fish the required command from mailcap and run it
2233 Args: image_file -- The name of the file to pass viewer
2234 body -- body struct containing type/subtype of part
2236 A side effect may be that scrolltool is called as well if
2237 exec_mailcap_cmd has any substantial output...
2240 run_viewer(char *image_file
, struct mail_bodystruct
*body
, int chk_extension
)
2242 MCAP_CMD_S
*mc_cmd
= NULL
;
2243 int needs_terminal
= 0, we_cancel
= 0;
2245 we_cancel
= busy_cue("Displaying attachment", NULL
, 0);
2247 if((mc_cmd
= mailcap_build_command(body
->type
, body
->subtype
,
2249 &needs_terminal
, chk_extension
)) != NULL
){
2251 cancel_busy_cue(-1);
2253 exec_mailcap_cmd(mc_cmd
, image_file
, needs_terminal
);
2255 fs_give((void **)&mc_cmd
->command
);
2256 fs_give((void **)&mc_cmd
);
2260 cancel_busy_cue(-1);
2262 q_status_message1(SM_ORDER
, 3, 4, _("Cannot display %s attachment"),
2263 type_desc(body
->type
, body
->subtype
,
2264 body
->parameter
, NULL
, 1));
2269 /*----------------------------------------------------------------------
2270 Detach and provide for browsing a text body part
2272 Args: msgno -- raw message number to get part from
2273 a -- attachment struct for the desired part
2278 format_text_att(long int msgno
, ATTACH_S
*a
, HANDLE_S
**handlesp
)
2283 if((store
= so_get(CharStar
, NULL
, EDIT_ACCESS
)) != NULL
){
2285 init_handles(handlesp
);
2287 gf_set_so_writec(&pc
, store
);
2288 (void) decode_text(a
, msgno
, pc
, handlesp
, QStatus
, FM_DISPLAY
);
2289 gf_clear_so_writec(store
);
2296 /*----------------------------------------------------------------------
2297 Detach and provide for browsing a text body part
2299 Args: msgno -- raw message number to get part from
2300 a -- attachment struct for the desired part
2305 display_text_att(long int msgno
, ATTACH_S
*a
, int flags
)
2308 HANDLE_S
*handles
= NULL
;
2312 clear_index_cache_ent(ps_global
->mail_stream
, msgno
, 0);
2314 if((store
= format_text_att(msgno
, a
, &handles
)) != NULL
){
2315 rv
= scroll_attachment("ATTACHED TEXT", store
, CharStar
, handles
, a
, flags
);
2316 free_handles(&handles
);
2317 so_give(&store
); /* free resources associated with store */
2320 q_status_message(SM_ORDER
| SM_DING
, 3, 3,
2321 _("Error allocating space for attachment."));
2327 /*----------------------------------------------------------------------
2328 Detach and provide for browsing a body part of type "MESSAGE"
2330 Args: msgno -- message number to get partrom
2331 a -- attachment struct for the desired part
2336 display_msg_att(long int msgno
, ATTACH_S
*a
, int flags
)
2341 HANDLE_S
*handles
= NULL
;
2345 clear_index_cache_ent(ps_global
->mail_stream
, msgno
, 0);
2347 /* BUG, should check this return code */
2348 (void) pine_mail_fetchstructure(ps_global
->mail_stream
, msgno
, NULL
);
2350 /* initialize a storage object */
2351 if(!(store
= so_get(CharStar
, NULL
, EDIT_ACCESS
))){
2352 q_status_message(SM_ORDER
| SM_DING
, 3, 3,
2353 _("Error allocating space for message."));
2357 gf_set_so_writec(&pc
, store
);
2359 if(format_msg_att(msgno
, &ap
, &handles
, pc
, FM_DISPLAY
)){
2360 if(ps_global
->full_header
== 2)
2361 q_status_message(SM_INFO
, 0, 3,
2362 _("Full header mode ON. All header text being included"));
2364 rv
= scroll_attachment((a
->body
->subtype
2365 && !strucmp(a
->body
->subtype
, "delivery-status"))
2366 ? "DELIVERY STATUS REPORT" : "ATTACHED MESSAGE",
2367 store
, CharStar
, handles
, a
, flags
);
2368 free_handles(&handles
);
2371 gf_clear_so_writec(store
);
2373 so_give(&store
); /* free resources associated with store */
2378 /*----------------------------------------------------------------------
2379 Detach and provide for browsing a multipart body part of type "DIGEST"
2381 Args: msgno -- message number to get partrom
2382 a -- attachment struct for the desired part
2387 display_digest_att(long int msgno
, ATTACH_S
*a
, int flags
)
2391 HANDLE_S
*handles
= NULL
;
2393 SourceType src
= CharStar
;
2397 clear_index_cache_ent(ps_global
->mail_stream
, msgno
, 0);
2399 /* BUG, should check this return code */
2400 (void) pine_mail_fetchstructure(ps_global
->mail_stream
, msgno
, NULL
);
2402 if(!(store
= so_get(src
, NULL
, EDIT_ACCESS
))){
2403 q_status_message(SM_ORDER
| SM_DING
, 3, 3,
2404 _("Error allocating space for message."));
2408 gf_set_so_writec(&pc
, store
);
2411 * While in a subtype of this message
2415 && !strncmp(a
->number
, ap
->number
, strlen(a
->number
))
2418 if(ap
->body
->type
== TYPEMESSAGE
){
2421 if(ap
->body
->subtype
&& strucmp(ap
->body
->subtype
, "rfc822")){
2424 tsub
= cpystr(ap
->body
->subtype
);
2425 convert_possibly_encoded_str_to_utf8((char **) &tsub
);
2426 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, "Unknown Message subtype: %s", tsub
);
2427 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
2429 if((errstr
= format_editorial(tmp_20k_buf
,
2430 ps_global
->ttyo
->screen_cols
, 0,
2431 NULL
, pc
)) != NULL
){
2432 q_status_message1(SM_ORDER
| SM_DING
, 3, 3,
2433 _("Can't format digest: %s"), errstr
);
2436 else if(!gf_puts(NEWLINE
, pc
))
2439 fs_give((void **) &tsub
);
2442 if((errstr
= part_desc(ap
->number
, ap
->body
->nested
.msg
->body
,
2443 0, ps_global
->ttyo
->screen_cols
, FM_DISPLAY
, pc
)) != NULL
){
2444 q_status_message1(SM_ORDER
| SM_DING
, 3, 3,
2445 _("Can't format digest: %s"), errstr
);
2448 else if(!format_msg_att(msgno
, &ap
, &handles
, pc
, FM_DISPLAY
))
2452 else if(ap
->body
->type
== TYPETEXT
2453 && decode_text(ap
, msgno
, pc
, NULL
, QStatus
, FM_DISPLAY
))
2455 else if(!gf_puts("Unknown type in Digest", pc
))
2460 if(ps_global
->full_header
== 2)
2461 q_status_message(SM_INFO
, 0, 3,
2462 _("Full header mode ON. All header text being included"));
2464 scroll_attachment(_("ATTACHED MESSAGES"), store
, src
, handles
, a
, flags
);
2467 free_handles(&handles
);
2469 gf_clear_so_writec(store
);
2470 so_give(&store
); /* free resources associated with store */
2475 scroll_attachment(char *title
, STORE_S
*store
, SourceType src
, HANDLE_S
*handles
, ATTACH_S
*a
, int flags
)
2479 memset(&sargs
, 0, sizeof(SCROLL_S
));
2480 sargs
.text
.text
= so_text(store
);
2481 sargs
.text
.src
= src
;
2482 sargs
.text
.desc
= "attachment";
2483 sargs
.text
.handles
= handles
;
2484 sargs
.bar
.title
= title
;
2485 sargs
.proc
.tool
= process_attachment_cmd
;
2486 sargs
.proc
.data
.p
= (void *) a
;
2487 sargs
.help
.text
= h_mail_text_att_view
;
2488 sargs
.help
.title
= _("HELP FOR ATTACHED TEXT VIEW");
2489 sargs
.keys
.menu
= &att_view_keymenu
;
2490 setbitmap(sargs
.keys
.bitmap
);
2492 /* First, fix up "back" key */
2493 if(flags
& DA_FROM_VIEW
){
2494 att_view_keymenu
.keys
[ATV_BACK_KEY
].label
= N_("MsgText");
2497 att_view_keymenu
.keys
[ATV_BACK_KEY
].label
= N_("AttchIndex");
2501 clrbitn(ATV_VIEW_HILITE
, sargs
.keys
.bitmap
);
2502 clrbitn(ATV_PREV_URL
, sargs
.keys
.bitmap
);
2503 clrbitn(ATV_NEXT_URL
, sargs
.keys
.bitmap
);
2506 if(F_OFF(F_ENABLE_PIPE
, ps_global
))
2507 clrbitn(ATV_PIPE_KEY
, sargs
.keys
.bitmap
);
2509 if(!(a
->body
->type
== TYPETEXT
|| MIME_MSG_A(a
) || MIME_DGST_A(a
)))
2510 clrbitn(ATV_PRINT_KEY
, sargs
.keys
.bitmap
);
2513 * If message or digest, leave Reply and Save and,
2514 * conditionally, Bounce on...
2517 if(F_OFF(F_ENABLE_BOUNCE
, ps_global
))
2518 clrbitn(ATV_BOUNCE_KEY
, sargs
.keys
.bitmap
);
2521 clrbitn(ATV_BOUNCE_KEY
, sargs
.keys
.bitmap
);
2522 clrbitn(ATV_REPLY_KEY
, sargs
.keys
.bitmap
);
2523 clrbitn(ATV_EXPORT_KEY
, sargs
.keys
.bitmap
);
2526 sargs
.use_indexline_color
= 1;
2528 if(DA_RESIZE
& flags
)
2529 sargs
.resize_exit
= 1;
2533 sargs
.mouse
.popup
= scroll_att_popup
;
2536 return(scrolltool(&sargs
));
2541 process_attachment_cmd(int cmd
, MSGNO_S
*msgmap
, SCROLL_S
*sparms
)
2544 long rawno
= mn_m2raw(msgmap
, mn_get_cur(msgmap
));
2545 #define AD(X) ((ATTACH_S *) (X)->proc.data.p)
2553 ps_global
->next_screen
= quit_screen
;
2557 ps_global
->next_screen
= main_menu_screen
;
2561 reply_msg_att(ps_global
->mail_stream
, rawno
, sparms
->proc
.data
.p
);
2565 forward_attachment(ps_global
->mail_stream
, rawno
, sparms
->proc
.data
.p
);
2569 bounce_msg_att(ps_global
->mail_stream
, rawno
, AD(sparms
)->number
,
2570 AD(sparms
)->body
->nested
.msg
->env
->subject
);
2571 ps_global
->mangled_footer
= 1;
2575 delete_attachment(rawno
, sparms
->proc
.data
.p
);
2579 if(undelete_attachment(rawno
, sparms
->proc
.data
.p
, &n
))
2580 q_status_message1(SM_ORDER
, 0, 3,
2581 "Part %s UNdeleted", AD(sparms
)->number
);
2586 save_attachment(-FOOTER_ROWS(ps_global
), rawno
, sparms
->proc
.data
.p
);
2587 ps_global
->mangled_footer
= 1;
2591 export_attachment(-FOOTER_ROWS(ps_global
), rawno
, sparms
->proc
.data
.p
);
2592 ps_global
->mangled_footer
= 1;
2596 print_attachment(-FOOTER_ROWS(ps_global
), rawno
, sparms
->proc
.data
.p
);
2597 ps_global
->mangled_footer
= 1;
2601 pipe_attachment(rawno
, sparms
->proc
.data
.p
);
2602 ps_global
->mangled_footer
= 1;
2606 ps_global
->full_header
++;
2607 if(ps_global
->full_header
== 1){
2608 if(!(ps_global
->quote_suppression_threshold
2609 && (ps_global
->some_quoting_was_suppressed
/* || in_index != View*/)))
2610 ps_global
->full_header
++;
2612 else if(ps_global
->full_header
> 2)
2613 ps_global
->full_header
= 0;
2615 switch(ps_global
->full_header
){
2617 q_status_message(SM_ORDER
, 0, 3,
2618 _("Display of full headers is now off."));
2622 q_status_message1(SM_ORDER
, 0, 3,
2623 _("Quotes displayed, use %s to see full headers"),
2624 F_ON(F_USE_FK
, ps_global
) ? "F9" : "H");
2628 q_status_message(SM_ORDER
, 0, 3,
2629 _("Display of full headers is now on."));
2638 alpine_panic("Unexpected command case");
2647 * Returns 1 on success, 0 on error.
2650 format_msg_att(long int msgno
, ATTACH_S
**a
, HANDLE_S
**handlesp
, gf_io_t pc
, int flags
)
2654 if((*a
)->body
->type
!= TYPEMESSAGE
)
2655 return(gf_puts("[ Undisplayed Attachment of Type ", pc
)
2656 && gf_puts(body_type_names((*a
)->body
->type
), pc
)
2657 && gf_puts(" ]", pc
) && gf_puts(NEWLINE
, pc
));
2659 if((*a
)->body
->subtype
&& strucmp((*a
)->body
->subtype
, "rfc822") == 0){
2662 HD_INIT(&h
, ps_global
->VAR_VIEW_HEADERS
, ps_global
->view_all_except
,
2664 switch(format_header(ps_global
->mail_stream
, msgno
, (*a
)->number
,
2665 (*a
)->body
->nested
.msg
->env
, &h
, NULL
, NULL
,
2667 case -1 : /* write error */
2670 case 1 : /* fetch error */
2671 if(!(gf_puts("[ Error fetching header ]", pc
)
2672 && !gf_puts(NEWLINE
, pc
)))
2678 gf_puts(NEWLINE
, pc
);
2683 if((*a
)->body
&& (*a
)->body
->subtype
&& (strucmp((*a
)->body
->subtype
, OUR_PKCS7_ENCLOSURE_SUBTYPE
)==0)){
2684 if((*a
)->description
){
2685 if(!(!format_editorial((*a
)->description
,
2686 ps_global
->ttyo
->screen_cols
,
2688 && gf_puts(NEWLINE
, pc
) && gf_puts(NEWLINE
, pc
)))
2696 if(((*a
))->description
2697 && (*a
)->body
&& (*a
)->body
->type
== TYPETEXT
){
2698 if(decode_text(*a
, msgno
, pc
, NULL
, QStatus
, flags
))
2701 else if(!(gf_puts("[Can't display ", pc
)
2702 && gf_puts(((*a
)->description
&& (*a
)->body
)
2703 ? "first non-" : "missing ", pc
)
2704 && gf_puts("text segment]", pc
)
2705 && gf_puts(NEWLINE
, pc
)))
2711 else if((*a
)->body
->subtype
2712 && strucmp((*a
)->body
->subtype
, "external-body") == 0) {
2713 if(format_editorial("This part is not included and can be fetched as follows:",
2714 ps_global
->ttyo
->screen_cols
, flags
, NULL
, pc
)
2715 || !gf_puts(NEWLINE
, pc
)
2716 || format_editorial(display_parameters((*a
)->body
->parameter
),
2717 ps_global
->ttyo
->screen_cols
, flags
, handlesp
, pc
))
2720 else if(decode_text(*a
, msgno
, pc
, NULL
, QStatus
, flags
))
2728 display_vcard_att(long int msgno
, ATTACH_S
*a
, int flags
)
2730 STORE_S
*in_store
, *out_store
= NULL
;
2731 HANDLE_S
*handles
= NULL
;
2734 char **lines
, **ll
, *errstr
= NULL
, tmp
[MAILTMPLEN
], *p
;
2735 int cmd
, indent
, begins
= 0;
2737 lines
= detach_vcard_att(ps_global
->mail_stream
,
2738 msgno
, a
->body
, a
->number
);
2740 q_status_message(SM_ORDER
| SM_DING
, 3, 3,
2741 _("Error accessing attachment."));
2745 if(!(in_store
= so_get(CharStar
, NULL
, EDIT_ACCESS
))){
2746 free_list_array(&lines
);
2747 q_status_message(SM_ORDER
| SM_DING
, 3, 3,
2748 _("Error allocating space for attachment."));
2752 for(ll
= lines
, indent
= 0; ll
&& *ll
; ll
++)
2753 if((p
= strindex(*ll
, ':')) && p
- *ll
> indent
)
2757 for(ll
= lines
; ll
&& *ll
; ll
++){
2758 if((p
= strindex(*ll
, ':')) != NULL
){
2759 if(begins
< 2 && struncmp(*ll
, "begin:", 6) == 0)
2762 snprintf(tmp
, sizeof(tmp
), " %-*.*s : ", indent
- 5,
2763 MIN(p
- *ll
, sizeof(tmp
)-5), *ll
);
2764 tmp
[sizeof(tmp
)-1] = '\0';
2765 so_puts(in_store
, tmp
);
2770 so_puts(in_store
, repeat_char(indent
, SPACE
));
2773 snprintf(tmp
, sizeof(tmp
), "%.200s", p
);
2774 tmp
[sizeof(tmp
)-1] = '\0';
2776 (char *)rfc1522_decode_to_utf8((unsigned char *)tmp_20k_buf
,
2777 SIZEOF_20KBUF
, tmp
));
2778 so_puts(in_store
, "\015\012");
2781 free_list_array(&lines
);
2783 so_puts(in_store
, "\015\012\015\012");
2786 if((out_store
= so_get(CharStar
, NULL
, EDIT_ACCESS
)) != NULL
){
2787 so_seek(in_store
, 0L, 0);
2789 init_handles(&handles
);
2792 if(F_ON(F_VIEW_SEL_URL
, ps_global
)
2793 || F_ON(F_VIEW_SEL_URL_HOST
, ps_global
)
2794 || F_ON(F_SCAN_ADDR
, ps_global
))
2795 gf_link_filter(gf_line_test
,
2796 gf_line_test_opt(url_hilite
,
2797 gf_url_hilite_opt(&uh
,&handles
,0)));
2799 gf_link_filter(gf_wrap
,
2800 gf_wrap_filter_opt(ps_global
->ttyo
->screen_cols
- 4,
2801 ps_global
->ttyo
->screen_cols
,
2802 NULL
, indent
, GFW_HANDLES
));
2803 gf_link_filter(gf_nvtnl_local
, NULL
);
2805 gf_set_so_readc(&gc
, in_store
);
2806 gf_set_so_writec(&pc
, out_store
);
2808 errstr
= gf_pipe(gc
, pc
);
2810 gf_clear_so_readc(in_store
);
2813 #define VCARD_TEXT_ONE _("This is a vCard which has been forwarded to you. You may add parts of it to your address book with the Save command. You will have a chance to edit it before committing it to your address book.")
2814 #define VCARD_TEXT_MORE _("This is a vCard which has been forwarded to you. You may add the entries to your address book with the Save command.")
2815 errstr
= format_editorial((begins
> 1)
2816 ? VCARD_TEXT_MORE
: VCARD_TEXT_ONE
,
2817 ps_global
->ttyo
->screen_cols
, 0, NULL
, pc
);
2820 gf_clear_so_writec(out_store
);
2823 cmd
= scroll_attachment(_("ADDRESS BOOK ATTACHMENT"), out_store
,
2824 CharStar
, handles
, a
, flags
| DA_RESIZE
);
2826 free_handles(&handles
);
2827 so_give(&out_store
);
2830 errstr
= _("Error allocating space");
2832 while(!errstr
&& (cmd
== MC_RESIZE
|| cmd
== MC_FULLHDR
));
2835 q_status_message1(SM_ORDER
| SM_DING
, 3, 3,
2836 _("Can't format entry : %s"), errstr
);
2842 /*----------------------------------------------------------------------
2843 Display attachment information
2845 Args: msgno -- message number to get partrom
2846 a -- attachment struct for the desired part
2848 Result: a screen containing information about attachment:
2851 display_attach_info(long int msgno
, ATTACH_S
*a
)
2853 int i
, indent
, cols
;
2854 char buf1
[100], *folded
;
2859 (void) dispatch_attachment(a
);
2861 if(!(store
= so_get(CharStar
, NULL
, EDIT_ACCESS
))){
2862 q_status_message(SM_ORDER
| SM_DING
, 3, 3,
2863 _("Error allocating space for message."));
2867 cols
= ps_global
->ttyo
->screen_cols
;
2871 * 16 for text (longest is Display Method == 14)
2876 /* don't try stupid folding */
2877 cols
= MAX(indent
+10, cols
);
2879 so_puts(store
, "Details about Attachment #");
2880 so_puts(store
, a
->number
);
2881 so_puts(store
, " :\n\n");
2882 utf8_snprintf(buf1
, sizeof(buf1
), " %-*.*w: ", indent
-4, indent
-4, "Type");
2883 so_puts(store
, buf1
);
2884 so_puts(store
, body_type_names(a
->body
->type
));
2885 so_puts(store
, "\n");
2886 utf8_snprintf(buf1
, sizeof(buf1
), " %-*.*w: ", indent
-4, indent
-4, "Subtype");
2887 so_puts(store
, buf1
);
2888 so_puts(store
, a
->body
->subtype
? a
->body
->subtype
: "Unknown");
2889 so_puts(store
, "\n");
2890 utf8_snprintf(buf1
, sizeof(buf1
), " %-*.*w: ", indent
-4, indent
-4, "Encoding");
2891 so_puts(store
, buf1
);
2892 so_puts(store
, a
->body
->encoding
< ENCMAX
2893 ? body_encodings
[a
->body
->encoding
]
2895 so_puts(store
, "\n");
2896 if((plist
= rfc2231_newparmlist(a
->body
->parameter
)) != NULL
){
2897 utf8_snprintf(buf1
, sizeof(buf1
), " %-*.*w: ", indent
-4, indent
-4, "Parameters");
2898 so_puts(store
, buf1
);
2900 while(rfc2231_list_params(plist
)){
2902 so_puts(store
, repeat_char(indent
, ' '));
2904 so_puts(store
, plist
->attrib
);
2905 so_puts(store
, " = ");
2906 so_puts(store
, plist
->value
? plist
->value
: "");
2907 so_puts(store
, "\n");
2910 rfc2231_free_parmlist(&plist
);
2913 if(a
->body
->description
&& a
->body
->description
[0]){
2914 char buftmp
[MAILTMPLEN
];
2917 utf8_snprintf(buf1
, sizeof(buf1
), " %-*.*w: ", indent
-4, indent
-4, "Description");
2919 snprintf(buftmp
, sizeof(buftmp
), "%s", a
->body
->description
);
2920 buftmp
[sizeof(buftmp
)-1] = '\0';
2921 q
= rfc1522_decode_to_utf8((unsigned char *)tmp_20k_buf
, SIZEOF_20KBUF
, buftmp
);
2922 folded
= fold((char *) q
, cols
, cols
, buf1
, repeat_char(indent
+1, ' '), FLD_NONE
);
2925 so_puts(store
, folded
);
2926 fs_give((void **) &folded
);
2930 /* BUG: no a->body->language support */
2932 if(a
->body
->disposition
.type
){
2933 utf8_snprintf(buf1
, sizeof(buf1
), " %-*.*w: ", indent
-4, indent
-4, "Disposition");
2934 so_puts(store
, buf1
);
2935 so_puts(store
, a
->body
->disposition
.type
);
2936 so_puts(store
, "\n");
2937 if((plist
= rfc2231_newparmlist(a
->body
->disposition
.parameter
)) != NULL
){
2938 while(rfc2231_list_params(plist
)){
2939 so_puts(store
, repeat_char(indent
, ' '));
2940 so_puts(store
, plist
->attrib
);
2941 so_puts(store
, " = ");
2942 so_puts(store
, plist
->value
? plist
->value
: "");
2943 so_puts(store
, "\n");
2946 rfc2231_free_parmlist(&plist
);
2950 utf8_snprintf(buf1
, sizeof(buf1
), " %-*.*w: ", indent
-4, indent
-4, "Approx. Size");
2951 so_puts(store
, buf1
);
2952 so_puts(store
, comatose((a
->body
->encoding
== ENCBASE64
)
2953 ? ((a
->body
->size
.bytes
* 3)/4)
2954 : a
->body
->size
.bytes
));
2955 so_puts(store
, " bytes\n");
2956 utf8_snprintf(buf1
, sizeof(buf1
), " %-*.*w: ", indent
-4, indent
-4, "Display Method");
2957 so_puts(store
, buf1
);
2958 if(a
->can_display
== MCD_NONE
) {
2959 so_puts(store
, "Can't, ");
2960 so_puts(store
, (a
->body
->encoding
< ENCOTHER
)
2961 ? "Unknown Attachment Format"
2962 : "Unknown Encoding");
2964 else if(!(a
->can_display
& MCD_EXTERNAL
)){
2965 so_puts(store
, "Alpine's Internal Pager");
2968 int nt
, free_pretty_cmd
;
2972 if((mc_cmd
= mailcap_build_command(a
->body
->type
, a
->body
->subtype
,
2973 a
->body
, "<datafile>", &nt
,
2974 a
->can_display
& MCD_EXT_PROMPT
)) != NULL
){
2975 so_puts(store
, "\"");
2976 if((pretty_cmd
= execview_pretty_command(mc_cmd
, &free_pretty_cmd
)) != NULL
)
2977 so_puts(store
, pretty_cmd
);
2978 so_puts(store
, "\"");
2979 if(free_pretty_cmd
&& pretty_cmd
)
2980 fs_give((void **)&pretty_cmd
);
2982 fs_give((void **)&mc_cmd
->command
);
2983 fs_give((void **)&mc_cmd
);
2987 so_puts(store
, "\n");
2989 memset(&sargs
, 0, sizeof(SCROLL_S
));
2990 sargs
.text
.text
= so_text(store
);
2991 sargs
.text
.src
= CharStar
;
2992 sargs
.text
.desc
= "attachment info";
2993 sargs
.bar
.title
= _("ABOUT ATTACHMENT");
2994 sargs
.help
.text
= h_simple_text_view
;
2995 sargs
.help
.title
= _("HELP FOR \"ABOUT ATTACHMENT\"");
2997 sargs
.use_indexline_color
= 1;
3001 so_give(&store
); /* free resources associated with store */
3002 ps_global
->mangled_screen
= 1;
3006 /*----------------------------------------------------------------------
3010 forward_attachment(MAILSTREAM
*stream
, long int msgno
, ATTACH_S
*a
)
3018 forward_msg_att(stream
, msgno
, a
);
3021 ACTION_S
*role
= NULL
;
3022 REDRAFT_POS_S
*redraft_pos
= NULL
;
3023 long rflags
= ROLE_FORWARD
;
3026 outgoing
= mail_newenvelope();
3027 outgoing
->message_id
= generate_message_id();
3028 outgoing
->subject
= cpystr("Forwarded attachment...");
3030 if(nonempty_patterns(rflags
, &dummy
)){
3032 * There is no message, but a Current Folder Type might match.
3034 * This has been changed to check against the message
3035 * containing the attachment.
3037 role
= set_role_from_msg(ps_global
, ROLE_FORWARD
, msgno
, NULL
);
3038 if(confirm_role(rflags
, &role
))
3039 role
= combine_inherited_role(role
);
3042 cmd_cancelled("Forward");
3043 mail_free_envelope(&outgoing
);
3049 q_status_message1(SM_ORDER
, 3, 4,
3050 _("Forwarding using role \"%s\""), role
->nick
);
3053 * as with all text bound for the composer, build it in
3054 * a storage object of the type it understands...
3056 if((msgtext
= (void *) so_get(PicoText
, NULL
, EDIT_ACCESS
)) != NULL
){
3057 int impl
, template_len
= 0;
3059 if(role
&& role
->template){
3063 filtered
= detoken(role
, NULL
, 0, 0, 0, &redraft_pos
, &impl
);
3066 so_puts((STORE_S
*)msgtext
, filtered
);
3068 template_len
= strlen(filtered
);
3071 fs_give((void **)&filtered
);
3077 if((sig
= detoken(role
, NULL
, 2, 0, 1, &redraft_pos
, &impl
)) != NULL
){
3079 redraft_pos
->offset
+= template_len
;
3081 so_puts((STORE_S
*)msgtext
, *sig
? sig
: NEWLINE
);
3083 fs_give((void **)&sig
);
3086 so_puts((STORE_S
*)msgtext
, NEWLINE
);
3088 /*---- New Body to start with ----*/
3089 body
= mail_newbody();
3090 body
->type
= TYPEMULTIPART
;
3092 /*---- The TEXT part/body ----*/
3093 body
->nested
.part
= mail_newbody_part();
3094 body
->nested
.part
->body
.type
= TYPETEXT
;
3095 body
->nested
.part
->body
.contents
.text
.data
= msgtext
;
3097 /*---- The corresponding things we're attaching ----*/
3098 body
->nested
.part
->next
= mail_newbody_part();
3099 body
->nested
.part
->next
->body
.id
= generate_message_id();
3100 copy_body(&body
->nested
.part
->next
->body
, a
->body
);
3102 if(fetch_contents(stream
, msgno
, a
->number
,
3103 &body
->nested
.part
->next
->body
)){
3104 pine_send(outgoing
, &body
, "FORWARD MESSAGE",
3105 role
, NULL
, NULL
, redraft_pos
, NULL
, NULL
, 0);
3107 ps_global
->mangled_screen
= 1;
3108 pine_free_body(&body
);
3109 free_redraft_pos(&redraft_pos
);
3112 mail_free_body(&body
);
3113 so_give((STORE_S
**) &msgtext
);
3114 free_redraft_pos(&redraft_pos
);
3115 q_status_message(SM_ORDER
| SM_DING
, 4, 5,
3116 _("Error fetching message contents. Can't forward message."));
3120 q_status_message(SM_ORDER
| SM_DING
, 3, 4,
3121 _("Error allocating message text"));
3123 mail_free_envelope(&outgoing
);
3130 forward_msg_att(MAILSTREAM
*stream
, long int msgno
, ATTACH_S
*a
)
3132 char *p
, *sig
= NULL
;
3137 ACTION_S
*role
= NULL
;
3139 REDRAFT_POS_S
*redraft_pos
= NULL
;
3141 outgoing
= mail_newenvelope();
3142 outgoing
->message_id
= generate_message_id();
3144 memset((void *)&reply
, 0, sizeof(reply
));
3146 if((outgoing
->subject
= forward_subject(a
->body
->nested
.msg
->env
, 0)) != NULL
){
3148 * as with all text bound for the composer, build it in
3149 * a storage object of the type it understands...
3151 if((msgtext
= (void *) so_get(PicoText
, NULL
, EDIT_ACCESS
)) != NULL
){
3152 int impl
, template_len
= 0;
3153 long rflags
= ROLE_FORWARD
;
3157 if(ps_global
->full_header
== 2)
3158 ret
= want_to(_("Forward message as an attachment"), 'n', 0,
3159 NO_HELP
, WT_SEQ_SENSITIVE
);
3160 /* Setup possible role */
3161 if(nonempty_patterns(rflags
, &dummy
)){
3162 role
= set_role_from_msg(ps_global
, rflags
, msgno
, a
->number
);
3163 if(confirm_role(rflags
, &role
))
3164 role
= combine_inherited_role(role
);
3165 else{ /* cancel reply */
3167 cmd_cancelled("Forward");
3168 mail_free_envelope(&outgoing
);
3169 so_give((STORE_S
**) &msgtext
);
3175 q_status_message1(SM_ORDER
, 3, 4,
3176 _("Forwarding using role \"%s\""), role
->nick
);
3178 if(role
&& role
->template){
3182 filtered
= detoken(role
, a
->body
->nested
.msg
->env
,
3183 0, 0, 0, &redraft_pos
, &impl
);
3186 so_puts((STORE_S
*)msgtext
, filtered
);
3188 template_len
= strlen(filtered
);
3191 fs_give((void **)&filtered
);
3197 if((sig
= detoken(role
, a
->body
->nested
.msg
->env
,
3198 2, 0, 1, &redraft_pos
, &impl
)) != NULL
){
3200 redraft_pos
->offset
+= template_len
;
3202 so_puts((STORE_S
*)msgtext
, *sig
? sig
: NEWLINE
);
3204 fs_give((void **)&sig
);
3207 so_puts((STORE_S
*)msgtext
, NEWLINE
);
3210 /*---- New Body to start with ----*/
3211 body
= mail_newbody();
3212 body
->type
= TYPEMULTIPART
;
3214 /*---- The TEXT part/body ----*/
3215 body
->nested
.part
= mail_newbody_part();
3216 body
->nested
.part
->body
.type
= TYPETEXT
;
3217 body
->nested
.part
->body
.contents
.text
.data
= msgtext
;
3219 if(!forward_mime_msg(stream
, msgno
,
3220 p
= body_partno(stream
, msgno
, a
->body
),
3221 a
->body
->nested
.msg
->env
,
3222 &body
->nested
.part
->next
, msgtext
))
3223 mail_free_body(&body
);
3227 if(a
->body
->nested
.msg
->body
){
3231 = parameter_val(a
->body
->nested
.msg
->body
->parameter
,
3234 if(charset
&& strucmp(charset
, "us-ascii") != 0){
3238 * There is a non-ascii charset,
3239 * is there conversion happening?
3241 if(!(ct
=conversion_table(charset
, ps_global
->posting_charmap
))
3243 reply
.orig_charset
= charset
;
3249 fs_give((void **) &charset
);
3252 body
= forward_body(stream
, a
->body
->nested
.msg
->env
,
3253 a
->body
->nested
.msg
->body
, msgno
,
3254 p
= body_partno(stream
, msgno
, a
->body
),
3258 fs_give((void **) &p
);
3261 pine_send(outgoing
, &body
,
3264 reply
.forw
? &reply
: NULL
,
3265 redraft_pos
, NULL
, NULL
, 0);
3267 ps_global
->mangled_screen
= 1;
3268 pine_free_body(&body
);
3269 free_redraft_pos(&redraft_pos
);
3273 so_give((STORE_S
**) &msgtext
);
3274 q_status_message(SM_ORDER
| SM_DING
, 4, 5,
3275 _("Error fetching message contents. Can't forward message."));
3279 q_status_message(SM_ORDER
| SM_DING
, 3, 4,
3280 _("Error allocating message text"));
3283 q_status_message1(SM_ORDER
,3,4,
3284 _("Error fetching message %s. Can't forward it."),
3285 long2string(msgno
));
3287 if(reply
.orig_charset
)
3288 fs_give((void **)&reply
.orig_charset
);
3290 mail_free_envelope(&outgoing
);
3295 reply_msg_att(MAILSTREAM
*stream
, long int msgno
, ATTACH_S
*a
)
3297 ADDRESS
*saved_from
, *saved_to
, *saved_cc
, *saved_resent
;
3301 char *tp
, *prefix
= NULL
, *fcc
= NULL
, *errmsg
= NULL
;
3302 int include_text
= 0, flags
= RSF_QUERY_REPLY_ALL
;
3303 int rolemsg
= 0, copytomsg
= 0;
3306 REDRAFT_POS_S
*redraft_pos
= NULL
;
3307 ACTION_S
*role
= NULL
;
3309 outgoing
= mail_newenvelope();
3311 dprint((4,"\n - attachment reply \n"));
3313 saved_from
= (ADDRESS
*) NULL
;
3314 saved_to
= (ADDRESS
*) NULL
;
3315 saved_cc
= (ADDRESS
*) NULL
;
3316 saved_resent
= (ADDRESS
*) NULL
;
3317 outgoing
->subject
= NULL
;
3319 prefix
= reply_quote_str(a
->body
->nested
.msg
->env
);
3321 * For consistency, the first question is always "include text?"
3323 if((include_text
= reply_text_query(ps_global
, 1, &prefix
)) >= 0
3324 && reply_news_test(a
->body
->nested
.msg
->env
, outgoing
) > 0
3325 && reply_harvest(ps_global
, msgno
, a
->number
,
3326 a
->body
->nested
.msg
->env
, &saved_from
,
3327 &saved_to
, &saved_cc
, &saved_resent
, &flags
)){
3328 outgoing
->subject
= reply_subject(a
->body
->nested
.msg
->env
->subject
,
3331 reply_seed(ps_global
, outgoing
, a
->body
->nested
.msg
->env
,
3332 saved_from
, saved_to
, saved_cc
, saved_resent
,
3333 &fcc
, flags
& RSF_FORCE_REPLY_ALL
, &errmsg
);
3336 q_status_message1(SM_ORDER
, 3, 3, "%.200s", errmsg
);
3337 display_message(NO_OP_COMMAND
);
3340 fs_give((void **)&errmsg
);
3343 if(sp_expunge_count(stream
)) /* current msg was expunged */
3346 /* Setup possible role */
3347 rflags
= ROLE_REPLY
;
3348 if(nonempty_patterns(rflags
, &dummy
)){
3349 role
= set_role_from_msg(ps_global
, rflags
, msgno
, a
->number
);
3350 if(confirm_role(rflags
, &role
))
3351 role
= combine_inherited_role(role
);
3352 else{ /* cancel reply */
3354 cmd_cancelled("Reply");
3362 /* override fcc gotten in reply_seed */
3363 if(role
->fcc
&& fcc
)
3364 fs_give((void **) &fcc
);
3367 if(F_ON(F_COPY_TO_TO_FROM
, ps_global
) && !(role
&& role
->from
)){
3368 ADDRESS
*us_in_to_and_cc
, *ap
;
3370 us_in_to_and_cc
= (ADDRESS
*) NULL
;
3371 if(a
->body
->nested
.msg
->env
&& a
->body
->nested
.msg
->env
->to
)
3372 if((ap
=reply_cp_addr(ps_global
, 0L, NULL
,
3373 NULL
, us_in_to_and_cc
, NULL
,
3374 a
->body
->nested
.msg
->env
->to
, RCA_ONLY_US
)) != NULL
)
3375 reply_append_addr(&us_in_to_and_cc
, ap
);
3377 if(a
->body
->nested
.msg
->env
&& a
->body
->nested
.msg
->env
->cc
)
3378 if((ap
=reply_cp_addr(ps_global
, 0L, NULL
,
3379 NULL
, us_in_to_and_cc
, NULL
,
3380 a
->body
->nested
.msg
->env
->cc
, RCA_ONLY_US
)) != NULL
)
3381 reply_append_addr(&us_in_to_and_cc
, ap
);
3384 * A list of all of our addresses that appear in the To
3385 * and cc fields is in us_in_to_and_cc.
3386 * If there is exactly one address in that list then
3387 * use it for the outgoing From.
3389 if(us_in_to_and_cc
&& !us_in_to_and_cc
->next
){
3390 PINEFIELD
*custom
, *pf
;
3395 * Check to see if this address is different from what
3396 * we would have used anyway. If it is, notify the user
3397 * with a status message. This is pretty hokey because we're
3398 * mimicking how pine_send would set the From address and
3399 * there is no coordination between the two.
3402 /* in case user has a custom From value */
3403 custom
= parse_custom_hdrs(ps_global
->VAR_CUSTOM_HDRS
, UseAsDef
);
3405 pf
= (PINEFIELD
*) fs_get(sizeof(*pf
));
3406 memset((void *) pf
, 0, sizeof(*pf
));
3407 pf
->name
= cpystr("From");
3409 if(set_default_hdrval(pf
, custom
) >= UseAsDef
3410 && pf
->textbuf
&& pf
->textbuf
[0]){
3411 removing_trailing_white_space(pf
->textbuf
);
3412 (void)removing_double_quotes(pf
->textbuf
);
3413 build_address(pf
->textbuf
, &addr
, NULL
, NULL
, NULL
);
3414 rfc822_parse_adrlist(pf
->addr
, addr
, ps_global
->maildomain
);
3416 fs_give((void **) &addr
);
3420 *pf
->addr
= generate_from();
3422 if(*pf
->addr
&& !address_is_same(*pf
->addr
, us_in_to_and_cc
)){
3425 role
= (ACTION_S
*) fs_get(sizeof(*role
));
3426 memset((void *) role
, 0, sizeof(*role
));
3427 role
->is_a_role
= 1;
3430 role
->from
= us_in_to_and_cc
;
3431 us_in_to_and_cc
= NULL
;
3434 free_customs(custom
);
3439 mail_free_address(&us_in_to_and_cc
);
3444 if(rolemsg
&& copytomsg
)
3445 q_status_message1(SM_ORDER
, 3, 4,
3446 _("Replying using role \"%s\" and To as From"), role
->nick
);
3448 q_status_message1(SM_ORDER
, 3, 4,
3449 _("Replying using role \"%s\""), role
->nick
);
3451 q_status_message(SM_ORDER
, 3, 4,
3452 _("Replying using incoming To as outgoing From"));
3455 outgoing
->in_reply_to
= reply_in_reply_to(a
->body
->nested
.msg
->env
);
3456 outgoing
->references
= reply_build_refs(a
->body
->nested
.msg
->env
);
3457 outgoing
->message_id
= generate_message_id();
3459 if(!outgoing
->to
&& !outgoing
->cc
3460 && !outgoing
->bcc
&& !outgoing
->newsgroups
)
3461 q_status_message(SM_ORDER
| SM_DING
, 3, 6,
3462 _("Warning: no valid addresses to reply to!"));
3465 * Now fix up the body...
3467 if((msgtext
= (void *) so_get(PicoText
, NULL
, EDIT_ACCESS
)) != NULL
){
3470 memset((void *)&reply
, 0, sizeof(reply
));
3472 if(a
->body
->nested
.msg
->body
){
3476 = parameter_val(a
->body
->nested
.msg
->body
->parameter
,
3479 if(charset
&& strucmp(charset
, "us-ascii") != 0){
3483 * There is a non-ascii charset,
3484 * is there conversion happening?
3486 if(!(ct
=conversion_table(charset
, ps_global
->posting_charmap
))
3488 reply
.orig_charset
= charset
;
3494 fs_give((void **) &charset
);
3497 if((body
= reply_body(stream
, a
->body
->nested
.msg
->env
,
3498 a
->body
->nested
.msg
->body
, msgno
,
3499 tp
= body_partno(stream
, msgno
, a
->body
),
3500 msgtext
, prefix
, include_text
, role
,
3501 1, &redraft_pos
)) != NULL
){
3502 /* partially formatted outgoing message */
3503 pine_send(outgoing
, &body
, "COMPOSE MESSAGE REPLY",
3504 role
, fcc
, &reply
, redraft_pos
, NULL
, NULL
, 0);
3506 pine_free_body(&body
);
3507 ps_global
->mangled_screen
= 1;
3510 q_status_message(SM_ORDER
| SM_DING
, 3, 4,
3511 _("Error building message body"));
3513 fs_give((void **) &tp
);
3514 if(reply
.orig_charset
)
3515 fs_give((void **)&reply
.orig_charset
);
3518 q_status_message(SM_ORDER
| SM_DING
, 3, 4,
3519 _("Error allocating message text"));
3523 mail_free_envelope(&outgoing
);
3524 mail_free_address(&saved_from
);
3525 mail_free_address(&saved_to
);
3526 mail_free_address(&saved_cc
);
3527 mail_free_address(&saved_resent
);
3530 fs_give((void **) &prefix
);
3533 fs_give((void **) &fcc
);
3535 free_redraft_pos(&redraft_pos
);
3541 bounce_msg_att(MAILSTREAM
*stream
, long int msgno
, char *part
, char *subject
)
3545 if((errstr
= bounce_msg(stream
, msgno
, part
, NULL
, NULL
, subject
, NULL
, NULL
)) != NULL
)
3546 q_status_message(SM_ORDER
| SM_DING
, 3, 3, errstr
);
3551 pipe_attachment(long int msgno
, ATTACH_S
*a
)
3553 char *err
, *resultfilename
= NULL
, prompt
[80], *p
;
3554 int rc
, capture
= 1, raw
= 0, we_cancel
= 0, j
= 0;
3558 char pipe_command
[MAXPATH
+1];
3559 unsigned flagsforhist
= 1; /* raw=2 /capture=1 */
3560 static HISTORY_S
*history
= NULL
;
3561 ESCKEY_S pipe_opt
[6];
3563 if(ps_global
->restricted
){
3564 q_status_message(SM_ORDER
| SM_DING
, 0, 4,
3565 "Alpine demo can't pipe attachments");
3570 pipe_command
[0] = '\0';
3572 init_hist(&history
, HISTSIZE
);
3573 flagsforhist
= (raw
? 0x2 : 0) + (capture
? 0x1 : 0);
3574 if((p
= get_prev_hist(history
, "", flagsforhist
, NULL
)) != NULL
){
3575 strncpy(pipe_command
, p
, sizeof(pipe_command
));
3576 pipe_command
[sizeof(pipe_command
)-1] = '\0';
3577 if(history
->hist
[history
->curindex
]){
3578 flagsforhist
= history
->hist
[history
->curindex
]->flags
;
3579 raw
= (flagsforhist
& 0x2) ? 1 : 0;
3580 capture
= (flagsforhist
& 0x1) ? 1 : 0;
3585 pipe_opt
[j
].rval
= 0;
3586 pipe_opt
[j
].name
= "";
3587 pipe_opt
[j
++].label
= "";
3589 pipe_opt
[j
].ch
= ctrl('W');
3590 pipe_opt
[j
].rval
= 10;
3591 pipe_opt
[j
].name
= "^W";
3592 pipe_opt
[j
++].label
= NULL
;
3594 pipe_opt
[j
].ch
= ctrl('Y');
3595 pipe_opt
[j
].rval
= 11;
3596 pipe_opt
[j
].name
= "^Y";
3597 pipe_opt
[j
++].label
= NULL
;
3599 pipe_opt
[j
].ch
= KEY_UP
;
3600 pipe_opt
[j
].rval
= 30;
3601 pipe_opt
[j
].name
= "";
3603 pipe_opt
[j
++].label
= "";
3605 pipe_opt
[j
].ch
= KEY_DOWN
;
3606 pipe_opt
[j
].rval
= 31;
3607 pipe_opt
[j
].name
= "";
3608 pipe_opt
[j
++].label
= "";
3610 pipe_opt
[j
].ch
= -1;
3615 snprintf(prompt
, sizeof(prompt
), "Pipe %sattachment %s to %s: ", raw
? "RAW " : "",
3616 a
->number
, capture
? "" : "(Free Output) ");
3617 prompt
[sizeof(prompt
)-1] = '\0';
3618 pipe_opt
[1].label
= raw
? "DecodedData" : "Raw Data";
3619 pipe_opt
[2].label
= capture
? "Free Output" : "Capture Output";
3622 * 2 is really 1 because there will be one real entry and
3623 * one entry of "" because of the get_prev_hist above.
3625 if(items_in_hist(history
) > 2){
3626 pipe_opt
[ku
].name
= HISTORY_UP_KEYNAME
;
3627 pipe_opt
[ku
].label
= HISTORY_KEYLABEL
;
3628 pipe_opt
[ku
+1].name
= HISTORY_DOWN_KEYNAME
;
3629 pipe_opt
[ku
+1].label
= HISTORY_KEYLABEL
;
3632 pipe_opt
[ku
].name
= "";
3633 pipe_opt
[ku
].label
= "";
3634 pipe_opt
[ku
+1].name
= "";
3635 pipe_opt
[ku
+1].label
= "";
3638 flags
= OE_APPEND_CURRENT
| OE_SEQ_SENSITIVE
;
3639 rc
= optionally_enter(pipe_command
, -FOOTER_ROWS(ps_global
), 0,
3640 sizeof(pipe_command
), prompt
,
3641 pipe_opt
, help
, &flags
);
3643 q_status_message(SM_ORDER
| SM_DING
, 3, 4,
3644 "Internal problem encountered");
3648 raw
= !raw
; /* flip raw text */
3651 capture
= !capture
; /* flip capture output */
3654 flagsforhist
= (raw
? 0x2 : 0) + (capture
? 0x1 : 0);
3655 if((p
= get_prev_hist(history
, pipe_command
, flagsforhist
, NULL
)) != NULL
){
3656 strncpy(pipe_command
, p
, sizeof(pipe_command
));
3657 pipe_command
[sizeof(pipe_command
)-1] = '\0';
3658 if(history
->hist
[history
->curindex
]){
3659 flagsforhist
= history
->hist
[history
->curindex
]->flags
;
3660 raw
= (flagsforhist
& 0x2) ? 1 : 0;
3661 capture
= (flagsforhist
& 0x1) ? 1 : 0;
3668 flagsforhist
= (raw
? 0x2 : 0) + (capture
? 0x1 : 0);
3669 if((p
= get_next_hist(history
, pipe_command
, flagsforhist
, NULL
)) != NULL
){
3670 strncpy(pipe_command
, p
, sizeof(pipe_command
));
3671 pipe_command
[sizeof(pipe_command
)-1] = '\0';
3672 if(history
->hist
[history
->curindex
]){
3673 flagsforhist
= history
->hist
[history
->curindex
]->flags
;
3674 raw
= (flagsforhist
& 0x2) ? 1 : 0;
3675 capture
= (flagsforhist
& 0x1) ? 1 : 0;
3682 if(pipe_command
[0] == '\0'){
3683 cmd_cancelled("Pipe command");
3687 flagsforhist
= (raw
? 0x2 : 0) + (capture
? 0x1 : 0);
3688 save_hist(history
, pipe_command
, flagsforhist
, NULL
);
3690 flags
= PIPE_USER
| PIPE_WRITE
| PIPE_STDERR
;
3691 flags
|= (raw
? PIPE_RAW
: 0);
3697 ps_global
->mangled_screen
= 1;
3699 flags
|= PIPE_RESET
;
3702 if((syspipe
= open_system_pipe(pipe_command
,
3703 (flags
&PIPE_RESET
) ? NULL
: &resultfilename
,
3704 NULL
, flags
, 0, pipe_callback
, pipe_report_error
)) != NULL
){
3706 gf_io_t pc
; /* wire up a generic putchar */
3708 is_text
= (a
&& a
->body
&& a
->body
->type
== TYPETEXT
);
3710 gf_set_writec(&pc
, syspipe
, 0L, PipeStar
,
3711 (is_text
&& !raw
) ? WRITE_TO_LOCALE
: 0);
3713 /*------ Write the image to a temporary file ------*/
3714 if(raw
){ /* pipe raw text */
3715 FETCH_READC_S fetch_part
;
3720 we_cancel
= busy_cue(NULL
, NULL
, 1);
3725 fetch_readc_init(&fetch_part
, ps_global
->mail_stream
,
3726 msgno
, a
->number
, a
->body
->size
.bytes
, 0, 0);
3727 gf_link_filter(gf_nvtnl_local
, NULL
);
3728 err
= gf_pipe(FETCH_READC
, pc
);
3738 /* BUG: there's got to be a better way */
3740 ps_global
->print
= (PRINT_S
*) 1;
3743 err
= detach(ps_global
->mail_stream
, msgno
,
3744 a
->number
, 0L, (long *)NULL
, pc
, NULL
, 0);
3745 ps_global
->print
= (PRINT_S
*) NULL
;
3749 (void) close_system_pipe(&syspipe
, NULL
, pipe_callback
);
3752 q_status_message1(SM_ORDER
| SM_DING
, 3, 4,
3753 _("Error detaching for pipe: %s"), err
);
3755 display_output_file(resultfilename
,
3757 ? _("PIPE ATTACHMENT (ERROR)")
3758 : _("PIPE ATTACHMENT"),
3761 fs_give((void **) &resultfilename
);
3764 q_status_message(SM_ORDER
| SM_DING
, 3, 4,
3765 _("Error opening pipe"));
3770 cmd_cancelled("Pipe");
3774 help
= (help
== NO_HELP
) ? h_pipe_attach
: NO_HELP
;
3780 delete_attachment(long int msgno
, ATTACH_S
*a
)
3782 int expbits
, rv
= 0;
3784 if(!msgno_exceptions(ps_global
->mail_stream
, msgno
,
3785 a
->number
, &expbits
, FALSE
)
3786 || !(expbits
& MSG_EX_DELETE
)){
3787 expbits
|= MSG_EX_DELETE
;
3788 msgno_exceptions(ps_global
->mail_stream
, msgno
,
3789 a
->number
, &expbits
, TRUE
);
3791 q_status_message1(SM_ORDER
, 0, 3,
3792 _("Part %s will be omitted only if message is Saved"),
3797 q_status_message1(SM_ORDER
, 0, 3, _("Part %s already deleted"),
3805 undelete_attachment(long int msgno
, ATTACH_S
*a
, int *expbitsp
)
3809 if(msgno_exceptions(ps_global
->mail_stream
, msgno
,
3810 a
->number
, expbitsp
, FALSE
)
3811 && ((*expbitsp
) & MSG_EX_DELETE
)){
3812 (*expbitsp
) ^= MSG_EX_DELETE
;
3813 msgno_exceptions(ps_global
->mail_stream
, msgno
,
3814 a
->number
, expbitsp
, TRUE
);
3818 q_status_message1(SM_ORDER
, 0, 3, _("Part %s already UNdeleted"),
3825 /*----------------------------------------------------------------------
3826 Resolve any deferred tests for attachment displayability
3828 Args: attachment structure
3830 Returns: undefer's attachment's displayability test
3833 dispatch_attachment(ATTACH_S
*a
)
3835 if(a
->test_deferred
){
3836 a
->test_deferred
= 0;
3837 a
->can_display
= mime_can_display(a
->body
->type
, a
->body
->subtype
, a
->body
);
3840 return(a
->can_display
);
3846 scroll_att_popup(sparms
, in_handle
)
3850 MPopup scrat_popup
[20];
3854 scrat_popup
[++i
].type
= tIndex
;
3855 scrat_popup
[i
].label
.style
= lNormal
;
3856 scrat_popup
[i
].label
.string
= "View Selectable Item";
3857 scrat_popup
[i
].data
.val
= ctrl('L');
3860 scrat_popup
[++i
].type
= tQueue
;
3861 scrat_popup
[i
].label
.style
= lNormal
;
3862 scrat_popup
[i
].label
.string
= "&Save";
3863 scrat_popup
[i
].data
.val
= 'S';
3865 scrat_popup
[++i
].type
= tQueue
;
3866 scrat_popup
[i
].label
.style
= lNormal
;
3867 if(msgno_exceptions(ps_global
->mail_stream
,
3868 mn_m2raw(ps_global
->msgmap
,
3869 mn_get_cur(ps_global
->msgmap
)),
3870 scrat_attachp
->number
, &n
, FALSE
)
3871 && (n
& MSG_EX_DELETE
)){
3872 scrat_popup
[i
].label
.string
= "&Undelete";
3873 scrat_popup
[i
].data
.val
= 'U';
3876 scrat_popup
[i
].label
.string
= "&Delete";
3877 scrat_popup
[i
].data
.val
= 'D';
3880 if(MIME_MSG_A(scrat_attachp
) || MIME_DGST_A(scrat_attachp
)){
3881 scrat_popup
[++i
].type
= tQueue
;
3882 scrat_popup
[i
].label
.style
= lNormal
;
3883 scrat_popup
[i
].label
.string
= "&Reply";
3884 scrat_popup
[i
].data
.val
= 'R';
3886 scrat_popup
[++i
].type
= tQueue
;
3887 scrat_popup
[i
].label
.style
= lNormal
;
3888 scrat_popup
[i
].label
.string
= "&Forward";
3889 scrat_popup
[i
].data
.val
= 'f';
3892 scrat_popup
[++i
].type
= tSeparator
;
3894 scrat_popup
[++i
].type
= tQueue
;
3895 scrat_popup
[i
].label
.style
= lNormal
;
3896 scrat_popup
[i
].label
.string
= "Attachment Index";
3897 scrat_popup
[i
].data
.val
= '<';
3899 scrat_popup
[++i
].type
= tTail
;
3901 return(mswin_popup(scrat_popup
) == 0 && in_handle
);
3906 display_att_window(a
)
3909 #if !defined(DOS) && !defined(OS2)
3913 if(a
->body
->type
== TYPEMULTIPART
){
3914 if(a
->body
->subtype
){
3915 /* if(!strucmp(a->body->subtype, "digest"))
3916 display_digest_att(msgno, a, flags);
3918 q_status_message1(SM_ORDER
, 3, 5,
3919 "Can't display Multipart/%s",
3923 q_status_message(SM_ORDER
, 3, 5,
3924 "Can't display unknown Multipart Subtype");
3926 /* else if(MIME_VCARD_A(a))
3927 display_vcard_att_window(msgno, a, flags);*/
3928 else if(a
->body
->type
== TYPETEXT
)
3929 display_text_att_window(a
);
3930 else if(a
->body
->type
== TYPEMESSAGE
)
3931 display_msg_att_window(a
);
3936 display_text_att_window(a
)
3942 msgno
= mn_m2raw(ps_global
->msgmap
, mn_get_cur(ps_global
->msgmap
));
3944 if(store
= format_text_att(msgno
, a
, NULL
)){
3945 if (mswin_displaytext("ATTACHED TEXT",
3947 strlen((char *) so_text(store
)),
3948 NULL
, NULL
, 0) >= 0)
3949 store
->txt
= (void *) NULL
; /* free'd in mswin_displaytext */
3951 so_give(&store
); /* free resources associated with store */
3954 q_status_message(SM_ORDER
| SM_DING
, 3, 3,
3955 "Error allocating space for attachment.");
3960 display_msg_att_window(a
)
3968 msgno
= mn_m2raw(ps_global
->msgmap
, mn_get_cur(ps_global
->msgmap
));
3970 /* BUG, should check this return code */
3971 (void) pine_mail_fetchstructure(ps_global
->mail_stream
, msgno
, NULL
);
3973 /* initialize a storage object */
3974 if(store
= so_get(CharStar
, NULL
, EDIT_ACCESS
)){
3976 gf_set_so_writec(&pc
, store
);
3978 if(format_msg_att(msgno
, &ap
, NULL
, pc
, FM_DISPLAY
)
3979 && mswin_displaytext("ATTACHED MESSAGE", so_text(store
),
3980 strlen((char *) so_text(store
)),
3981 NULL
, NULL
, 0) >= 0)
3982 /* free'd in mswin_displaytext */
3983 store
->txt
= (void *) NULL
;
3985 gf_clear_so_writec(store
);
3990 q_status_message(SM_ORDER
| SM_DING
, 3, 3,
3991 "Error allocating space for message.");