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 2013-2021 Eduardo Chappa
8 * Copyright 2006-2008 University of Washington
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.
43 #include "../pith/state.h"
44 #include "../pith/conf.h"
45 #include "../pith/store.h"
46 #include "../pith/msgno.h"
47 #include "../pith/detach.h"
48 #include "../pith/handle.h"
49 #include "../pith/filter.h"
50 #include "../pith/bitmap.h"
51 #include "../pith/charset.h"
52 #include "../pith/mimedesc.h"
53 #include "../pith/mailcap.h"
54 #include "../pith/newmail.h"
55 #include "../pith/rfc2231.h"
56 #include "../pith/flag.h"
57 #include "../pith/text.h"
58 #include "../pith/editorial.h"
59 #include "../pith/save.h"
60 #include "../pith/pipe.h"
61 #include "../pith/util.h"
62 #include "../pith/detoken.h"
63 #include "../pith/busy.h"
64 #include "../pith/mimetype.h"
65 #include "../pith/icache.h"
66 #include "../pith/list.h"
67 #include "../pith/ablookup.h"
68 #include "../pith/options.h"
69 #include "../pith/smime.h"
70 #include "../pith/ical.h"
71 #include "../pith/body.h"
72 #include "../pith/init.h"
75 * Information used to paint and maintain a line on the attachment
78 typedef struct atdisp_line
{
79 char *dstring
; /* alloc'd var value string */
80 ATTACH_S
*attp
; /* actual attachment pointer */
81 struct atdisp_line
*next
, *prev
;
86 * struct defining attachment screen's current state
88 typedef struct att_screen
{
91 COLOR_PAIR
*titlecolor
;
94 static ATT_SCREEN_S
*att_screen
;
97 #define next_attline(p) ((p) ? (p)->next : NULL)
98 #define prev_attline(p) ((p) ? (p)->prev : NULL)
103 * local global pointer to scroll attachment popup menu
105 static ATTACH_S
*scrat_attachp
;
109 #define FETCH_READC g_fr_desc->readc
112 /* used to keep track of detached MIME segments total length */
113 static long save_att_length
;
116 * Internal Prototypes
118 ATDISP_S
*new_attline(ATDISP_S
**);
119 void free_attline(ATDISP_S
**);
120 int attachment_screen_updater(struct pine
*, ATDISP_S
*, ATT_SCREEN_S
*);
121 void attachment_screen_redrawer(void);
122 void update_att_screen_titlebar(void);
123 ATDISP_S
*first_attline(ATDISP_S
*);
124 int init_att_progress(char *, MAILSTREAM
*, BODY
*);
125 long save_att_piped(int);
126 int save_att_percent(void);
127 void save_attachment(int, long, ATTACH_S
*);
128 void export_attachment(int, long, ATTACH_S
*);
129 char *write_attached_msg(long, ATTACH_S
**, STORE_S
*, int);
130 void save_msg_att(long, ATTACH_S
*);
131 void save_digest_att(long, ATTACH_S
*);
132 int save_msg_att_work(long int, ATTACH_S
*, MAILSTREAM
*, char *,
133 CONTEXT_S
*, char *);
134 void export_msg_att(long, ATTACH_S
*);
135 void export_digest_att(long, ATTACH_S
*);
136 void print_attachment(int, long, ATTACH_S
*);
137 int print_msg_att(long, ATTACH_S
*, int);
138 void print_digest_att(long, ATTACH_S
*);
139 void run_viewer(char *, BODY
*, int);
140 STORE_S
*format_text_att(long, ATTACH_S
*, HANDLE_S
**);
141 int display_text_att(long, ATTACH_S
*, int);
142 int display_msg_att(long, ATTACH_S
*, int);
143 void display_digest_att(long, ATTACH_S
*, int);
144 int scroll_attachment(char *, STORE_S
*, SourceType
, HANDLE_S
*, ATTACH_S
*, int);
145 int process_attachment_cmd(int, MSGNO_S
*, SCROLL_S
*);
146 int format_msg_att(long, ATTACH_S
**, HANDLE_S
**, gf_io_t
, int);
147 void display_vcard_att(long, ATTACH_S
*, int);
148 void display_vcalendar_att(long, ATTACH_S
*, int);
149 void display_attach_info(long, ATTACH_S
*);
150 int display_html_external_attachment(long int, ATTACH_S
*, int);
151 void forward_attachment(MAILSTREAM
*, long, ATTACH_S
*);
152 void forward_msg_att(MAILSTREAM
*, long, ATTACH_S
*);
153 void reply_msg_att(MAILSTREAM
*, long, ATTACH_S
*);
154 void bounce_msg_att(MAILSTREAM
*, long, char *, char *);
155 void pipe_attachment(long, ATTACH_S
*);
156 int delete_attachment(long, ATTACH_S
*);
157 int undelete_attachment(long, ATTACH_S
*, int *);
159 int scroll_att_popup(SCROLL_S
*, int);
160 void display_text_att_window(ATTACH_S
*);
161 void display_msg_att_window(ATTACH_S
*);
165 /*----------------------------------------------------------------------
166 Provide attachments in browser for selected action
168 Args: ps -- pointer to pine structure
169 msgmap -- struct containing current message to display
173 Handle painting and navigation of attachment index. It would be nice
174 to someday handle message/rfc822 segments in a neat way (i.e., enable
175 forwarding, take address, etc.).
178 attachment_screen(struct pine
*ps
)
182 maxnumwid
= 0, maxsizewid
= 0, old_cols
= -1, km_popped
= 0, expbits
,
183 last_type
= TYPEOTHER
;
185 char *q
, *last_subtype
= NULL
, backtag
[64], *utf8str
;
188 ATDISP_S
*current
= NULL
, *ctmp
= NULL
;
191 ps
->prev_screen
= attachment_screen
;
192 ps
->next_screen
= SCREEN_FUN_NULL
;
194 ps
->some_quoting_was_suppressed
= 0;
196 if(ps
->ttyo
->screen_rows
- HEADER_ROWS(ps
) - FOOTER_ROWS(ps
) < 1){
197 q_status_message(SM_ORDER
| SM_DING
, 0, 3,
198 _("Screen too small to view attachment"));
199 ps
->next_screen
= mail_view_screen
;
203 if(mn_total_cur(ps
->msgmap
) > 1L){
204 q_status_message(SM_ORDER
| SM_DING
, 0, 3,
205 _("Can only view one message's attachments at a time."));
208 else if(ps
->atmts
&& ps
->atmts
->description
&& !(ps
->atmts
+ 1)->description
)
209 q_status_message1(SM_ASYNC
, 0, 3,
210 _("Message %s has only one part (the message body), and no attachments."),
211 long2string(mn_get_cur(ps
->msgmap
)));
213 /*----- Figure max display widths -----*/
214 for(a
= ps
->atmts
; a
&& a
->description
!= NULL
; a
++){
215 if((n
= utf8_width(a
->number
)) > maxnumwid
)
218 if((n
= utf8_width(a
->size
)) > maxsizewid
)
223 * Then, allocate and initialize attachment line list...
225 for(a
= ps
->atmts
; a
&& a
->description
; a
++)
226 new_attline(¤t
)->attp
= a
;
228 memset(&screen
, 0, sizeof(screen
));
229 msgno
= mn_m2raw(ps
->msgmap
, mn_get_cur(ps
->msgmap
));
230 ps
->mangled_screen
= 1; /* build display */
231 ps
->redrawer
= attachment_screen_redrawer
;
232 att_screen
= &screen
;
233 current
= first_attline(current
);
237 * Advance to next attachment if it's likely that we've already
238 * shown it to the user...
241 if (current
== NULL
){
242 q_status_message1(SM_ORDER
| SM_DING
, 0, 3,
243 _("Malformed message: %s"),
244 ps
->c_client_error
? ps
->c_client_error
: "?");
245 ps
->next_screen
= mail_view_screen
;
247 else if(current
->attp
->shown
&& (ctmp
= next_attline(current
)))
250 while(ps
->next_screen
== SCREEN_FUN_NULL
){
251 ps
->user_says_cancel
= 0;
256 ps
->mangled_body
= 1;
260 if(ps
->mangled_screen
){
262 * build/rebuild display lines
264 if(old_cols
!= ps
->ttyo
->screen_cols
){
265 int avail
, s1
, s2
, s4
, s5
, dwid
, sizewid
, descwid
;
267 avail
= ps_global
->ttyo
->screen_cols
;
269 s1
= MAX(MIN(1, avail
), 0);
272 dwid
= MAX(MIN(1, avail
), 0);
275 s2
= MAX(MIN(1, avail
), 0);
278 /* Only give up a third of the display to part numbers */
279 maxnumwid
= MIN(maxnumwid
, (ps_global
->ttyo
->screen_cols
/3));
280 maxnumwid
= MAX(MIN(maxnumwid
, avail
), 0);
283 s4
= MAX(MIN(3, avail
), 0);
286 sizewid
= MAX(MIN(maxsizewid
, avail
), 0);
289 s5
= MAX(MIN(3, avail
), 0);
292 descwid
= MAX(0, avail
);
294 old_cols
= ps
->ttyo
->screen_cols
;
296 for(ctmp
= first_attline(current
);
297 ctmp
&& (a
= ctmp
->attp
) && a
->description
;
298 ctmp
= next_attline(ctmp
)){
301 char description
[1000];
304 fs_give((void **)&ctmp
->dstring
);
306 len
= 6 * MAX(80, ps
->ttyo
->screen_cols
) * sizeof(char);
307 ctmp
->dstring
= (char *)fs_get(len
+ 1);
312 q
= a
->body
->description
;
313 if(!(q
&& q
[0]) && (MIME_MSG_A(a
) && a
->body
->nested
.msg
->env
))
314 q
= a
->body
->nested
.msg
->env
->subject
;
319 strncpy(buftmp
, q
, sizeof(buftmp
));
320 buftmp
[sizeof(buftmp
)-1] = '\0';
322 q
= (char *) rfc1522_decode_to_utf8((unsigned char *) tmp_20k_buf
,
323 SIZEOF_20KBUF
, buftmp
);
329 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
? "\"" : "");
330 description
[sizeof(description
)-1] = '\0';
332 utf8_snprintf(ctmp
->dstring
, len
+1,
333 "%*.*s%*.*w%*.*s%-*.*w%*.*s%*.*w%*.*s%-*.*w",
336 msgno_part_deleted(ps
->mail_stream
, msgno
, a
->number
) ? "D" : "",
338 maxnumwid
, maxnumwid
,
340 ? short_str(a
->number
, numbuf
, sizeof(numbuf
), maxnumwid
, FrontDots
)
344 a
->size
? a
->size
: "",
346 descwid
, descwid
, description
);
348 ctmp
->dstring
[len
] = '\0';
352 ps
->mangled_header
= 1;
353 ps
->mangled_footer
= 1;
354 ps
->mangled_body
= 1;
357 /*----------- Check for new mail -----------*/
358 if(new_mail(0, NM_TIMING(ch
), NM_STATUS_MSG
| NM_DEFER_SORT
) >= 0)
359 ps
->mangled_header
= 1;
362 * If an expunge of the current message happened during the
363 * new mail check we want to bail out of here. See mm_expunged.
365 if(ps
->next_screen
!= SCREEN_FUN_NULL
)
368 if(ps
->mangled_header
){
369 update_att_screen_titlebar();
370 ps
->mangled_header
= 0;
373 if(ps
->mangled_screen
){
375 ps
->mangled_screen
= 0;
378 dline
= attachment_screen_updater(ps
, current
, &screen
);
380 /*---- This displays new mail notification, or errors ---*/
383 mark_status_unknown();
389 mark_status_unknown();
392 if(ps
->mangled_footer
393 || current
->attp
->body
->type
!= last_type
394 || !(last_subtype
&& current
->attp
->body
->subtype
)
395 || strucmp(last_subtype
, current
->attp
->body
->subtype
)){
397 struct key_menu
*km
= &att_index_keymenu
;
401 ps
->mangled_footer
= 0;
402 last_type
= current
->attp
->body
->type
;
403 last_subtype
= current
->attp
->body
->subtype
;
405 snprintf(backtag
, sizeof(backtag
), "Msg #%ld", mn_get_cur(ps
->msgmap
));
406 backtag
[sizeof(backtag
)-1] = '\0';
407 km
->keys
[ATT_PARENT_KEY
].label
= backtag
;
409 if(F_OFF(F_ENABLE_PIPE
, ps
))
410 clrbitn(ATT_PIPE_KEY
, bitmap
);
413 * If message or digest, leave Reply and Save and,
414 * conditionally, Bounce on...
416 if(MIME_MSG(last_type
, last_subtype
)){
417 if(F_OFF(F_ENABLE_BOUNCE
, ps
))
418 clrbitn(ATT_BOUNCE_KEY
, bitmap
);
420 km
->keys
[ATT_EXPORT_KEY
].name
= "";
421 km
->keys
[ATT_EXPORT_KEY
].label
= "";
423 else if(MIME_DGST(last_type
, last_subtype
)){
424 clrbitn(ATT_BOUNCE_KEY
, bitmap
);
425 clrbitn(ATT_REPLY_KEY
, bitmap
);
427 km
->keys
[ATT_EXPORT_KEY
].name
= "";
428 km
->keys
[ATT_EXPORT_KEY
].label
= "";
431 clrbitn(ATT_BOUNCE_KEY
, bitmap
);
432 clrbitn(ATT_REPLY_KEY
, bitmap
);
434 if(last_type
!= TYPETEXT
)
435 clrbitn(ATT_PRINT_KEY
, bitmap
);
437 km
->keys
[ATT_EXPORT_KEY
].name
= "E";
438 km
->keys
[ATT_EXPORT_KEY
].label
= N_("Export");
446 if(F_ON(F_ARROW_NAV
, ps
)){
447 menu_add_binding(km
, KEY_LEFT
, MC_EXIT
);
448 menu_add_binding(km
, KEY_RIGHT
, MC_VIEW_ATCH
);
451 menu_clear_binding(km
, KEY_LEFT
);
452 menu_clear_binding(km
, KEY_RIGHT
);
455 draw_keymenu(km
, bitmap
, ps
->ttyo
->screen_cols
, 1-FOOTER_ROWS(ps
),
460 mark_keymenu_dirty();
464 if(F_ON(F_SHOW_CURSOR
, ps
))
465 MoveCursor(dline
, 0);
467 MoveCursor(MAX(0, ps
->ttyo
->screen_rows
- FOOTER_ROWS(ps
)), 0);
469 /*------ Prepare to read the command from the keyboard ----*/
471 mouse_in_content(KEY_MOUSE
, -1, -1, 0, 0); /* prime the handler */
472 register_mfunc(mouse_in_content
, HEADER_ROWS(ps_global
), 0,
473 ps_global
->ttyo
->screen_rows
-(FOOTER_ROWS(ps_global
)+1),
474 ps_global
->ttyo
->screen_cols
);
476 ch
= READ_COMMAND(&utf8str
);
478 clear_mfunc(mouse_in_content
);
481 cmd
= menu_command(ch
, &att_index_keymenu
);
499 if(FOOTER_ROWS(ps
) == 1 && km_popped
== 0){
501 ps
->mangled_footer
= 1;
505 helper(h_attachment_screen
, _("HELP FOR ATTACHMENT INDEX"), 0);
506 ps
->mangled_screen
= 1;
511 ps
->mangled_footer
= 1;
516 if(ps
->full_header
== 1){
517 if(!(ps
->quote_suppression_threshold
518 && (ps
->some_quoting_was_suppressed
/* || in_index != View */)))
521 else if(ps
->full_header
> 2)
524 switch(ps
->full_header
){
526 q_status_message(SM_ORDER
, 0, 3,
527 _("Display of full headers is now off."));
531 q_status_message1(SM_ORDER
, 0, 3,
532 _("Quotes displayed, use %s to see full headers"),
533 F_ON(F_USE_FK
, ps
) ? "F9" : "H");
537 q_status_message(SM_ORDER
, 0, 3,
538 _("Display of full headers is now on."));
546 display_html_external_attachment(msgno
, current
->attp
,
547 DA_EXTERNAL
| DA_SAVE
| (F_OFF(F_EXTERNAL_INLINE_IMAGES
, ps_global
) ? DA_ALLIMAGES
: 0));
550 case MC_EXIT
: /* exit attachment screen */
551 ps
->next_screen
= mail_view_screen
;
555 ps
->next_screen
= quit_screen
;
559 ps
->next_screen
= main_menu_screen
;
563 ps
->next_screen
= mail_index_screen
;
567 if((ctmp
= next_attline(current
)) != NULL
)
570 q_status_message(SM_ORDER
, 0, 1, _("Already on last attachment"));
575 if((ctmp
= prev_attline(current
)) != NULL
)
578 q_status_message(SM_ORDER
, 0, 1, _("Already on first attachment"));
582 case MC_PAGEDN
: /* page forward */
583 if(next_attline(current
)){
584 while(dline
++ < ps
->ttyo
->screen_rows
- FOOTER_ROWS(ps
))
585 if((ctmp
= next_attline(current
)) != NULL
)
591 q_status_message(SM_ORDER
, 0, 1,
592 _("Already on last page of attachments"));
596 case MC_PAGEUP
: /* page backward */
597 if(prev_attline(current
)){
598 while(dline
-- > HEADER_ROWS(ps
))
599 if((ctmp
= prev_attline(current
)) != NULL
)
604 while(++dline
< ps
->ttyo
->screen_rows
- FOOTER_ROWS(ps
))
605 if((ctmp
= prev_attline(current
)) != NULL
)
611 q_status_message(SM_ORDER
, 0, 1,
612 _("Already on first page of attachments"));
621 mouse_get_last (NULL
, &mp
);
622 mp
.row
-= HEADER_ROWS(ps
);
623 ctmp
= screen
.top_line
;
624 while (mp
.row
&& ctmp
!= NULL
) {
633 if(mp
.button
== M_BUTTON_LEFT
)
634 display_attachment(msgno
, current
->attp
, DA_SAVE
);
637 else if(mp
.button
== M_BUTTON_RIGHT
){
638 MPopup atmt_popup
[20];
639 int i
= -1, exoffer
= 0;
641 dline
= attachment_screen_updater(ps
,current
,&screen
);
643 if(dispatch_attachment(current
->attp
) != MCD_NONE
){
644 atmt_popup
[++i
].type
= tQueue
;
645 atmt_popup
[i
].data
.val
= 'V';
646 atmt_popup
[i
].label
.style
= lNormal
;
647 atmt_popup
[i
].label
.string
= "&View";
649 if(!(current
->attp
->can_display
& MCD_EXTERNAL
)
650 && (current
->attp
->body
->type
== TYPETEXT
651 || MIME_MSG_A(current
->attp
)
652 || MIME_DGST_A(current
->attp
))){
654 atmt_popup
[++i
].type
= tIndex
;
655 atmt_popup
[i
].label
.style
= lNormal
;
656 atmt_popup
[i
].label
.string
=
657 "View in New Window";
661 atmt_popup
[++i
].type
= tQueue
;
662 atmt_popup
[i
].data
.val
= 'S';
663 atmt_popup
[i
].label
.style
= lNormal
;
664 atmt_popup
[i
].label
.string
= "&Save";
666 atmt_popup
[++i
].type
= tQueue
;
667 atmt_popup
[i
].label
.style
= lNormal
;
668 if(current
->dstring
[1] == 'D'){
669 atmt_popup
[i
].data
.val
= 'U';
670 atmt_popup
[i
].label
.string
= "&Undelete";
673 atmt_popup
[i
].data
.val
= 'D';
674 atmt_popup
[i
].label
.string
= "&Delete";
677 if(MIME_MSG_A(current
->attp
)){
678 atmt_popup
[++i
].type
= tQueue
;
679 atmt_popup
[i
].label
.style
= lNormal
;
680 atmt_popup
[i
].label
.string
= "&Reply...";
681 atmt_popup
[i
].data
.val
= 'R';
683 atmt_popup
[++i
].type
= tQueue
;
684 atmt_popup
[i
].label
.style
= lNormal
;
685 atmt_popup
[i
].label
.string
= "&Forward...";
686 atmt_popup
[i
].data
.val
= 'F';
689 atmt_popup
[++i
].type
= tQueue
;
690 atmt_popup
[i
].label
.style
= lNormal
;
691 atmt_popup
[i
].label
.string
= "&About...";
692 atmt_popup
[i
].data
.val
= 'A';
694 atmt_popup
[++i
].type
= tSeparator
;
696 atmt_popup
[++i
].type
= tQueue
;
697 snprintf(backtag
, sizeof(backtag
), "View Message #%ld",
698 mn_get_cur(ps
->msgmap
));
699 backtag
[sizeof(backtag
)-1] = '\0';
700 atmt_popup
[i
].label
.string
= backtag
;
701 atmt_popup
[i
].label
.style
= lNormal
;
702 atmt_popup
[i
].data
.val
= '<';
704 atmt_popup
[++i
].type
= tTail
;
706 if(mswin_popup(atmt_popup
) == 1 && exoffer
)
707 display_att_window(current
->attp
);
710 else if(mp
.button
== M_BUTTON_RIGHT
){
711 MPopup atmt_popup
[2];
713 atmt_popup
[0].type
= tQueue
;
714 snprintf(backtag
, sizeof(backtag
), "View Message #%ld",
715 mn_get_cur(ps
->msgmap
));
716 backtag
[sizeof(backtag
)-1] = '\0';
717 atmt_popup
[0].label
.string
= backtag
;
718 atmt_popup
[0].label
.style
= lNormal
;
719 atmt_popup
[0].data
.val
= '<';
721 atmt_popup
[1].type
= tTail
;
723 mswin_popup(atmt_popup
);
730 case MC_WHEREIS
: /* whereis */
731 /*--- get string ---*/
733 char *result
= NULL
, buf
[64];
734 static char last
[64], tmp
[64];
737 ps
->mangled_footer
= 1;
739 snprintf(tmp
, sizeof(tmp
), "Word to find %s%s%s: ",
740 (last
[0]) ? "[" : "",
741 (last
[0]) ? last
: "",
742 (last
[0]) ? "]" : "");
743 tmp
[sizeof(tmp
)-1] = '\0';
746 int flags
= OE_APPEND_CURRENT
| OE_SEQ_SENSITIVE
;
748 rc
= optionally_enter(buf
,-FOOTER_ROWS(ps
),0,sizeof(buf
),
749 tmp
,NULL
,help
,&flags
);
751 help
= help
== NO_HELP
? h_attach_index_whereis
: NO_HELP
;
752 else if(rc
== 0 || rc
== 1 || !buf
[0]){
753 if(rc
== 0 && !buf
[0] && last
[0]){
754 strncpy(buf
, last
, sizeof(buf
));
755 buf
[sizeof(buf
)-1] = '\0';
762 if(rc
== 0 && buf
[0]){
764 while((ctmp
= next_attline(ctmp
)) != NULL
)
765 if(srchstr(ctmp
->dstring
, buf
)){
771 ctmp
= first_attline(current
);
773 while(ctmp
!= current
)
774 if(srchstr(ctmp
->dstring
, buf
)){
779 ctmp
= next_attline(ctmp
);
783 result
= _("WhereIs cancelled");
786 strncpy(last
, buf
, sizeof(last
));
787 last
[sizeof(last
)-1] = '\0';
788 result
= "Word found";
792 q_status_message(SM_ORDER
, 0, 3,
793 result
? result
: _("Word not found"));
799 if(delete_attachment(msgno
, current
->attp
)){
800 int l
= current
? strlen(current
->attp
->number
) : 0;
802 current
->dstring
[1] = 'D';
804 /* Also indicate any children that will be deleted */
806 for(ctmp
= current
; ctmp
; ctmp
= next_attline(ctmp
))
807 if(!strncmp(ctmp
->attp
->number
, current
->attp
->number
, l
)
808 && ctmp
->attp
->number
[l
] == '.'){
809 ctmp
->dstring
[1] = 'D';
810 ps
->mangled_screen
= 1;
817 if(undelete_attachment(msgno
, current
->attp
, &expbits
)){
818 int l
= current
? strlen(current
->attp
->number
) : 0;
820 current
->dstring
[1] = ' ';
822 /* And unflag anything implicitly undeleted */
823 for(ctmp
= current
; ctmp
; ctmp
= next_attline(ctmp
))
824 if(!strncmp(ctmp
->attp
->number
, current
->attp
->number
, l
)
825 && ctmp
->attp
->number
[l
] == '.'
826 && (!msgno_exceptions(ps
->mail_stream
, msgno
,
827 ctmp
->attp
->number
, &expbits
, FALSE
)
828 || !(expbits
& MSG_EX_DELETE
))){
829 ctmp
->dstring
[1] = ' ';
830 ps
->mangled_screen
= 1;
837 reply_msg_att(ps
->mail_stream
, msgno
, current
->attp
);
841 forward_attachment(ps
->mail_stream
, msgno
, current
->attp
);
845 bounce_msg_att(ps
->mail_stream
, msgno
, current
->attp
->number
,
846 current
->attp
->body
->nested
.msg
->env
->subject
);
847 ps
->mangled_footer
= 1;
851 display_attach_info(msgno
, current
->attp
);
854 case MC_VIEW_ATCH
: /* View command */
855 display_attachment(msgno
, current
->attp
, DA_SAVE
);
857 /* fall thru to repaint */
859 case MC_REPAINT
: /* redraw */
861 ps
->mangled_screen
= 1;
865 export_attachment(-FOOTER_ROWS(ps
), msgno
, current
->attp
);
866 ps
->mangled_footer
= 1;
869 case MC_SAVETEXT
: /* Save command */
870 save_attachment(-FOOTER_ROWS(ps
), msgno
, current
->attp
);
871 ps
->mangled_footer
= 1;
874 case MC_PRINTMSG
: /* Save command */
875 print_attachment(-FOOTER_ROWS(ps
), msgno
, current
->attp
);
876 ps
->mangled_footer
= 1;
879 case MC_PIPE
: /* Pipe command */
880 if(F_ON(F_ENABLE_PIPE
, ps
)){
881 pipe_attachment(msgno
, current
->attp
);
882 ps
->mangled_footer
= 1;
884 } /* fall thru to complain */
886 case MC_NONE
: /* simple timeout */
890 bogus_utf8_command(utf8str
, F_ON(F_USE_FK
, ps
) ? "F1" : "?");
901 bogus_command(ch
, F_ON(F_USE_FK
, ps
) ? "F1" : "?");
906 for(current
= first_attline(current
); current
;){ /* clean up */
907 ctmp
= current
->next
;
908 free_attline(¤t
);
912 if(screen
.titlecolor
)
913 free_color_pair(&screen
.titlecolor
);
917 /*----------------------------------------------------------------------
918 allocate and attach a fresh attachment line struct
920 Args: current -- display line to attach new struct to
922 Returns: newly alloc'd attachment display line
925 new_attline(ATDISP_S
**current
)
929 p
= (ATDISP_S
*)fs_get(sizeof(ATDISP_S
));
930 memset((void *)p
, 0, sizeof(ATDISP_S
));
933 p
->next
= (*current
)->next
;
934 (*current
)->next
= p
;
947 /*----------------------------------------------------------------------
948 Release system resources associated with attachment display line
950 Args: p -- line to free
955 free_attline(ATDISP_S
**p
)
959 fs_give((void **)&(*p
)->dstring
);
966 /*----------------------------------------------------------------------
967 Manage display of the attachment screen menu body.
969 Args: ps -- pine struct pointer
970 current -- currently selected display line
971 screen -- reference points for display painting
976 attachment_screen_updater(struct pine
*ps
, ATDISP_S
*current
, ATT_SCREEN_S
*screen
)
978 int dline
, return_line
= HEADER_ROWS(ps
);
979 ATDISP_S
*top_line
, *ctmp
;
981 /* calculate top line of display */
983 ctmp
= top_line
= first_attline(current
);
985 if(((dline
++)%(ps
->ttyo
->screen_rows
-HEADER_ROWS(ps
)-FOOTER_ROWS(ps
)))==0)
987 while(ctmp
!= current
&& (ctmp
= next_attline(ctmp
)));
990 /* Don't know how to manage scroll bar for attachment screen yet. */
991 scroll_setrange (0L, 0L);
994 /* mangled body or new page, force redraw */
995 if(ps
->mangled_body
|| screen
->top_line
!= top_line
)
996 screen
->current
= NULL
;
998 /* loop thru painting what's needed */
999 for(dline
= 0, ctmp
= top_line
;
1000 dline
< ps
->ttyo
->screen_rows
- FOOTER_ROWS(ps
) - HEADER_ROWS(ps
);
1001 dline
++, ctmp
= next_attline(ctmp
)){
1004 * only fall thru painting if something needs painting...
1006 if(!(!screen
->current
|| ctmp
== screen
->current
|| ctmp
== current
))
1009 if(F_ON(F_ENABLE_DEL_WHEN_WRITING
, ps_global
))
1010 ClearLine(dline
+ HEADER_ROWS(ps
));
1011 if(ctmp
&& ctmp
->dstring
){
1012 char *p
= tmp_20k_buf
;
1013 int i
, col
, x
= 0, totlen
;
1015 if(F_ON(F_FORCE_LOW_SPEED
,ps
) || ps
->low_speed
){
1017 if(ctmp
== current
){
1018 return_line
= dline
+ HEADER_ROWS(ps
);
1019 PutLine0(dline
+ HEADER_ROWS(ps
), 0, "->");
1022 PutLine0(dline
+ HEADER_ROWS(ps
), 0, " ");
1025 * Only paint lines if we have to...
1030 else if(ctmp
== current
){
1031 return_line
= dline
+ HEADER_ROWS(ps
);
1035 totlen
= strlen(ctmp
->dstring
);
1038 * Copy the value to a temp buffer expanding tabs.
1039 * Assume the caller set the widths so as not to overflow the
1042 for(i
=0,col
=x
; ctmp
->dstring
[i
]; i
++){
1043 if(ctmp
->dstring
[i
] == TAB
){
1044 if((p
-tmp_20k_buf
) < SIZEOF_20KBUF
-8)
1047 while((++col
)&0x07);
1050 col
+= width_at_this_position((unsigned char *) &ctmp
->dstring
[i
], totlen
-i
);
1051 if((p
-tmp_20k_buf
) < SIZEOF_20KBUF
)
1052 *p
++ = ctmp
->dstring
[i
];
1057 if((p
-tmp_20k_buf
) < SIZEOF_20KBUF
)
1060 PutLine0(dline
+ HEADER_ROWS(ps
), x
, tmp_20k_buf
+ x
);
1063 && !(F_ON(F_FORCE_LOW_SPEED
,ps
) || ps
->low_speed
))
1066 else if(F_OFF(F_ENABLE_DEL_WHEN_WRITING
, ps_global
))
1067 ClearLine(dline
+ HEADER_ROWS(ps
));
1070 ps
->mangled_body
= 0;
1071 screen
->top_line
= top_line
;
1072 screen
->current
= current
;
1073 return(return_line
);
1077 /*----------------------------------------------------------------------
1078 Redraw the attachment screen based on the global "att_screen" struct
1085 attachment_screen_redrawer(void)
1089 update_att_screen_titlebar();
1090 ps_global
->mangled_header
= 0;
1093 ps_global
->mangled_body
= 1;
1094 (void)attachment_screen_updater(ps_global
,att_screen
->current
,att_screen
);
1097 draw_keymenu(&att_index_keymenu
, bitmap
, ps_global
->ttyo
->screen_cols
,
1098 1-FOOTER_ROWS(ps_global
), 0, SameMenu
);
1103 update_att_screen_titlebar(void)
1106 COLOR_PAIR
*returned_color
= NULL
;
1107 COLOR_PAIR
*titlecolor
= NULL
;
1109 SEARCHSET
*ss
= NULL
;
1110 PAT_STATE
*pstate
= NULL
;
1112 if(ps_global
->titlebar_color_style
!= TBAR_COLOR_DEFAULT
){
1113 raw_msgno
= mn_m2raw(ps_global
->msgmap
, mn_get_cur(ps_global
->msgmap
));
1114 ss
= mail_newsearchset();
1115 ss
->first
= ss
->last
= (unsigned long) raw_msgno
;
1118 colormatch
= get_index_line_color(ps_global
->mail_stream
,
1119 ss
, &pstate
, &returned_color
);
1120 mail_free_searchset(&ss
);
1123 * This is a bit tricky. If there is a colormatch but
1125 * is NULL, that means that the user explicitly wanted the
1126 * Normal color used in this index line, so that is what we
1127 * use. If no colormatch then we will use the TITLE color
1128 * instead of Normal.
1132 titlecolor
= returned_color
;
1134 titlecolor
= new_color_pair(ps_global
->VAR_NORM_FORE_COLOR
,
1135 ps_global
->VAR_NORM_BACK_COLOR
);
1139 && ps_global
->titlebar_color_style
== TBAR_COLOR_REV_INDEXLINE
){
1140 char cbuf
[MAXCOLORLEN
+1];
1142 strncpy(cbuf
, titlecolor
->fg
, sizeof(cbuf
));
1143 cbuf
[sizeof(cbuf
)-1] = '\0';
1144 strncpy(titlecolor
->fg
, titlecolor
->bg
, MAXCOLORLEN
);
1145 titlecolor
->fg
[MAXCOLORLEN
] = '\0';
1146 strncpy(titlecolor
->bg
, cbuf
, MAXCOLORLEN
);
1147 titlecolor
->bg
[MAXCOLORLEN
] = '\0';
1151 /* Did the color change? */
1152 if((!titlecolor
&& att_screen
->titlecolor
)
1154 (titlecolor
&& !att_screen
->titlecolor
)
1156 (titlecolor
&& att_screen
->titlecolor
1157 && (strcmp(titlecolor
->fg
, att_screen
->titlecolor
->fg
)
1158 || strcmp(titlecolor
->bg
, att_screen
->titlecolor
->bg
)))){
1160 if(att_screen
->titlecolor
)
1161 free_color_pair(&att_screen
->titlecolor
);
1163 att_screen
->titlecolor
= titlecolor
;
1168 free_color_pair(&titlecolor
);
1171 set_titlebar(_("ATTACHMENT INDEX"), ps_global
->mail_stream
,
1172 ps_global
->context_current
, ps_global
->cur_folder
,
1173 ps_global
->msgmap
, 1, MessageNumber
, 0, 0,
1174 att_screen
->titlecolor
);
1178 /*----------------------------------------------------------------------
1179 Seek back from the given display line to the beginning of the list
1181 Args: p -- display linked list
1186 first_attline(ATDISP_S
*p
)
1196 init_att_progress(char *msg
, MAILSTREAM
*stream
, struct mail_bodystruct
*body
)
1198 if((save_att_length
= body
->size
.bytes
) != 0){
1199 /* if there are display filters, factor in extra copy */
1200 if(body
->type
== TYPETEXT
&& ps_global
->VAR_DISPLAY_FILTERS
)
1201 save_att_length
+= body
->size
.bytes
;
1203 /* if remote folder and segment not cached, factor in IMAP fetch */
1204 if(stream
&& stream
->mailbox
&& IS_REMOTE(stream
->mailbox
)
1205 && !((body
->type
== TYPETEXT
&& body
->contents
.text
.data
)
1206 || ((body
->type
== TYPEMESSAGE
)
1207 && body
->nested
.msg
&& body
->nested
.msg
->text
.text
.data
)
1208 || body
->contents
.text
.data
))
1209 save_att_length
+= body
->size
.bytes
;
1211 gf_filter_init(); /* reset counters */
1214 return(busy_cue(msg
, save_att_percent
, 0));
1222 save_att_piped(int reset
)
1230 else if((y
= gf_bytes_piped()) >= x
){
1240 save_att_percent(void)
1242 int i
= (int) (((pine_gets_bytes(0) + save_att_piped(0)) * 100)
1244 return(MIN(i
, 100));
1248 /*----------------------------------------------------------------------
1249 Save the given attachment associated with the given message no
1256 save_attachment(int qline
, long int msgno
, ATTACH_S
*a
)
1258 if(ps_global
->restricted
){
1259 q_status_message(SM_ORDER
| SM_DING
, 0, 4,
1260 "Alpine demo can't save attachments");
1265 save_msg_att(msgno
, a
);
1266 else if(MIME_DGST_A(a
))
1267 save_digest_att(msgno
, a
);
1268 else if(MIME_VCARD_A(a
))
1269 save_vcard_att(ps_global
, qline
, msgno
, a
);
1271 write_attachment(qline
, msgno
, a
, "SAVE");
1275 /*----------------------------------------------------------------------
1276 Save the given attachment associated with the given message no
1283 export_attachment(int qline
, long int msgno
, ATTACH_S
*a
)
1285 if(ps_global
->restricted
){
1286 q_status_message(SM_ORDER
| SM_DING
, 0, 4,
1287 "Alpine demo can't export attachments");
1292 export_msg_att(msgno
, a
);
1293 else if(MIME_DGST_A(a
))
1294 export_digest_att(msgno
, a
);
1296 q_status_message1(SM_ORDER
, 0, 3,
1297 _("Can't Export %s. Use \"Save\" to write file, \"<\" to leave index."),
1298 body_type_names(a
->body
->type
));
1303 write_attachment(int qline
, long int msgno
, ATTACH_S
*a
, char *method
)
1305 char filename
[MAXPATH
+1], full_filename
[MAXPATH
+1],
1306 title_buf
[64], *err
;
1307 int r
, rflags
= GER_NONE
, we_cancel
= 0, flags
;
1308 static HISTORY_S
*history
= NULL
;
1309 static ESCKEY_S att_save_opts
[] = {
1310 {ctrl('T'), 10, "^T", N_("To Files")},
1311 {-1, 0, NULL
, NULL
},
1312 {-1, 0, NULL
, NULL
},
1313 {-1, 0, NULL
, NULL
}};
1315 /*------- Figure out suggested file name ----*/
1316 filename
[0] = full_filename
[0] = '\0';
1317 (void) get_filename_parameter(filename
, sizeof(filename
), a
->body
, NULL
);
1319 dprint((9, "export_attachment(name: %s)\n",
1320 filename
? filename
: "?"));
1323 #if !defined(DOS) && !defined(MAC) && !defined(OS2)
1324 if(ps_global
->VAR_DOWNLOAD_CMD
&& ps_global
->VAR_DOWNLOAD_CMD
[0]){
1325 att_save_opts
[++r
].ch
= ctrl('V');
1326 att_save_opts
[r
].rval
= 12;
1327 att_save_opts
[r
].name
= "^V";
1328 att_save_opts
[r
].label
= N_("Downld Msg");
1330 #endif /* !(DOS || MAC) */
1332 if(F_ON(F_ENABLE_TAB_COMPLETE
,ps_global
)){
1333 att_save_opts
[++r
].ch
= ctrl('I');
1334 att_save_opts
[r
].rval
= 11;
1335 att_save_opts
[r
].name
= "TAB";
1336 att_save_opts
[r
].label
= N_("Complete");
1339 att_save_opts
[++r
].ch
= -1;
1341 snprintf(title_buf
, sizeof(title_buf
), "%s ATTACHMENT", method
);
1342 title_buf
[sizeof(title_buf
)-1] = '\0';
1344 flags
= (a
&& a
->body
&& a
->body
->type
== TYPETEXT
? GE_BINARY
: 0)
1347 r
= get_export_filename(ps_global
, filename
, NULL
, full_filename
,
1348 sizeof(filename
), "attachment", title_buf
,
1349 att_save_opts
, &rflags
, qline
, flags
, &history
);
1354 cmd_cancelled((char *) lcase((unsigned char *) title_buf
+ 1) - 1);
1358 q_status_message1(SM_ORDER
, 0, 2,
1359 _("Can't save to file outside of %s"),
1360 ps_global
->VAR_OPER_DIR
);
1366 #if !defined(DOS) && !defined(MAC) && !defined(OS2)
1367 else if(r
== 12){ /* Download */
1368 char cmd
[MAXPATH
], *tfp
= NULL
;
1373 char prompt_buf
[256];
1375 if(ps_global
->restricted
){
1376 q_status_message(SM_ORDER
| SM_DING
, 3, 3,
1377 "Download disallowed in restricted mode");
1382 tfp
= temp_nam(NULL
, "pd");
1383 dprint((1, "Download attachment called!\n"));
1384 if((store
= so_get(FileStar
, tfp
, WRITE_ACCESS
|OWNER_ONLY
|WRITE_TO_LOCALE
)) != NULL
){
1386 snprintf(prompt_buf
, sizeof(prompt_buf
), "Saving to \"%s\"", tfp
);
1387 prompt_buf
[sizeof(prompt_buf
)-1] = '\0';
1388 we_cancel
= init_att_progress(prompt_buf
,
1389 ps_global
->mail_stream
,
1392 gf_set_so_writec(&pc
, store
);
1393 if((err
= detach(ps_global
->mail_stream
, msgno
,
1394 a
->number
, 0L, &len
, pc
, NULL
, 0)) != NULL
)
1395 q_status_message2(SM_ORDER
| SM_DING
, 3, 5,
1396 "%s: Error writing attachment to \"%s\"",
1399 /* cancel regardless, so it doesn't get in way of xfer */
1402 gf_clear_so_writec(store
);
1403 if(so_give(&store
)) /* close file */
1404 err
= "Error writing tempfile for download";
1407 build_updown_cmd(cmd
, sizeof(cmd
), ps_global
->VAR_DOWNLOAD_CMD_PREFIX
,
1408 ps_global
->VAR_DOWNLOAD_CMD
, tfp
);
1409 if((syspipe
= open_system_pipe(cmd
, NULL
, NULL
,
1410 PIPE_USER
| PIPE_RESET
,
1411 0, pipe_callback
, pipe_report_error
)) != NULL
)
1412 (void)close_system_pipe(&syspipe
, NULL
, pipe_callback
);
1414 q_status_message(SM_ORDER
| SM_DING
, 3, 3,
1415 err
= "Error running download command");
1419 q_status_message(SM_ORDER
| SM_DING
, 3, 3,
1420 err
= "Error building temp file for download");
1424 fs_give((void **)&tfp
);
1428 q_status_message1(SM_ORDER
, 0, 4, "Part %s downloaded",
1433 #endif /* !(DOS || MAC) */
1435 (void) write_attachment_to_file(ps_global
->mail_stream
, msgno
, a
,
1436 rflags
, full_filename
);
1442 * msgno -- raw message number
1443 * a -- attachment struct
1444 * flags -- comes from get_export_filename
1445 * GER_OVER -- the file was truncated before we wrote
1446 * GER_APPEND -- the file was not truncated prior to our writing,
1447 * so we were appending
1448 * else -- the file didn't previously exist
1449 * file -- the full pathname of the file
1451 * Returns 1 for successful write, 0 for nothing to write, -1 for error
1454 write_attachment_to_file(MAILSTREAM
*stream
, long int msgno
, ATTACH_S
*a
, int flags
, char *file
)
1456 char *l_string
, sbuf
[256], *err
;
1457 int is_text
, we_cancel
= 0, dt_flags
= 0, so_flags
;
1458 long len
, orig_size
;
1462 if(!(a
&& a
->body
&& a
->number
&& a
->number
[0] && file
&& file
[0]
1466 is_text
= (a
&& a
->body
&& a
->body
->type
== TYPETEXT
);
1468 if(flags
& GER_APPEND
)
1469 orig_size
= name_file_size(file
);
1471 if(flags
& GER_BINARY
)
1472 dt_flags
|= DT_BINARY
;
1474 so_flags
= (is_text
& !(flags
& GER_BINARY
) ? WRITE_TO_LOCALE
: 0)
1477 store
= so_get(FileStar
, file
, so_flags
);
1479 q_status_message2(SM_ORDER
| SM_DING
, 3, 5,
1480 /* TRANSLATORS: Error opening destination <filename>: <error text> */
1481 _("Error opening destination %s: %s"),
1482 file
, error_description(errno
));
1486 snprintf(sbuf
, sizeof(sbuf
), "Saving to \"%s\"", file
);
1487 sbuf
[sizeof(sbuf
)-1] = '\0';
1488 we_cancel
= init_att_progress(sbuf
, stream
, a
->body
);
1490 gf_set_so_writec(&pc
, store
);
1491 err
= detach(stream
, msgno
, a
->number
, 0L, &len
, pc
, NULL
, dt_flags
);
1492 gf_clear_so_writec(store
);
1497 if(so_give(&store
)) /* close file */
1498 err
= error_description(errno
);
1501 if(!(flags
& (GER_APPEND
| GER_OVER
)))
1504 our_truncate(file
, (flags
& GER_APPEND
) ? (off_t
) orig_size
: (off_t
) 0);
1506 q_status_message2(SM_ORDER
| SM_DING
, 3, 5,
1507 /* TRANSLATORS: <error text>: Error writing attachment to <filename> */
1508 _("%s: Error writing attachment to \"%s\""),
1513 l_string
= cpystr(byte_string(len
));
1514 q_status_message8(SM_ORDER
, 0, 4,
1515 "Part %s, %s%s %s to \"%s\"%s%s%s",
1518 ? comatose(a
->body
->size
.lines
) : l_string
,
1519 is_text
? " lines" : "",
1522 : flags
& GER_APPEND
? "appended" : "written",
1524 (is_text
|| len
== a
->body
->size
.bytes
)
1525 ? "" : "(decoded from ",
1526 (is_text
|| len
== a
->body
->size
.bytes
)
1527 ? "" : byte_string(a
->body
->size
.bytes
),
1528 is_text
|| len
== a
->body
->size
.bytes
1530 fs_give((void **)&l_string
);
1537 write_attached_msg(long int msgno
, ATTACH_S
**ap
, STORE_S
*store
, int newfile
)
1540 long start_of_append
;
1544 if(ap
&& *ap
&& (*ap
)->body
&& (*ap
)->body
->nested
.msg
1545 && (*ap
)->body
->nested
.msg
->env
){
1546 start_of_append
= so_tell(store
);
1548 gf_set_so_writec(&pc
, store
);
1549 if(!(ps_global
->mail_stream
&& msgno
> 0L
1550 && msgno
<= ps_global
->mail_stream
->nmsgs
1551 && (mc
= mail_elt(ps_global
->mail_stream
, msgno
)) && mc
->valid
))
1554 if(!bezerk_delimiter((*ap
)->body
->nested
.msg
->env
, mc
, pc
, newfile
)
1555 || !format_msg_att(msgno
, ap
, NULL
, pc
, FM_NOINDENT
))
1556 err
= error_description(errno
);
1558 gf_clear_so_writec(store
);
1561 ftruncate(fileno((FILE *)store
->txt
), (off_t
) start_of_append
);
1564 err
= "Can't export message. Missing Envelope data";
1570 /*----------------------------------------------------------------------
1571 Save the attachment message/rfc822 to specified folder
1578 save_msg_att(long int msgno
, ATTACH_S
*a
)
1580 char newfolder
[MAILTMPLEN
], *save_folder
, *flags
= NULL
;
1581 char date
[64], nmsgs
[80];
1582 CONTEXT_S
*cntxt
= NULL
;
1583 int our_stream
= 0, rv
;
1584 MAILSTREAM
*save_stream
;
1587 snprintf(nmsgs
, sizeof(nmsgs
), _("Attached Msg (part %s) "), a
->number
);
1588 nmsgs
[sizeof(nmsgs
)-1] = '\0';
1589 if(save_prompt(ps_global
, &cntxt
, newfolder
, sizeof(newfolder
), nmsgs
,
1590 a
->body
->nested
.msg
->env
, msgno
, a
->number
, NULL
, NULL
)){
1591 if(strucmp(newfolder
, ps_global
->inbox_name
) == 0){
1592 save_folder
= ps_global
->VAR_INBOX_PATH
;
1596 save_folder
= newfolder
;
1598 save_stream
= save_msg_stream(cntxt
, save_folder
, &our_stream
);
1600 mc
= (msgno
> 0L && ps_global
->mail_stream
1601 && msgno
<= ps_global
->mail_stream
->nmsgs
)
1602 ? mail_elt(ps_global
->mail_stream
, msgno
) : NULL
;
1603 flags
= flag_string(ps_global
->mail_stream
, msgno
, F_ANS
|F_FLAG
|F_SEEN
|F_KEYWORD
);
1605 mail_date(date
, mc
);
1609 if(pith_opt_save_size_changed_prompt
)
1610 (*pith_opt_save_size_changed_prompt
)(0L, SSCP_INIT
);
1612 rv
= save_msg_att_work(msgno
, a
, save_stream
, save_folder
, cntxt
, date
);
1614 if(pith_opt_save_size_changed_prompt
)
1615 (*pith_opt_save_size_changed_prompt
)(0L, SSCP_END
);
1618 fs_give((void **) &flags
);
1621 q_status_message2(SM_ORDER
, 0, 4,
1622 _("Attached message (part %s) saved to \"%s\""),
1626 cmd_cancelled("Attached message Save");
1627 /* else whatever broke in save_fetch_append shoulda bitched */
1630 mail_close(save_stream
);
1635 /*----------------------------------------------------------------------
1636 Save the message/rfc822 in the given digest to the specified folder
1643 save_digest_att(long int msgno
, ATTACH_S
*a
)
1645 char newfolder
[MAILTMPLEN
], *save_folder
,
1646 date
[64], nmsgs
[80];
1647 CONTEXT_S
*cntxt
= NULL
;
1648 int our_stream
= 0, rv
, cnt
= 0;
1649 MAILSTREAM
*save_stream
;
1654 && !strncmp(a
->number
, ap
->number
, strlen(a
->number
));
1656 if(MIME_MSG(ap
->body
->type
, ap
->body
->subtype
))
1659 snprintf(nmsgs
, sizeof(nmsgs
), "%d Msg Digest (part %s) ", cnt
, a
->number
);
1660 nmsgs
[sizeof(nmsgs
)-1] = '\0';
1662 if(save_prompt(ps_global
, &cntxt
, newfolder
, sizeof(newfolder
),
1663 nmsgs
, NULL
, 0, NULL
, NULL
, NULL
)){
1664 save_folder
= (strucmp(newfolder
, ps_global
->inbox_name
) == 0)
1665 ? ps_global
->VAR_INBOX_PATH
: newfolder
;
1667 save_stream
= save_msg_stream(cntxt
, save_folder
, &our_stream
);
1669 if(pith_opt_save_size_changed_prompt
)
1670 (*pith_opt_save_size_changed_prompt
)(0L, SSCP_INIT
);
1674 && !strncmp(a
->number
, ap
->number
, strlen(a
->number
));
1676 if(MIME_MSG(ap
->body
->type
, ap
->body
->subtype
)){
1678 rv
= save_msg_att_work(msgno
, ap
, save_stream
, save_folder
, cntxt
, date
);
1683 if(pith_opt_save_size_changed_prompt
)
1684 (*pith_opt_save_size_changed_prompt
)(0L, SSCP_END
);
1687 q_status_message2(SM_ORDER
, 0, 4,
1688 _("Attached digest (part %s) saved to \"%s\""),
1692 cmd_cancelled("Attached digest Save");
1693 /* else whatever broke in save_fetch_append shoulda bitched */
1696 mail_close(save_stream
);
1702 save_msg_att_work(long int msgno
, ATTACH_S
*a
, MAILSTREAM
*save_stream
,
1703 char *save_folder
, CONTEXT_S
*cntxt
, char *date
)
1708 if(a
&& a
->body
&& MIME_MSG(a
->body
->type
, a
->body
->subtype
)){
1709 if((so
= so_get(CharStar
, NULL
, WRITE_ACCESS
)) != NULL
){
1711 rv
= save_fetch_append(ps_global
->mail_stream
, msgno
,
1713 save_stream
, save_folder
, cntxt
,
1714 a
->body
->size
.bytes
,
1718 dprint((1, "Can't allocate store for save: %s\n",
1719 error_description(errno
)));
1720 q_status_message(SM_ORDER
| SM_DING
, 3, 4,
1721 _("Problem creating space for message text."));
1730 /*----------------------------------------------------------------------
1731 Export the attachment message/rfc822 to specified file
1738 export_msg_att(long int msgno
, ATTACH_S
*a
)
1740 char filename
[MAXPATH
+1], full_filename
[MAXPATH
+1], *err
;
1741 int rv
, rflags
= GER_NONE
, i
= 1;
1744 static HISTORY_S
*history
= NULL
;
1745 static ESCKEY_S opts
[] = {
1746 {ctrl('T'), 10, "^T", N_("To Files")},
1747 {-1, 0, NULL
, NULL
},
1748 {-1, 0, NULL
, NULL
}};
1750 if(F_ON(F_ENABLE_TAB_COMPLETE
,ps_global
)){
1751 opts
[i
].ch
= ctrl('I');
1753 opts
[i
].name
= "TAB";
1754 opts
[i
].label
= N_("Complete");
1757 filename
[0] = full_filename
[0] = '\0';
1759 rv
= get_export_filename(ps_global
, filename
, NULL
, full_filename
,
1760 sizeof(filename
), "msg attachment",
1761 /* TRANSLATORS: Message Attachment (a screen title) */
1762 _("MSG ATTACHMENT"), opts
,
1763 &rflags
, -FOOTER_ROWS(ps_global
),
1764 GE_IS_EXPORT
| GE_SEQ_SENSITIVE
, &history
);
1769 cmd_cancelled("Export");
1773 q_status_message1(SM_ORDER
, 0, 2,
1774 _("Can't export to file outside of %s"),
1775 ps_global
->VAR_OPER_DIR
);
1782 /* With name in hand, allocate storage object and save away... */
1783 if((store
= so_get(FileStar
, full_filename
, WRITE_ACCESS
)) != NULL
){
1784 if((err
= write_attached_msg(msgno
, &ap
, store
, !(rflags
& GER_APPEND
))) != NULL
)
1785 q_status_message(SM_ORDER
| SM_DING
, 3, 4, err
);
1787 q_status_message3(SM_ORDER
, 0, 4,
1788 _("Attached message (part %s) %s to \"%s\""),
1792 : rflags
& GER_APPEND
? _("appended") : _("written"),
1796 q_status_message2(SM_ORDER
| SM_DING
, 3, 4,
1797 _("Error writing %s: %s"),
1798 full_filename
, error_description(errno
));
1801 q_status_message2(SM_ORDER
| SM_DING
, 3, 4,
1802 /* TRANSLATORS: Error opening file <filename> to export message: <error text> */
1803 _("Error opening file \"%s\" to export message: %s"),
1804 full_filename
, error_description(errno
));
1808 /*----------------------------------------------------------------------
1809 Export the message/rfc822 in the given digest to the specified file
1816 export_digest_att(long int msgno
, ATTACH_S
*a
)
1818 char filename
[MAXPATH
+1], full_filename
[MAXPATH
+1], *err
= NULL
;
1819 int rv
, rflags
= GER_NONE
, i
= 1;
1822 static HISTORY_S
*history
= NULL
;
1824 static ESCKEY_S opts
[] = {
1825 {ctrl('T'), 10, "^T", N_("To Files")},
1826 {-1, 0, NULL
, NULL
},
1827 {-1, 0, NULL
, NULL
}};
1829 if(F_ON(F_ENABLE_TAB_COMPLETE
,ps_global
)){
1830 opts
[i
].ch
= ctrl('I');
1832 opts
[i
].name
= "TAB";
1833 opts
[i
].label
= N_("Complete");
1836 filename
[0] = full_filename
[0] = '\0';
1838 rv
= get_export_filename(ps_global
, filename
, NULL
, full_filename
,
1839 sizeof(filename
), "digest", _("DIGEST ATTACHMENT"),
1840 opts
, &rflags
, -FOOTER_ROWS(ps_global
),
1841 GE_IS_EXPORT
| GE_SEQ_SENSITIVE
, &history
);
1846 cmd_cancelled("Export");
1850 q_status_message1(SM_ORDER
, 0, 2,
1851 _("Can't export to file outside of %s"),
1852 ps_global
->VAR_OPER_DIR
);
1859 /* With name in hand, allocate storage object and save away... */
1860 if((store
= so_get(FileStar
, full_filename
, WRITE_ACCESS
)) != NULL
){
1865 && !strncmp(a
->number
, ap
->number
, strlen(a
->number
))
1868 if(MIME_MSG(ap
->body
->type
, ap
->body
->subtype
)){
1870 err
= write_attached_msg(msgno
, &ap
, store
,
1871 !count
&& !(rflags
& GER_APPEND
));
1876 err
= error_description(errno
);
1879 q_status_message1(SM_ORDER
| SM_DING
, 3, 3,
1880 _("Error exporting: %s"), err
);
1881 q_status_message1(SM_ORDER
| SM_DING
, 3, 3,
1882 _("%s messages exported before error occurred"), err
);
1885 q_status_message4(SM_ORDER
, 0, 4,
1886 "%s messages in digest (part %s) %s to \"%s\"",
1891 : rflags
& GER_APPEND
? "appended" : "written",
1895 q_status_message2(SM_ORDER
| SM_DING
, 3, 4,
1896 _("Error opening file \"%s\" to export digest: %s"),
1897 full_filename
, error_description(errno
));
1901 /*----------------------------------------------------------------------
1902 Print the given attachment associated with the given message no
1909 print_attachment(int qline
, long int msgno
, ATTACH_S
*a
)
1913 if(ps_global
->restricted
){
1914 q_status_message(SM_ORDER
| SM_DING
, 0, 4,
1915 "Alpine demo can't Print attachments");
1919 snprintf(prompt
, sizeof(prompt
), "attach%s %s",
1920 (a
->body
->type
== TYPETEXT
) ? "ment" : "ed message",
1921 MIME_DGST_A(a
) ? "digest" : a
->number
);
1922 prompt
[sizeof(prompt
)-1] = '\0';
1923 if(open_printer(prompt
) >= 0){
1925 (void) print_msg_att(msgno
, a
, 1);
1926 else if(MIME_DGST_A(a
))
1927 print_digest_att(msgno
, a
);
1929 (void) decode_text(a
, msgno
, print_char
, NULL
, QStatus
, FM_NOINDENT
);
1937 * Print the attachment message/rfc822 to specified file
1939 * Returns 1 on success, 0 on failure.
1942 print_msg_att(long int msgno
, ATTACH_S
*a
, int first
)
1947 if(!(ps_global
->mail_stream
&& msgno
> 0L
1948 && msgno
<= ps_global
->mail_stream
->nmsgs
1949 && (mc
= mail_elt(ps_global
->mail_stream
, msgno
)) && mc
->valid
))
1952 if(((!first
&& F_ON(F_AGG_PRINT_FF
, ps_global
)) ? print_char(FORMFEED
) : 1)
1953 && pine_mail_fetchstructure(ps_global
->mail_stream
, msgno
, NULL
)
1954 && (F_ON(F_FROM_DELIM_IN_PRINT
, ps_global
)
1955 ? bezerk_delimiter(a
->body
->nested
.msg
->env
, mc
, print_char
, !first
)
1957 && format_msg_att(msgno
, &ap
, NULL
, print_char
, FM_NOINDENT
))
1961 q_status_message2(SM_ORDER
| SM_DING
, 3, 3,
1962 _("Error printing message %s, part %s"),
1963 long2string(msgno
), a
->number
);
1968 /*----------------------------------------------------------------------
1969 Print the attachment message/rfc822 to specified file
1976 print_digest_att(long int msgno
, ATTACH_S
*a
)
1983 && !strncmp(a
->number
, ap
->number
, strlen(a
->number
));
1985 if(MIME_MSG(ap
->body
->type
, ap
->body
->subtype
)){
1986 char *p
= part_desc(ap
->number
, ap
->body
->nested
.msg
->body
,
1987 0, 80, FM_NOINDENT
, print_char
);
1989 q_status_message1(SM_ORDER
| SM_DING
, 3, 3,
1990 _("Can't print digest: %s"), p
);
1993 else if(!print_msg_att(msgno
, ap
, !next
))
2002 display_html_external_attachment(long int msgno
, ATTACH_S
*a
, int flags
)
2004 char dir_path
[MAXPATH
+1];
2005 char *filename
= NULL
;
2006 char *file_path
; /* file:///some/path/ */
2010 int we_cancel
= 0, saved
, errs
;
2013 unsigned long rawno
;
2015 if(a
->body
== NULL
){
2016 q_status_message(SM_ORDER
| SM_DING
, 3, 5, _("Attachment has no body!"));
2018 } else if (a
->body
->type
!= TYPETEXT
2019 || a
->body
->subtype
== NULL
2020 || strucmp(a
->body
->subtype
, "HTML")){
2021 q_status_message(SM_ORDER
| SM_DING
, 3, 5, _("Not a TEXT/HTML attachment"));
2025 /* zero these variables, just in case. Do not try freeing them. They have short lives */
2026 for(att
= ps_global
->atmts
; att
->description
!= NULL
; att
++){
2027 att
->cid_tmpfile
= NULL
;
2031 /* setup the environment first */
2032 if(!ps_global
->html_dir
){
2033 if(!html_directory_path(ps_global
->VAR_HTML_DIRECTORY
, dir_path
, MAXPATH
)){
2034 q_status_message1(SM_ORDER
| SM_DING
, 3, 5,
2035 _("Error creating full path for %s"), ps_global
->VAR_HTML_DIRECTORY
);
2037 } else if (init_html_directory(dir_path
) < 0){
2038 q_status_message1(SM_ORDER
| SM_DING
, 3, 5, _("Error initializing %s"), dir_path
);
2041 ps_global
->html_dir
= cpystr(dir_path
);
2044 strncpy(dir_path
, ps_global
->html_dir
, sizeof(dir_path
));
2045 dir_path
[sizeof(dir_path
)-1] = '\0';
2048 if(create_random_dir(dir_path
, sizeof(dir_path
)) < 0){
2049 q_status_message1(SM_ORDER
| SM_DING
, 3, 5, _("Error creating temp dir in %s"), dir_path
);
2053 a
->tmpdir
= cpystr(dir_path
);
2054 add_html_log(&ps_global
->html_dir_list
, a
->tmpdir
);
2056 /* Process the text/html part */
2057 filename
= temp_nam_ext(a
->tmpdir
, "tmp-html-", HTML_EXT
);
2060 q_status_message1(SM_ORDER
| SM_DING
, 3, 5,
2061 _("Error \"%s\", Can't create temporary file"),
2062 error_description(errno
));
2066 if((store
= so_get(FileStar
, filename
, WRITE_ACCESS
|OWNER_ONLY
)) == NULL
){
2067 q_status_message2(SM_ORDER
| SM_DING
, 3, 5,
2068 _("Error \"%s\", Can't write file %s"),
2069 error_description(errno
), filename
);
2071 our_unlink(filename
);
2072 fs_give((void **)&filename
);
2077 if(a
->body
->size
.bytes
){
2080 snprintf(msg_buf
, sizeof(msg_buf
), "Decoding %s%s%s%s",
2081 a
->description
? "\"" : "",
2082 a
->description
? a
->description
: "attachment number ",
2083 a
->description
? "" : a
->number
,
2084 a
->description
? "\"" : "");
2085 msg_buf
[sizeof(msg_buf
)-1] = '\0';
2086 we_cancel
= init_att_progress(msg_buf
, ps_global
->mail_stream
, a
->body
);
2089 gf_set_so_writec(&pc
, store
);
2091 err
= detach(ps_global
->mail_stream
, msgno
, a
->number
, 0L, NULL
, pc
, NULL
,
2092 DT_EXTERNAL
| ((flags
& DA_ALLIMAGES
) ? DT_ALLIMAGES
: 0));
2094 gf_clear_so_writec(store
);
2101 /*----- Download all needed inline attachments ------*/
2103 rawno
= mn_m2raw(ps_global
->msgmap
, msgno
);
2104 for (att
= ps_global
->atmts
; rawno
> 0 && att
->description
!= NULL
; att
++){
2105 if(att
->cid_tmpfile
){
2106 if(write_attachment_to_file(ps_global
->mail_stream
, rawno
,
2107 att
, GER_NONE
, att
->cid_tmpfile
) == 1)
2111 fs_give((void **) &att
->cid_tmpfile
);
2114 fs_give((void **) &att
->tmpdir
);
2118 q_status_message2(SM_ORDER
| SM_DING
, 3, 5,
2119 "%s: Error saving image to temp file %s",
2122 our_unlink(filename
);
2123 fs_give((void **)&filename
);
2128 tool
= get_url_external_handler("http://", 1);
2129 if(tool
== NULL
) tool
= get_url_external_handler("http://", 0);
2130 if(tool
== NULL
) tool
= get_url_external_handler("https://", 1);
2131 if(tool
== NULL
) tool
= get_url_external_handler("https://", 0);
2133 file_path
= fs_get((strlen(filename
) + strlen("file://") + 1)*sizeof(char));
2134 sprintf(file_path
, "file://%s", filename
);
2136 /*----- Run the viewer process ----*/
2137 if(do_url_launch(tool
, file_path
) == 0)
2138 q_status_message(SM_ORDER
, 3, 3, "Opened message in external browser");
2140 q_status_message(SM_ORDER
|SM_DING
, 3, 5, "Failed to open message in external browser");
2143 fs_give((void **)&filename
);
2146 fs_give((void **)&file_path
);
2148 ps_global
->mangled_screen
= 1;
2154 /*----------------------------------------------------------------------
2155 Unpack and display the given attachment associated with given message no.
2157 Args: msgno -- message no attachment is part of
2158 a -- attachment to display
2160 Returns: 0 on success, non-zero (and error message queued) otherwise
2163 display_attachment(long int msgno
, ATTACH_S
*a
, int flags
)
2165 char *filename
= NULL
;
2166 char sender_filename
[1000];
2171 int we_cancel
= 0, rv
;
2176 if(flags
& DA_EXTERNAL
)
2177 return display_html_external_attachment(msgno
, a
, flags
);
2179 /*------- Display the attachment -------*/
2180 if(dispatch_attachment(a
) == MCD_NONE
){
2181 /*----- Can't display this type ------*/
2182 if(a
->body
->encoding
< ENCOTHER
)
2183 q_status_message4(SM_ORDER
| SM_DING
, 3, 5,
2184 /* TRANSLATORS: Don't know how to display <certain type> attachments. <might say Try Save.> */
2185 _("Don't know how to display %s%s%s attachments.%s"),
2186 body_type_names(a
->body
->type
),
2187 a
->body
->subtype
? "/" : "",
2188 a
->body
->subtype
? a
->body
->subtype
:"",
2189 (flags
& DA_SAVE
) ? _(" Try Save.") : "");
2191 q_status_message1(SM_ORDER
| SM_DING
, 3, 5,
2192 _("Don't know how to unpack \"%s\" encoding"),
2193 body_encodings
[(a
->body
->encoding
<= ENCMAX
)
2194 ? a
->body
->encoding
: ENCOTHER
]);
2198 else if(!(a
->can_display
& MCD_EXTERNAL
)){
2199 if(a
->body
->type
== TYPEMULTIPART
){
2200 if(a
->body
->subtype
){
2201 if(!strucmp(a
->body
->subtype
, "digest"))
2202 display_digest_att(msgno
, a
, flags
);
2204 q_status_message1(SM_ORDER
, 3, 5,
2205 _("Can't display Multipart/%s"),
2209 q_status_message(SM_ORDER
, 3, 5,
2210 _("Can't display unknown Multipart Subtype"));
2212 else if(MIME_VCARD_A(a
))
2213 display_vcard_att(msgno
, a
, flags
);
2214 else if( MIME_VCALENDAR(a
->body
->type
, a
->body
->subtype
))
2215 display_vcalendar_att(msgno
, a
, flags
);
2216 else if(a
->body
->type
== TYPETEXT
){
2218 rv
= display_text_att(msgno
, a
, flags
);
2219 } while(rv
== MC_FULLHDR
);
2221 else if(a
->body
->type
== TYPEMESSAGE
){
2223 rv
= display_msg_att(msgno
, a
, flags
);
2224 } while(rv
== MC_FULLHDR
);
2227 ps_global
->mangled_screen
= 1;
2231 /* arrive here if MCD_EXTERNAL */
2233 if(F_OFF(F_QUELL_ATTACH_EXTRA_PROMPT
, ps_global
)
2234 && (!(flags
& DA_DIDPROMPT
)))
2235 if(want_to(_("View selected Attachment"), 'y',
2236 0, NO_HELP
, WT_NORM
) == 'n'){
2237 cmd_cancelled(NULL
);
2241 sender_filename
[0] = '\0';
2245 if(F_OFF(F_QUELL_ATTACH_EXT_WARN
, ps_global
)
2246 && (a
->can_display
& MCD_EXT_PROMPT
)){
2249 (void) get_filename_parameter(sender_filename
, sizeof(sender_filename
),
2251 snprintf(prompt
, sizeof(prompt
),
2252 "Attachment %s%s unrecognized. %s%s%s",
2254 strlen(a
->body
->subtype
) > 12 ? "..." : "",
2255 (extp
&& extp
[0]) ? "Try open by file extension (." : "Try opening anyway",
2256 (extp
&& extp
[0]) ? extp
: "",
2257 (extp
&& extp
[0]) ? ")" : "");
2259 if(want_to(prompt
, 'n', 0, NO_HELP
, WT_NORM
) == 'n'){
2260 cmd_cancelled(NULL
);
2265 /*------ Write the image to a temporary file ------*/
2267 /* create type/subtype in mtype */
2268 strncpy(mtype
, body_type_names(a
->body
->type
), sizeof(mtype
));
2269 mtype
[sizeof(mtype
)-1] = '\0';
2270 if(a
->body
->subtype
){
2271 strncat(mtype
, "/", sizeof(mtype
)-strlen(mtype
)-1);
2272 mtype
[sizeof(mtype
)-1] = '\0';
2273 strncat(mtype
, a
->body
->subtype
, sizeof(mtype
)-strlen(mtype
)-1);
2274 mtype
[sizeof(mtype
)-1] = '\0';
2278 * If we haven't already gotten the filename parameter, get it
2279 * now. It may be used in the temporary filename and possibly
2280 * for its extension.
2282 if(!sender_filename
[0])
2283 (void) get_filename_parameter(sender_filename
, sizeof(sender_filename
),
2286 if(check_mime_type_by_extension(extp
, mtype
)
2287 || (!set_mime_extension_by_type(ext
, mtype
) /* extension from type */
2288 && extp
&& extp
[0])){ /* extension from filename */
2289 strncpy(ext
, extp
, sizeof(ext
));
2290 ext
[sizeof(ext
)-1] = '\0';
2293 /* create a temp file */
2294 if(sender_filename
){
2297 /* get rid of any extension */
2298 if(mt_get_file_ext(sender_filename
, &q
) && q
&& q
> sender_filename
)
2301 /* be careful about what is allowed in the filename */
2302 for(p
= sender_filename
; *p
; p
++)
2303 if(!(isascii((unsigned char) *p
)
2304 && (isalnum((unsigned char) *p
)
2305 || *p
== '-' || *p
== '_' || *p
== '+' || *p
== '.' || *p
== '=')))
2308 if(!*p
) /* filename was ok to use */
2309 snprintf(prefix
, sizeof(prefix
), "img-%s-", sender_filename
);
2312 /* didn't get it yet */
2314 snprintf(prefix
, sizeof(prefix
), "img-%s-", (a
->body
->subtype
)
2315 ? a
->body
->subtype
: "unk");
2318 /* We are creating a temporary name. This is just a prefix. If you
2319 * need the original name, use the save command, so if the prefix
2320 * is too long, shorten it.
2322 if (strlen(prefix
) > 9){
2327 filename
= temp_nam_ext(NULL
, prefix
, ext
);
2330 q_status_message1(SM_ORDER
| SM_DING
, 3, 5,
2331 _("Error \"%s\", Can't create temporary file"),
2332 error_description(errno
));
2336 if((store
= so_get(FileStar
, filename
, WRITE_ACCESS
|OWNER_ONLY
)) == NULL
){
2337 q_status_message2(SM_ORDER
| SM_DING
, 3, 5,
2338 _("Error \"%s\", Can't write file %s"),
2339 error_description(errno
), filename
);
2341 our_unlink(filename
);
2342 fs_give((void **)&filename
);
2349 if(a
->body
->size
.bytes
){
2352 snprintf(msg_buf
, sizeof(msg_buf
), "Decoding %s%s%s%s",
2353 a
->description
? "\"" : "",
2354 a
->description
? a
->description
: "attachment number ",
2355 a
->description
? "" : a
->number
,
2356 a
->description
? "\"" : "");
2357 msg_buf
[sizeof(msg_buf
)-1] = '\0';
2358 we_cancel
= init_att_progress(msg_buf
, ps_global
->mail_stream
,
2362 if(a
->body
->type
== TYPEMULTIPART
){
2363 char *h
= mail_fetch_mime(ps_global
->mail_stream
, msgno
, a
->number
,
2366 /* Write to store while converting newlines */
2368 if(*h
== '\015' && *(h
+1) == '\012'){
2369 so_puts(store
, NEWLINE
);
2373 so_writec(*h
++, store
);
2376 gf_set_so_writec(&pc
, store
);
2378 err
= detach(ps_global
->mail_stream
, msgno
, a
->number
, 0L, NULL
, pc
, NULL
, 0);
2380 gf_clear_so_writec(store
);
2388 q_status_message2(SM_ORDER
| SM_DING
, 3, 5,
2389 "%s: Error saving image to temp file %s",
2392 our_unlink(filename
);
2393 fs_give((void **)&filename
);
2399 /*----- Run the viewer process ----*/
2400 run_viewer(filename
, a
->body
, a
->can_display
& MCD_EXT_PROMPT
);
2402 fs_give((void **)&filename
);
2408 /*----------------------------------------------------------------------
2409 Fish the required command from mailcap and run it
2411 Args: image_file -- The name of the file to pass viewer
2412 body -- body struct containing type/subtype of part
2414 A side effect may be that scrolltool is called as well if
2415 exec_mailcap_cmd has any substantial output...
2418 run_viewer(char *image_file
, struct mail_bodystruct
*body
, int chk_extension
)
2420 MCAP_CMD_S
*mc_cmd
= NULL
;
2421 int needs_terminal
= 0, we_cancel
= 0;
2423 we_cancel
= busy_cue("Displaying attachment", NULL
, 0);
2425 if((mc_cmd
= mailcap_build_command(body
->type
, body
->subtype
,
2427 &needs_terminal
, chk_extension
)) != NULL
){
2429 cancel_busy_cue(-1);
2431 exec_mailcap_cmd(mc_cmd
, image_file
, needs_terminal
);
2433 fs_give((void **)&mc_cmd
->command
);
2434 fs_give((void **)&mc_cmd
);
2438 cancel_busy_cue(-1);
2440 q_status_message1(SM_ORDER
, 3, 4, _("Cannot display %s attachment"),
2441 type_desc(body
->type
, body
->subtype
,
2442 body
->parameter
, NULL
, 1));
2447 /*----------------------------------------------------------------------
2448 Detach and provide for browsing a text body part
2450 Args: msgno -- raw message number to get part from
2451 a -- attachment struct for the desired part
2456 format_text_att(long int msgno
, ATTACH_S
*a
, HANDLE_S
**handlesp
)
2461 if((store
= so_get(CharStar
, NULL
, EDIT_ACCESS
)) != NULL
){
2463 init_handles(handlesp
);
2465 gf_set_so_writec(&pc
, store
);
2466 (void) decode_text(a
, msgno
, pc
, handlesp
, QStatus
, FM_DISPLAY
);
2467 gf_clear_so_writec(store
);
2474 /*----------------------------------------------------------------------
2475 Detach and provide for browsing a text body part
2477 Args: msgno -- raw message number to get part from
2478 a -- attachment struct for the desired part
2483 display_text_att(long int msgno
, ATTACH_S
*a
, int flags
)
2486 HANDLE_S
*handles
= NULL
;
2490 clear_index_cache_ent(ps_global
->mail_stream
, msgno
, 0);
2492 if((store
= format_text_att(msgno
, a
, &handles
)) != NULL
){
2493 rv
= scroll_attachment("ATTACHED TEXT", store
, CharStar
, handles
, a
, flags
);
2494 free_handles(&handles
);
2495 so_give(&store
); /* free resources associated with store */
2498 q_status_message(SM_ORDER
| SM_DING
, 3, 3,
2499 _("Error allocating space for attachment."));
2505 /*----------------------------------------------------------------------
2506 Detach and provide for browsing a body part of type "MESSAGE"
2508 Args: msgno -- message number to get partrom
2509 a -- attachment struct for the desired part
2514 display_msg_att(long int msgno
, ATTACH_S
*a
, int flags
)
2519 HANDLE_S
*handles
= NULL
;
2523 clear_index_cache_ent(ps_global
->mail_stream
, msgno
, 0);
2525 /* BUG, should check this return code */
2526 (void) pine_mail_fetchstructure(ps_global
->mail_stream
, msgno
, NULL
);
2528 /* initialize a storage object */
2529 if(!(store
= so_get(CharStar
, NULL
, EDIT_ACCESS
))){
2530 q_status_message(SM_ORDER
| SM_DING
, 3, 3,
2531 _("Error allocating space for message."));
2535 gf_set_so_writec(&pc
, store
);
2537 if(format_msg_att(msgno
, &ap
, &handles
, pc
, FM_DISPLAY
)){
2538 if(ps_global
->full_header
== 2)
2539 q_status_message(SM_INFO
, 0, 3,
2540 _("Full header mode ON. All header text being included"));
2542 rv
= scroll_attachment((a
->body
->subtype
2543 && !strucmp(a
->body
->subtype
, "delivery-status"))
2544 ? "DELIVERY STATUS REPORT" : "ATTACHED MESSAGE",
2545 store
, CharStar
, handles
, a
, flags
);
2546 free_handles(&handles
);
2549 gf_clear_so_writec(store
);
2551 so_give(&store
); /* free resources associated with store */
2556 /*----------------------------------------------------------------------
2557 Detach and provide for browsing a multipart body part of type "DIGEST"
2559 Args: msgno -- message number to get partrom
2560 a -- attachment struct for the desired part
2565 display_digest_att(long int msgno
, ATTACH_S
*a
, int flags
)
2569 HANDLE_S
*handles
= NULL
;
2571 SourceType src
= CharStar
;
2575 clear_index_cache_ent(ps_global
->mail_stream
, msgno
, 0);
2577 /* BUG, should check this return code */
2578 (void) pine_mail_fetchstructure(ps_global
->mail_stream
, msgno
, NULL
);
2580 if(!(store
= so_get(src
, NULL
, EDIT_ACCESS
))){
2581 q_status_message(SM_ORDER
| SM_DING
, 3, 3,
2582 _("Error allocating space for message."));
2586 gf_set_so_writec(&pc
, store
);
2589 * While in a subtype of this message
2593 && !strncmp(a
->number
, ap
->number
, strlen(a
->number
))
2596 if(ap
->body
->type
== TYPEMESSAGE
){
2599 if(ap
->body
->subtype
&& strucmp(ap
->body
->subtype
, "rfc822")){
2602 tsub
= cpystr(ap
->body
->subtype
);
2603 convert_possibly_encoded_str_to_utf8((char **) &tsub
);
2604 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, "Unknown Message subtype: %s", tsub
);
2605 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
2607 if((errstr
= format_editorial(tmp_20k_buf
,
2608 ps_global
->ttyo
->screen_cols
, 0,
2609 NULL
, pc
)) != NULL
){
2610 q_status_message1(SM_ORDER
| SM_DING
, 3, 3,
2611 _("Can't format digest: %s"), errstr
);
2614 else if(!gf_puts(NEWLINE
, pc
))
2617 fs_give((void **) &tsub
);
2620 if((errstr
= part_desc(ap
->number
, ap
->body
->nested
.msg
->body
,
2621 0, ps_global
->ttyo
->screen_cols
, FM_DISPLAY
, pc
)) != NULL
){
2622 q_status_message1(SM_ORDER
| SM_DING
, 3, 3,
2623 _("Can't format digest: %s"), errstr
);
2626 else if(!format_msg_att(msgno
, &ap
, &handles
, pc
, FM_DISPLAY
))
2630 else if(ap
->body
->type
== TYPETEXT
2631 && decode_text(ap
, msgno
, pc
, NULL
, QStatus
, FM_DISPLAY
))
2633 else if(!gf_puts("Unknown type in Digest", pc
))
2638 if(ps_global
->full_header
== 2)
2639 q_status_message(SM_INFO
, 0, 3,
2640 _("Full header mode ON. All header text being included"));
2642 scroll_attachment(_("ATTACHED MESSAGES"), store
, src
, handles
, a
, flags
);
2645 free_handles(&handles
);
2647 gf_clear_so_writec(store
);
2648 so_give(&store
); /* free resources associated with store */
2653 scroll_attachment(char *title
, STORE_S
*store
, SourceType src
, HANDLE_S
*handles
, ATTACH_S
*a
, int flags
)
2657 memset(&sargs
, 0, sizeof(SCROLL_S
));
2658 sargs
.text
.text
= so_text(store
);
2659 sargs
.text
.src
= src
;
2660 sargs
.text
.desc
= "attachment";
2661 sargs
.text
.handles
= handles
;
2662 sargs
.bar
.title
= title
;
2663 sargs
.proc
.tool
= process_attachment_cmd
;
2664 sargs
.proc
.data
.p
= (void *) a
;
2665 sargs
.help
.text
= h_mail_text_att_view
;
2666 sargs
.help
.title
= _("HELP FOR ATTACHED TEXT VIEW");
2667 sargs
.keys
.menu
= &att_view_keymenu
;
2668 setbitmap(sargs
.keys
.bitmap
);
2670 /* First, fix up "back" key */
2671 if(flags
& DA_FROM_VIEW
){
2672 att_view_keymenu
.keys
[ATV_BACK_KEY
].label
= N_("MsgText");
2675 att_view_keymenu
.keys
[ATV_BACK_KEY
].label
= N_("AttchIndex");
2679 clrbitn(ATV_VIEW_HILITE
, sargs
.keys
.bitmap
);
2680 clrbitn(ATV_PREV_URL
, sargs
.keys
.bitmap
);
2681 clrbitn(ATV_NEXT_URL
, sargs
.keys
.bitmap
);
2684 if(F_OFF(F_ENABLE_PIPE
, ps_global
))
2685 clrbitn(ATV_PIPE_KEY
, sargs
.keys
.bitmap
);
2687 if(!(a
->body
->type
== TYPETEXT
|| MIME_MSG_A(a
) || MIME_DGST_A(a
)))
2688 clrbitn(ATV_PRINT_KEY
, sargs
.keys
.bitmap
);
2691 * If message or digest, leave Reply and Save and,
2692 * conditionally, Bounce on...
2695 if(F_OFF(F_ENABLE_BOUNCE
, ps_global
))
2696 clrbitn(ATV_BOUNCE_KEY
, sargs
.keys
.bitmap
);
2699 clrbitn(ATV_BOUNCE_KEY
, sargs
.keys
.bitmap
);
2700 clrbitn(ATV_REPLY_KEY
, sargs
.keys
.bitmap
);
2701 clrbitn(ATV_EXPORT_KEY
, sargs
.keys
.bitmap
);
2704 if(!(ps_global
->smime
&& ps_global
->smime
->need_passphrase
))
2705 clrbitn(ATV_DECRYPT_KEY
, sargs
.keys
.bitmap
);
2707 if(F_ON(F_DONT_DO_SMIME
, ps_global
) || !MIME_MSG_A(a
)){
2708 clrbitn(ATV_DECRYPT_KEY
, sargs
.keys
.bitmap
);
2709 clrbitn(ATV_SECURITY_KEY
, sargs
.keys
.bitmap
);
2713 sargs
.use_indexline_color
= 1;
2715 if(DA_RESIZE
& flags
)
2716 sargs
.resize_exit
= 1;
2720 sargs
.mouse
.popup
= scroll_att_popup
;
2723 return(scrolltool(&sargs
));
2728 display_smime_info_att(struct pine
*ps
, ATTACH_S
*a
)
2730 if(smime_check(a
->body
->nested
.msg
->body
) == 0){
2731 q_status_message(SM_ORDER
| SM_DING
, 0, 3,
2732 _("Not a signed or encrypted message"));
2736 display_smime_info(ps
, a
->body
->nested
.msg
->env
, a
->body
->nested
.msg
->body
);
2741 process_attachment_cmd(int cmd
, MSGNO_S
*msgmap
, SCROLL_S
*sparms
)
2744 long rawno
= mn_m2raw(msgmap
, mn_get_cur(msgmap
));
2745 #define AD(X) ((ATTACH_S *) (X)->proc.data.p)
2753 ps_global
->next_screen
= quit_screen
;
2757 ps_global
->next_screen
= main_menu_screen
;
2761 reply_msg_att(ps_global
->mail_stream
, rawno
, sparms
->proc
.data
.p
);
2765 forward_attachment(ps_global
->mail_stream
, rawno
, sparms
->proc
.data
.p
);
2769 bounce_msg_att(ps_global
->mail_stream
, rawno
, AD(sparms
)->number
,
2770 AD(sparms
)->body
->nested
.msg
->env
->subject
);
2771 ps_global
->mangled_footer
= 1;
2775 delete_attachment(rawno
, sparms
->proc
.data
.p
);
2779 if(undelete_attachment(rawno
, sparms
->proc
.data
.p
, &n
))
2780 q_status_message1(SM_ORDER
, 0, 3,
2781 "Part %s UNdeleted", AD(sparms
)->number
);
2786 save_attachment(-FOOTER_ROWS(ps_global
), rawno
, sparms
->proc
.data
.p
);
2787 ps_global
->mangled_footer
= 1;
2791 export_attachment(-FOOTER_ROWS(ps_global
), rawno
, sparms
->proc
.data
.p
);
2792 ps_global
->mangled_footer
= 1;
2796 print_attachment(-FOOTER_ROWS(ps_global
), rawno
, sparms
->proc
.data
.p
);
2797 ps_global
->mangled_footer
= 1;
2801 pipe_attachment(rawno
, sparms
->proc
.data
.p
);
2802 ps_global
->mangled_footer
= 1;
2806 ps_global
->full_header
++;
2807 if(ps_global
->full_header
== 1){
2808 if(!(ps_global
->quote_suppression_threshold
2809 && (ps_global
->some_quoting_was_suppressed
/* || in_index != View*/)))
2810 ps_global
->full_header
++;
2812 else if(ps_global
->full_header
> 2)
2813 ps_global
->full_header
= 0;
2815 switch(ps_global
->full_header
){
2817 q_status_message(SM_ORDER
, 0, 3,
2818 _("Display of full headers is now off."));
2822 q_status_message1(SM_ORDER
, 0, 3,
2823 _("Quotes displayed, use %s to see full headers"),
2824 F_ON(F_USE_FK
, ps_global
) ? "F9" : "H");
2828 q_status_message(SM_ORDER
, 0, 3,
2829 _("Display of full headers is now on."));
2839 if(ps_global
->smime
&& ps_global
->smime
->need_passphrase
)
2840 smime_get_passphrase();
2844 display_smime_info_att(ps_global
, sparms
->proc
.data
.p
);
2849 alpine_panic("Unexpected command case");
2858 * Returns 1 on success, 0 on error.
2861 format_msg_att(long int msgno
, ATTACH_S
**a
, HANDLE_S
**handlesp
, gf_io_t pc
, int flags
)
2865 if((*a
)->body
->type
!= TYPEMESSAGE
)
2866 return(gf_puts("[ Undisplayed Attachment of Type ", pc
)
2867 && gf_puts(body_type_names((*a
)->body
->type
), pc
)
2868 && gf_puts(" ]", pc
) && gf_puts(NEWLINE
, pc
));
2870 if((*a
)->body
->subtype
&& strucmp((*a
)->body
->subtype
, "rfc822") == 0){
2873 HD_INIT(&h
, ps_global
->VAR_VIEW_HEADERS
, ps_global
->view_all_except
,
2875 switch(format_header(ps_global
->mail_stream
, msgno
, (*a
)->number
,
2876 (*a
)->body
->nested
.msg
->env
, &h
, NULL
, NULL
,
2878 case -1 : /* write error */
2881 case 1 : /* fetch error */
2882 if(!(gf_puts("[ Error fetching header ]", pc
)
2883 && !gf_puts(NEWLINE
, pc
)))
2889 gf_puts(NEWLINE
, pc
);
2891 if(((*a
)+1)->description
)
2894 if(!(gf_puts("[Can't display missing text segment]", pc
)
2895 && gf_puts(NEWLINE
, pc
)))
2901 if((*a
)->body
&& (*a
)->body
->subtype
&& (strucmp((*a
)->body
->subtype
, OUR_PKCS7_ENCLOSURE_SUBTYPE
)==0)){
2902 if((*a
)->description
){
2903 if(!(!format_editorial((*a
)->description
,
2904 ps_global
->ttyo
->screen_cols
,
2906 && gf_puts(NEWLINE
, pc
) && gf_puts(NEWLINE
, pc
)))
2910 if(((*a
)+1)->description
)
2913 if(!(gf_puts("[Can't display missing text segment]", pc
)
2914 && gf_puts(NEWLINE
, pc
)))
2921 if(((*a
))->description
2922 && (*a
)->body
&& (*a
)->body
->type
== TYPETEXT
){
2923 if(decode_text(*a
, msgno
, pc
, NULL
, QStatus
, flags
))
2926 else if(!(gf_puts("[Can't display ", pc
)
2927 && gf_puts(((*a
)->description
&& (*a
)->body
)
2928 ? "first non-" : "missing ", pc
)
2929 && gf_puts("text segment]", pc
)
2930 && gf_puts(NEWLINE
, pc
)))
2933 if(((*a
)+1)->description
)
2936 if(!(gf_puts("[Can't display missing text segment]", pc
)
2937 && gf_puts(NEWLINE
, pc
)))
2943 else if((*a
)->body
->subtype
2944 && strucmp((*a
)->body
->subtype
, "external-body") == 0) {
2945 if(format_editorial("This part is not included and can be fetched as follows:",
2946 ps_global
->ttyo
->screen_cols
, flags
, NULL
, pc
)
2947 || !gf_puts(NEWLINE
, pc
)
2948 || format_editorial(display_parameters((*a
)->body
->parameter
),
2949 ps_global
->ttyo
->screen_cols
, flags
, handlesp
, pc
))
2952 else if(decode_text(*a
, msgno
, pc
, NULL
, QStatus
, flags
))
2960 display_vcard_att(long int msgno
, ATTACH_S
*a
, int flags
)
2962 STORE_S
*in_store
, *out_store
= NULL
;
2963 HANDLE_S
*handles
= NULL
;
2966 char **lines
, **ll
, *errstr
= NULL
, tmp
[MAILTMPLEN
], *p
;
2967 int cmd
, indent
, begins
= 0;
2969 lines
= detach_vcard_att(ps_global
->mail_stream
,
2970 msgno
, a
->body
, a
->number
);
2972 q_status_message(SM_ORDER
| SM_DING
, 3, 3,
2973 _("Error accessing attachment."));
2977 if(!(in_store
= so_get(CharStar
, NULL
, EDIT_ACCESS
))){
2978 free_list_array(&lines
);
2979 q_status_message(SM_ORDER
| SM_DING
, 3, 3,
2980 _("Error allocating space for attachment."));
2984 for(ll
= lines
, indent
= 0; ll
&& *ll
; ll
++)
2985 if((p
= strindex(*ll
, ':')) && p
- *ll
> indent
)
2989 for(ll
= lines
; ll
&& *ll
; ll
++){
2990 if((p
= strindex(*ll
, ':')) != NULL
){
2991 if(begins
< 2 && struncmp(*ll
, "begin:", 6) == 0)
2994 snprintf(tmp
, sizeof(tmp
), " %-*.*s : ", indent
- 5,
2995 (int) MIN(p
- *ll
, sizeof(tmp
)-5), *ll
);
2996 tmp
[sizeof(tmp
)-1] = '\0';
2997 so_puts(in_store
, tmp
);
3002 so_puts(in_store
, repeat_char(indent
, SPACE
));
3005 snprintf(tmp
, sizeof(tmp
), "%.200s", p
);
3006 tmp
[sizeof(tmp
)-1] = '\0';
3008 (char *)rfc1522_decode_to_utf8((unsigned char *)tmp_20k_buf
,
3009 SIZEOF_20KBUF
, tmp
));
3010 so_puts(in_store
, "\015\012");
3013 free_list_array(&lines
);
3015 so_puts(in_store
, "\015\012\015\012");
3018 if((out_store
= so_get(CharStar
, NULL
, EDIT_ACCESS
)) != NULL
){
3019 so_seek(in_store
, 0L, 0);
3021 init_handles(&handles
);
3024 if(F_ON(F_VIEW_SEL_URL
, ps_global
)
3025 || F_ON(F_VIEW_SEL_URL_HOST
, ps_global
)
3026 || F_ON(F_SCAN_ADDR
, ps_global
))
3027 gf_link_filter(gf_line_test
,
3028 gf_line_test_opt(url_hilite
,
3029 gf_url_hilite_opt(&uh
,&handles
,0)));
3031 gf_link_filter(gf_wrap
,
3032 gf_wrap_filter_opt(ps_global
->ttyo
->screen_cols
- 4,
3033 ps_global
->ttyo
->screen_cols
,
3034 NULL
, indent
, GFW_HANDLES
));
3035 gf_link_filter(gf_nvtnl_local
, NULL
);
3037 gf_set_so_readc(&gc
, in_store
);
3038 gf_set_so_writec(&pc
, out_store
);
3040 errstr
= gf_pipe(gc
, pc
);
3042 gf_clear_so_readc(in_store
);
3045 #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.")
3046 #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.")
3047 errstr
= format_editorial((begins
> 1)
3048 ? VCARD_TEXT_MORE
: VCARD_TEXT_ONE
,
3049 ps_global
->ttyo
->screen_cols
, 0, NULL
, pc
);
3052 gf_clear_so_writec(out_store
);
3055 cmd
= scroll_attachment(_("ADDRESS BOOK ATTACHMENT"), out_store
,
3056 CharStar
, handles
, a
, flags
| DA_RESIZE
);
3058 free_handles(&handles
);
3059 so_give(&out_store
);
3062 errstr
= _("Error allocating space");
3064 while(!errstr
&& (cmd
== MC_RESIZE
|| cmd
== MC_FULLHDR
));
3067 q_status_message1(SM_ORDER
| SM_DING
, 3, 3,
3068 _("Can't format entry : %s"), errstr
);
3074 display_vevent_summary(long int msgno
, ATTACH_S
*a
, int flags
, int depth
)
3077 VCALENDAR_S
*vcal
= NULL
;
3078 char *b64text
, *caltext
;
3079 unsigned long callen
;
3080 VEVENT_SUMMARY_S
*vesy
, *vsummary
; /* vevent summary */
3081 STORE_S
*in_store
, *out_store
= NULL
;
3082 HANDLE_S
*handles
= NULL
;
3085 char *errstr
= NULL
, tmp
[MAILTMPLEN
], *p
;
3088 b
= mail_body(ps_global
->mail_stream
, msgno
, a
->number
);
3089 if(b
->sparep
== NULL
){
3090 b64text
= mail_fetch_body(ps_global
->mail_stream
, msgno
, a
->number
, &callen
, 0);
3091 b64text
[callen
] = '\0'; /* chop off cookie */
3092 caltext
= rfc822_base64(b64text
, strlen(b64text
), &callen
);
3093 vcal
= ical_parse_text(caltext
);
3094 b
->sparep
= create_body_sparep(iCalType
, (void *) vcal
);
3096 else if(get_body_sparep_type(b
->sparep
) == iCalType
)
3097 vcal
= (VCALENDAR_S
*) get_body_sparep_data(b
->sparep
);
3099 vsummary
= ical_vevent_summary(vcal
);
3101 if(vsummary
== NULL
){
3102 q_status_message(SM_ORDER
| SM_DING
, 3, 3,
3103 _("Error parsing event"));
3107 if(!(in_store
= so_get(CharStar
, NULL
, EDIT_ACCESS
))){
3108 q_status_message(SM_ORDER
| SM_DING
, 3, 3,
3109 _("Error allocating space to process Calendar"));
3113 gf_set_so_readc(&gc
, in_store
);
3115 for(vesy
= vsummary
, k
= 0; vesy
; vesy
= vesy
->next
, k
++){
3116 if(depth
>= 0 && k
!= depth
)
3120 so_puts(in_store
, _("This event was cancelled"));
3121 so_puts(in_store
, "\015\012");
3125 utf8_snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, "%s%d %s",
3126 _("Priority: "), vesy
->priority
,
3127 vesy
->priority
== 5 ? _("(Normal)")
3128 : (vesy
->priority
< 5 ? _("(High)")
3130 so_puts(in_store
, tmp_20k_buf
);
3131 so_puts(in_store
, "\015\012");
3135 utf8_snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, "%s%s",
3136 _("Summary: "), vesy
->summary
);
3137 so_puts(in_store
, tmp_20k_buf
);
3138 so_puts(in_store
, "\015\012");
3142 utf8_snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, "%s%s",
3143 _("Sender: "), vesy
->sender
);
3144 so_puts(in_store
, tmp_20k_buf
);
3145 so_puts(in_store
, "\015\012");
3148 if(vesy
->organizer
){
3149 utf8_snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, "%s%s",
3150 _("Organizer: "), vesy
->organizer
);
3151 so_puts(in_store
, tmp_20k_buf
);
3152 so_puts(in_store
, "\015\012");
3156 utf8_snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, "%s%s",
3157 _("Location: "), vesy
->location
);
3158 so_puts(in_store
, tmp_20k_buf
);
3159 so_puts(in_store
, "\015\012");
3163 utf8_snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, "%s%s",
3164 _("Start Date: "), vesy
->evstart
);
3165 so_puts(in_store
, tmp_20k_buf
);
3166 so_puts(in_store
, "\015\012");
3170 for(i
= 0; vesy
->duration
[i
] != NULL
; i
++){
3171 utf8_snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, "%s%s",
3172 _("Duration: "), vesy
->duration
[i
]);
3173 so_puts(in_store
, tmp_20k_buf
);
3174 so_puts(in_store
, "\015\012");
3176 } else if(vesy
->evend
){
3177 utf8_snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, "%s%s",
3178 _("End Date: "), vesy
->evend
);
3179 so_puts(in_store
, tmp_20k_buf
);
3180 so_puts(in_store
, "\015\012");
3184 utf8_snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, "%s%s",
3185 vcal
->method
? _("Created on: ") : _("Last Revised on; "),
3187 so_puts(in_store
, tmp_20k_buf
);
3188 so_puts(in_store
, "\015\012");
3191 if(vesy
->description
){
3195 so_puts(in_store
, "\015\012");
3197 for(i
= 0; vesy
->description
[i
] != NULL
; i
++){
3198 so_puts(in_store
, _("Description: "));
3199 /* Check if empty description */
3201 for(j
=0; empty
== 1 && vesy
->description
[i
][j
] != '\0'; j
++){
3202 c
= vesy
->description
[i
][j
];
3203 if(c
!= '\n' && c
!= ' ' && c
!= '\t')
3207 so_puts(in_store
, _("[ No description provided ]"));
3208 so_puts(in_store
, "\015\012");
3211 for(j
=0; vesy
->description
[i
][j
] != '\0'; j
++){
3212 c
= vesy
->description
[i
][j
];
3214 so_puts(in_store
, "\015\012");
3217 so_writec(c
, in_store
);
3220 so_puts(in_store
, "\015\012");
3225 so_puts(in_store
, "\015\012");
3226 so_puts(in_store
, _("List of Attendees:"));
3227 so_puts(in_store
, "\015\012");
3228 for(i
= 0; vesy
->attendee
[i
] != NULL
; i
++){
3229 so_puts(in_store
, vesy
->attendee
[i
]);
3230 so_puts(in_store
, "\015\012");
3232 so_puts(in_store
, "\015\012");
3235 utf8_snprintf(tmp_20k_buf
, SIZEOF_20KBUF
,
3236 _("This event was tagged as a %s entry by the sender"), vesy
->class);
3237 so_puts(in_store
, tmp_20k_buf
);
3238 so_puts(in_store
, "\015\012\015\012");
3240 if(depth
< 0 && vesy
->next
){
3241 for(i
= 0; i
< ps_global
->ttyo
->screen_cols
&& i
< 40; i
++)
3242 tmp_20k_buf
[i
] = '-';
3243 tmp_20k_buf
[i
]= '\0';
3244 so_puts(in_store
, tmp_20k_buf
);
3245 so_puts(in_store
, "\015\012");
3247 } /* end "for" loop */
3250 so_seek(in_store
, 0L, 0);
3251 if((out_store
= so_get(CharStar
, NULL
, EDIT_ACCESS
)) == NULL
){
3252 q_status_message(SM_ORDER
| SM_DING
, 3, 3,
3253 _("Error allocating space to write Calendar"));
3257 gf_set_so_writec(&pc
, out_store
);
3259 init_handles(&handles
);
3262 if(F_ON(F_VIEW_SEL_URL
, ps_global
)
3263 || F_ON(F_VIEW_SEL_URL_HOST
, ps_global
)
3264 || F_ON(F_SCAN_ADDR
, ps_global
))
3265 gf_link_filter(gf_line_test
,
3266 gf_line_test_opt(url_hilite
,
3267 gf_url_hilite_opt(&uh
,&handles
,0)));
3269 gf_link_filter(gf_wrap
,
3270 gf_wrap_filter_opt(ps_global
->ttyo
->screen_cols
- 4,
3271 ps_global
->ttyo
->screen_cols
,
3272 NULL
, 0, GFW_HANDLES
));
3273 gf_link_filter(gf_nvtnl_local
, NULL
);
3275 gf_set_so_readc(&gc
, in_store
);
3276 gf_set_so_writec(&pc
, out_store
);
3278 errstr
= gf_pipe(gc
, pc
);
3280 gf_clear_so_readc(in_store
);
3282 gf_clear_so_writec(out_store
);
3285 cmd
= scroll_attachment(_("CALENDAR EVENT ATTACHMENT"), out_store
,
3286 CharStar
, handles
, a
, flags
| DA_RESIZE
);
3288 free_handles(&handles
);
3289 so_give(&out_store
);
3291 while(!errstr
&& (cmd
== MC_RESIZE
|| cmd
== MC_FULLHDR
));
3294 q_status_message1(SM_ORDER
| SM_DING
, 3, 3,
3295 _("Can't format entry : %s"), errstr
);
3297 free_vevent_summary(&vsummary
);
3298 ps_global
->mangled_screen
= 1;
3303 display_vcalendar_att(long int msgno
, ATTACH_S
*a
, int flags
)
3305 display_vevent_summary(msgno
, a
, flags
, -1);
3309 /*----------------------------------------------------------------------
3310 Display attachment information
3312 Args: msgno -- message number to get partrom
3313 a -- attachment struct for the desired part
3315 Result: a screen containing information about attachment:
3318 display_attach_info(long int msgno
, ATTACH_S
*a
)
3320 int i
, indent
, cols
;
3321 char buf1
[100], *folded
;
3326 (void) dispatch_attachment(a
);
3328 if(!(store
= so_get(CharStar
, NULL
, EDIT_ACCESS
))){
3329 q_status_message(SM_ORDER
| SM_DING
, 3, 3,
3330 _("Error allocating space for message."));
3334 cols
= ps_global
->ttyo
->screen_cols
;
3338 * 16 for text (longest is Display Method == 14)
3343 /* don't try stupid folding */
3344 cols
= MAX(indent
+10, cols
);
3346 so_puts(store
, "Details about Attachment #");
3347 so_puts(store
, a
->number
);
3348 so_puts(store
, " :\n\n");
3349 utf8_snprintf(buf1
, sizeof(buf1
), " %-*.*w: ", indent
-4, indent
-4, "Type");
3350 so_puts(store
, buf1
);
3351 so_puts(store
, body_type_names(a
->body
->type
));
3352 so_puts(store
, "\n");
3353 utf8_snprintf(buf1
, sizeof(buf1
), " %-*.*w: ", indent
-4, indent
-4, "Subtype");
3354 so_puts(store
, buf1
);
3355 so_puts(store
, a
->body
->subtype
? a
->body
->subtype
: "Unknown");
3356 so_puts(store
, "\n");
3357 utf8_snprintf(buf1
, sizeof(buf1
), " %-*.*w: ", indent
-4, indent
-4, "Encoding");
3358 so_puts(store
, buf1
);
3359 so_puts(store
, a
->body
->encoding
< ENCMAX
3360 ? body_encodings
[a
->body
->encoding
]
3362 so_puts(store
, "\n");
3363 if((plist
= rfc2231_newparmlist(a
->body
->parameter
)) != NULL
){
3364 utf8_snprintf(buf1
, sizeof(buf1
), " %-*.*w: ", indent
-4, indent
-4, "Parameters");
3365 so_puts(store
, buf1
);
3367 while(rfc2231_list_params(plist
)){
3369 so_puts(store
, repeat_char(indent
, ' '));
3371 so_puts(store
, plist
->attrib
);
3372 so_puts(store
, " = ");
3373 so_puts(store
, plist
->value
? plist
->value
: "");
3374 so_puts(store
, "\n");
3377 rfc2231_free_parmlist(&plist
);
3380 if(a
->body
->description
&& a
->body
->description
[0]){
3381 char buftmp
[MAILTMPLEN
];
3384 utf8_snprintf(buf1
, sizeof(buf1
), " %-*.*w: ", indent
-4, indent
-4, "Description");
3386 snprintf(buftmp
, sizeof(buftmp
), "%s", a
->body
->description
);
3387 buftmp
[sizeof(buftmp
)-1] = '\0';
3388 q
= rfc1522_decode_to_utf8((unsigned char *)tmp_20k_buf
, SIZEOF_20KBUF
, buftmp
);
3389 folded
= fold((char *) q
, cols
, cols
, buf1
, repeat_char(indent
+1, ' '), FLD_NONE
);
3392 so_puts(store
, folded
);
3393 fs_give((void **) &folded
);
3397 /* BUG: no a->body->language support */
3399 if(a
->body
->disposition
.type
){
3400 utf8_snprintf(buf1
, sizeof(buf1
), " %-*.*w: ", indent
-4, indent
-4, "Disposition");
3401 so_puts(store
, buf1
);
3402 so_puts(store
, a
->body
->disposition
.type
);
3403 so_puts(store
, "\n");
3404 if((plist
= rfc2231_newparmlist(a
->body
->disposition
.parameter
)) != NULL
){
3405 while(rfc2231_list_params(plist
)){
3406 so_puts(store
, repeat_char(indent
, ' '));
3407 so_puts(store
, plist
->attrib
);
3408 so_puts(store
, " = ");
3409 so_puts(store
, plist
->value
? plist
->value
: "");
3410 so_puts(store
, "\n");
3413 rfc2231_free_parmlist(&plist
);
3417 utf8_snprintf(buf1
, sizeof(buf1
), " %-*.*w: ", indent
-4, indent
-4, "Approx. Size");
3418 so_puts(store
, buf1
);
3419 so_puts(store
, comatose((a
->body
->encoding
== ENCBASE64
)
3420 ? ((a
->body
->size
.bytes
* 3)/4)
3421 : a
->body
->size
.bytes
));
3422 so_puts(store
, " bytes\n");
3423 utf8_snprintf(buf1
, sizeof(buf1
), " %-*.*w: ", indent
-4, indent
-4, "Display Method");
3424 so_puts(store
, buf1
);
3425 if(a
->can_display
== MCD_NONE
) {
3426 so_puts(store
, "Can't, ");
3427 so_puts(store
, (a
->body
->encoding
< ENCOTHER
)
3428 ? "Unknown Attachment Format"
3429 : "Unknown Encoding");
3431 else if(!(a
->can_display
& MCD_EXTERNAL
)){
3432 so_puts(store
, "Alpine's Internal Pager");
3435 int nt
, free_pretty_cmd
;
3439 if((mc_cmd
= mailcap_build_command(a
->body
->type
, a
->body
->subtype
,
3440 a
->body
, "<datafile>", &nt
,
3441 a
->can_display
& MCD_EXT_PROMPT
)) != NULL
){
3442 so_puts(store
, "\"");
3443 if((pretty_cmd
= execview_pretty_command(mc_cmd
, &free_pretty_cmd
)) != NULL
)
3444 so_puts(store
, pretty_cmd
);
3445 so_puts(store
, "\"");
3446 if(free_pretty_cmd
&& pretty_cmd
)
3447 fs_give((void **)&pretty_cmd
);
3449 fs_give((void **)&mc_cmd
->command
);
3450 fs_give((void **)&mc_cmd
);
3454 so_puts(store
, "\n");
3456 memset(&sargs
, 0, sizeof(SCROLL_S
));
3457 sargs
.text
.text
= so_text(store
);
3458 sargs
.text
.src
= CharStar
;
3459 sargs
.text
.desc
= "attachment info";
3460 sargs
.bar
.title
= _("ABOUT ATTACHMENT");
3461 sargs
.help
.text
= h_simple_text_view
;
3462 sargs
.help
.title
= _("HELP FOR \"ABOUT ATTACHMENT\"");
3464 sargs
.use_indexline_color
= 1;
3468 so_give(&store
); /* free resources associated with store */
3469 ps_global
->mangled_screen
= 1;
3473 /*----------------------------------------------------------------------
3477 forward_attachment(MAILSTREAM
*stream
, long int msgno
, ATTACH_S
*a
)
3485 forward_msg_att(stream
, msgno
, a
);
3488 ACTION_S
*role
= NULL
;
3489 REDRAFT_POS_S
*redraft_pos
= NULL
;
3490 long rflags
= ROLE_FORWARD
;
3493 outgoing
= mail_newenvelope();
3494 outgoing
->subject
= cpystr("Forwarded attachment...");
3496 if(nonempty_patterns(rflags
, &dummy
)){
3498 * There is no message, but a Current Folder Type might match.
3500 * This has been changed to check against the message
3501 * containing the attachment.
3503 role
= set_role_from_msg(ps_global
, ROLE_FORWARD
, msgno
, NULL
);
3504 if(confirm_role(rflags
, &role
))
3505 role
= combine_inherited_role(role
);
3508 cmd_cancelled("Forward");
3509 mail_free_envelope(&outgoing
);
3515 q_status_message1(SM_ORDER
, 3, 4,
3516 _("Forwarding using role \"%s\""), role
->nick
);
3518 outgoing
->message_id
= generate_message_id(role
);
3520 * as with all text bound for the composer, build it in
3521 * a storage object of the type it understands...
3523 if((msgtext
= (void *) so_get(PicoText
, NULL
, EDIT_ACCESS
)) != NULL
){
3524 int impl
, template_len
= 0;
3526 if(role
&& role
->template){
3530 filtered
= detoken(role
, NULL
, 0, 0, 0, &redraft_pos
, &impl
);
3533 so_puts((STORE_S
*)msgtext
, filtered
);
3535 template_len
= strlen(filtered
);
3538 fs_give((void **)&filtered
);
3544 if((sig
= detoken(role
, NULL
, 2, 0, 1, &redraft_pos
, &impl
)) != NULL
){
3546 redraft_pos
->offset
+= template_len
;
3548 so_puts((STORE_S
*)msgtext
, *sig
? sig
: NEWLINE
);
3550 fs_give((void **)&sig
);
3553 so_puts((STORE_S
*)msgtext
, NEWLINE
);
3555 /*---- New Body to start with ----*/
3556 body
= mail_newbody();
3557 body
->type
= TYPEMULTIPART
;
3559 /*---- The TEXT part/body ----*/
3560 body
->nested
.part
= mail_newbody_part();
3561 body
->nested
.part
->body
.type
= TYPETEXT
;
3562 body
->nested
.part
->body
.contents
.text
.data
= msgtext
;
3564 /*---- The corresponding things we're attaching ----*/
3565 body
->nested
.part
->next
= mail_newbody_part();
3566 body
->nested
.part
->next
->body
.id
= generate_message_id(role
);
3567 copy_body(&body
->nested
.part
->next
->body
, a
->body
);
3569 if(fetch_contents(stream
, msgno
, a
->number
,
3570 &body
->nested
.part
->next
->body
)){
3571 pine_send(outgoing
, &body
, "FORWARD MESSAGE",
3572 role
, NULL
, NULL
, redraft_pos
, NULL
, NULL
, 0);
3574 ps_global
->mangled_screen
= 1;
3575 pine_free_body(&body
);
3576 free_redraft_pos(&redraft_pos
);
3579 mail_free_body(&body
);
3580 so_give((STORE_S
**) &msgtext
);
3581 free_redraft_pos(&redraft_pos
);
3582 q_status_message(SM_ORDER
| SM_DING
, 4, 5,
3583 _("Error fetching message contents. Can't forward message."));
3587 q_status_message(SM_ORDER
| SM_DING
, 3, 4,
3588 _("Error allocating message text"));
3590 mail_free_envelope(&outgoing
);
3597 forward_msg_att(MAILSTREAM
*stream
, long int msgno
, ATTACH_S
*a
)
3599 char *p
, *sig
= NULL
;
3604 ACTION_S
*role
= NULL
;
3606 REDRAFT_POS_S
*redraft_pos
= NULL
;
3608 outgoing
= mail_newenvelope();
3609 memset((void *)&reply
, 0, sizeof(reply
));
3611 if((outgoing
->subject
= forward_subject(a
->body
->nested
.msg
->env
, 0)) != NULL
){
3613 * as with all text bound for the composer, build it in
3614 * a storage object of the type it understands...
3616 if((msgtext
= (void *) so_get(PicoText
, NULL
, EDIT_ACCESS
)) != NULL
){
3617 int impl
, template_len
= 0;
3618 long rflags
= ROLE_FORWARD
;
3622 if(ps_global
->full_header
== 2)
3623 ret
= want_to(_("Forward message as an attachment"), 'n', 0,
3624 NO_HELP
, WT_SEQ_SENSITIVE
);
3625 /* Setup possible role */
3626 if(nonempty_patterns(rflags
, &dummy
)){
3627 role
= set_role_from_msg(ps_global
, rflags
, msgno
, a
->number
);
3628 if(confirm_role(rflags
, &role
))
3629 role
= combine_inherited_role(role
);
3630 else{ /* cancel reply */
3632 cmd_cancelled("Forward");
3633 mail_free_envelope(&outgoing
);
3634 so_give((STORE_S
**) &msgtext
);
3640 q_status_message1(SM_ORDER
, 3, 4,
3641 _("Forwarding using role \"%s\""), role
->nick
);
3643 outgoing
->message_id
= generate_message_id(role
);
3645 if(role
&& role
->template){
3649 filtered
= detoken(role
, a
->body
->nested
.msg
->env
,
3650 0, 0, 0, &redraft_pos
, &impl
);
3653 so_puts((STORE_S
*)msgtext
, filtered
);
3655 template_len
= strlen(filtered
);
3658 fs_give((void **)&filtered
);
3664 if((sig
= detoken(role
, a
->body
->nested
.msg
->env
,
3665 2, 0, 1, &redraft_pos
, &impl
)) != NULL
){
3667 redraft_pos
->offset
+= template_len
;
3669 so_puts((STORE_S
*)msgtext
, *sig
? sig
: NEWLINE
);
3671 fs_give((void **)&sig
);
3674 so_puts((STORE_S
*)msgtext
, NEWLINE
);
3677 /*---- New Body to start with ----*/
3678 body
= mail_newbody();
3679 body
->type
= TYPEMULTIPART
;
3681 /*---- The TEXT part/body ----*/
3682 body
->nested
.part
= mail_newbody_part();
3683 body
->nested
.part
->body
.type
= TYPETEXT
;
3684 body
->nested
.part
->body
.contents
.text
.data
= msgtext
;
3686 if(!forward_mime_msg(stream
, msgno
,
3687 p
= body_partno(stream
, msgno
, a
->body
),
3688 a
->body
->nested
.msg
->env
,
3689 &body
->nested
.part
->next
, msgtext
))
3690 mail_free_body(&body
);
3694 if(a
->body
->nested
.msg
->body
){
3698 = parameter_val(a
->body
->nested
.msg
->body
->parameter
,
3701 if(charset
&& strucmp(charset
, "us-ascii") != 0){
3705 * There is a non-ascii charset,
3706 * is there conversion happening?
3708 if(!(ct
=conversion_table(charset
, ps_global
->posting_charmap
))
3710 reply
.orig_charset
= charset
;
3716 fs_give((void **) &charset
);
3719 body
= forward_body(stream
, a
->body
->nested
.msg
->env
,
3720 a
->body
->nested
.msg
->body
, msgno
,
3721 p
= body_partno(stream
, msgno
, a
->body
),
3725 fs_give((void **) &p
);
3728 pine_send(outgoing
, &body
,
3731 reply
.forw
? &reply
: NULL
,
3732 redraft_pos
, NULL
, NULL
, 0);
3734 ps_global
->mangled_screen
= 1;
3735 pine_free_body(&body
);
3736 free_redraft_pos(&redraft_pos
);
3740 so_give((STORE_S
**) &msgtext
);
3741 q_status_message(SM_ORDER
| SM_DING
, 4, 5,
3742 _("Error fetching message contents. Can't forward message."));
3746 q_status_message(SM_ORDER
| SM_DING
, 3, 4,
3747 _("Error allocating message text"));
3750 q_status_message1(SM_ORDER
,3,4,
3751 _("Error fetching message %s. Can't forward it."),
3752 long2string(msgno
));
3754 if(reply
.orig_charset
)
3755 fs_give((void **)&reply
.orig_charset
);
3757 mail_free_envelope(&outgoing
);
3762 reply_msg_att(MAILSTREAM
*stream
, long int msgno
, ATTACH_S
*a
)
3764 ADDRESS
*saved_from
, *saved_to
, *saved_cc
, *saved_resent
;
3768 char *tp
, *prefix
= NULL
, *fcc
= NULL
, *errmsg
= NULL
;
3769 int include_text
= 0, flags
= RSF_QUERY_REPLY_ALL
;
3770 int rolemsg
= 0, copytomsg
= 0;
3773 REDRAFT_POS_S
*redraft_pos
= NULL
;
3774 ACTION_S
*role
= NULL
;
3776 outgoing
= mail_newenvelope();
3778 dprint((4,"\n - attachment reply \n"));
3780 saved_from
= (ADDRESS
*) NULL
;
3781 saved_to
= (ADDRESS
*) NULL
;
3782 saved_cc
= (ADDRESS
*) NULL
;
3783 saved_resent
= (ADDRESS
*) NULL
;
3784 outgoing
->subject
= NULL
;
3786 prefix
= reply_quote_str(a
->body
->nested
.msg
->env
);
3788 * For consistency, the first question is always "include text?"
3790 if((include_text
= reply_text_query(ps_global
, 1, NULL
, &prefix
)) >= 0
3791 && reply_news_test(a
->body
->nested
.msg
->env
, outgoing
) > 0
3792 && reply_harvest(ps_global
, msgno
, a
->number
,
3793 a
->body
->nested
.msg
->env
, &saved_from
,
3794 &saved_to
, &saved_cc
, &saved_resent
, &flags
)){
3795 outgoing
->subject
= reply_subject(a
->body
->nested
.msg
->env
->subject
,
3798 reply_seed(ps_global
, outgoing
, a
->body
->nested
.msg
->env
,
3799 saved_from
, saved_to
, saved_cc
, saved_resent
,
3800 &fcc
, flags
& RSF_FORCE_REPLY_ALL
, &errmsg
);
3803 q_status_message1(SM_ORDER
, 3, 3, "%.200s", errmsg
);
3804 display_message(NO_OP_COMMAND
);
3807 fs_give((void **)&errmsg
);
3810 if(sp_expunge_count(stream
)) /* current msg was expunged */
3813 /* Setup possible role */
3814 rflags
= ROLE_REPLY
;
3815 if(nonempty_patterns(rflags
, &dummy
)){
3816 role
= set_role_from_msg(ps_global
, rflags
, msgno
, a
->number
);
3817 if(confirm_role(rflags
, &role
))
3818 role
= combine_inherited_role(role
);
3819 else{ /* cancel reply */
3821 cmd_cancelled("Reply");
3829 /* override fcc gotten in reply_seed */
3830 if(role
->fcc
&& fcc
)
3831 fs_give((void **) &fcc
);
3834 if(F_ON(F_COPY_TO_TO_FROM
, ps_global
) && !(role
&& role
->from
)){
3835 ADDRESS
*us_in_to_and_cc
, *ap
;
3837 us_in_to_and_cc
= (ADDRESS
*) NULL
;
3838 if(a
->body
->nested
.msg
->env
&& a
->body
->nested
.msg
->env
->to
)
3839 if((ap
=reply_cp_addr(ps_global
, 0L, NULL
,
3840 NULL
, us_in_to_and_cc
, NULL
,
3841 a
->body
->nested
.msg
->env
->to
, RCA_ONLY_US
)) != NULL
)
3842 reply_append_addr(&us_in_to_and_cc
, ap
);
3844 if(a
->body
->nested
.msg
->env
&& a
->body
->nested
.msg
->env
->cc
)
3845 if((ap
=reply_cp_addr(ps_global
, 0L, NULL
,
3846 NULL
, us_in_to_and_cc
, NULL
,
3847 a
->body
->nested
.msg
->env
->cc
, RCA_ONLY_US
)) != NULL
)
3848 reply_append_addr(&us_in_to_and_cc
, ap
);
3851 * A list of all of our addresses that appear in the To
3852 * and cc fields is in us_in_to_and_cc.
3853 * If there is exactly one address in that list then
3854 * use it for the outgoing From.
3856 if(us_in_to_and_cc
&& !us_in_to_and_cc
->next
){
3857 PINEFIELD
*custom
, *pf
;
3862 * Check to see if this address is different from what
3863 * we would have used anyway. If it is, notify the user
3864 * with a status message. This is pretty hokey because we're
3865 * mimicking how pine_send would set the From address and
3866 * there is no coordination between the two.
3869 /* in case user has a custom From value */
3870 custom
= parse_custom_hdrs(ps_global
->VAR_CUSTOM_HDRS
, UseAsDef
);
3872 pf
= (PINEFIELD
*) fs_get(sizeof(*pf
));
3873 memset((void *) pf
, 0, sizeof(*pf
));
3874 pf
->name
= cpystr("From");
3876 if(set_default_hdrval(pf
, custom
) >= UseAsDef
3877 && pf
->textbuf
&& pf
->textbuf
[0]){
3878 removing_trailing_white_space(pf
->textbuf
);
3879 (void)removing_double_quotes(pf
->textbuf
);
3880 build_address(pf
->textbuf
, &addr
, NULL
, NULL
, NULL
);
3881 rfc822_parse_adrlist(pf
->addr
, addr
, ps_global
->maildomain
);
3883 fs_give((void **) &addr
);
3887 *pf
->addr
= generate_from();
3889 if(*pf
->addr
&& !address_is_same(*pf
->addr
, us_in_to_and_cc
)){
3892 role
= (ACTION_S
*) fs_get(sizeof(*role
));
3893 memset((void *) role
, 0, sizeof(*role
));
3894 role
->is_a_role
= 1;
3897 role
->from
= us_in_to_and_cc
;
3898 us_in_to_and_cc
= NULL
;
3901 free_customs(custom
);
3906 mail_free_address(&us_in_to_and_cc
);
3911 if(rolemsg
&& copytomsg
)
3912 q_status_message1(SM_ORDER
, 3, 4,
3913 _("Replying using role \"%s\" and To as From"), role
->nick
);
3915 q_status_message1(SM_ORDER
, 3, 4,
3916 _("Replying using role \"%s\""), role
->nick
);
3918 q_status_message(SM_ORDER
, 3, 4,
3919 _("Replying using incoming To as outgoing From"));
3922 outgoing
->in_reply_to
= reply_in_reply_to(a
->body
->nested
.msg
->env
);
3923 outgoing
->references
= reply_build_refs(a
->body
->nested
.msg
->env
);
3924 outgoing
->message_id
= generate_message_id(role
);
3926 if(!outgoing
->to
&& !outgoing
->cc
3927 && !outgoing
->bcc
&& !outgoing
->newsgroups
)
3928 q_status_message(SM_ORDER
| SM_DING
, 3, 6,
3929 _("Warning: no valid addresses to reply to!"));
3932 * Now fix up the body...
3934 if((msgtext
= (void *) so_get(PicoText
, NULL
, EDIT_ACCESS
)) != NULL
){
3937 memset((void *)&reply
, 0, sizeof(reply
));
3939 if(a
->body
->nested
.msg
->body
){
3943 = parameter_val(a
->body
->nested
.msg
->body
->parameter
,
3946 if(charset
&& strucmp(charset
, "us-ascii") != 0){
3950 * There is a non-ascii charset,
3951 * is there conversion happening?
3953 if(!(ct
=conversion_table(charset
, ps_global
->posting_charmap
))
3955 reply
.orig_charset
= charset
;
3961 fs_give((void **) &charset
);
3964 if((body
= reply_body(stream
, a
->body
->nested
.msg
->env
,
3965 a
->body
->nested
.msg
->body
, msgno
,
3966 tp
= body_partno(stream
, msgno
, a
->body
),
3967 msgtext
, prefix
, include_text
, role
,
3968 1, &redraft_pos
)) != NULL
){
3969 /* partially formatted outgoing message */
3970 pine_send(outgoing
, &body
, "COMPOSE MESSAGE REPLY",
3971 role
, fcc
, &reply
, redraft_pos
, NULL
, NULL
, 0);
3973 pine_free_body(&body
);
3974 ps_global
->mangled_screen
= 1;
3977 q_status_message(SM_ORDER
| SM_DING
, 3, 4,
3978 _("Error building message body"));
3980 fs_give((void **) &tp
);
3981 if(reply
.orig_charset
)
3982 fs_give((void **)&reply
.orig_charset
);
3985 q_status_message(SM_ORDER
| SM_DING
, 3, 4,
3986 _("Error allocating message text"));
3990 mail_free_envelope(&outgoing
);
3991 mail_free_address(&saved_from
);
3992 mail_free_address(&saved_to
);
3993 mail_free_address(&saved_cc
);
3994 mail_free_address(&saved_resent
);
3997 fs_give((void **) &prefix
);
4000 fs_give((void **) &fcc
);
4002 free_redraft_pos(&redraft_pos
);
4008 bounce_msg_att(MAILSTREAM
*stream
, long int msgno
, char *part
, char *subject
)
4012 if((errstr
= bounce_msg(stream
, msgno
, part
, NULL
, NULL
, subject
, NULL
, NULL
)) != NULL
)
4013 q_status_message(SM_ORDER
| SM_DING
, 3, 3, errstr
);
4018 pipe_attachment(long int msgno
, ATTACH_S
*a
)
4020 char *err
, *resultfilename
= NULL
, prompt
[80], *p
;
4021 int rc
, capture
= 1, raw
= 0, we_cancel
= 0, j
= 0;
4025 char pipe_command
[MAXPATH
+1];
4026 unsigned flagsforhist
= 1; /* raw=2 /capture=1 */
4027 static HISTORY_S
*history
= NULL
;
4028 ESCKEY_S pipe_opt
[6];
4030 if(ps_global
->restricted
){
4031 q_status_message(SM_ORDER
| SM_DING
, 0, 4,
4032 "Alpine demo can't pipe attachments");
4037 pipe_command
[0] = '\0';
4039 init_hist(&history
, HISTSIZE
);
4040 flagsforhist
= (raw
? 0x2 : 0) + (capture
? 0x1 : 0);
4041 if((p
= get_prev_hist(history
, "", flagsforhist
, NULL
)) != NULL
){
4042 strncpy(pipe_command
, p
, sizeof(pipe_command
));
4043 pipe_command
[sizeof(pipe_command
)-1] = '\0';
4044 if(history
->hist
[history
->curindex
]){
4045 flagsforhist
= history
->hist
[history
->curindex
]->flags
;
4046 raw
= (flagsforhist
& 0x2) ? 1 : 0;
4047 capture
= (flagsforhist
& 0x1) ? 1 : 0;
4052 pipe_opt
[j
].rval
= 0;
4053 pipe_opt
[j
].name
= "";
4054 pipe_opt
[j
++].label
= "";
4056 pipe_opt
[j
].ch
= ctrl('W');
4057 pipe_opt
[j
].rval
= 10;
4058 pipe_opt
[j
].name
= "^W";
4059 pipe_opt
[j
++].label
= NULL
;
4061 pipe_opt
[j
].ch
= ctrl('Y');
4062 pipe_opt
[j
].rval
= 11;
4063 pipe_opt
[j
].name
= "^Y";
4064 pipe_opt
[j
++].label
= NULL
;
4066 pipe_opt
[j
].ch
= KEY_UP
;
4067 pipe_opt
[j
].rval
= 30;
4068 pipe_opt
[j
].name
= "";
4070 pipe_opt
[j
++].label
= "";
4072 pipe_opt
[j
].ch
= KEY_DOWN
;
4073 pipe_opt
[j
].rval
= 31;
4074 pipe_opt
[j
].name
= "";
4075 pipe_opt
[j
++].label
= "";
4077 pipe_opt
[j
].ch
= -1;
4082 snprintf(prompt
, sizeof(prompt
), "Pipe %sattachment %s to %s: ", raw
? "RAW " : "",
4083 a
->number
, capture
? "" : "(Free Output) ");
4084 prompt
[sizeof(prompt
)-1] = '\0';
4085 pipe_opt
[1].label
= raw
? "DecodedData" : "Raw Data";
4086 pipe_opt
[2].label
= capture
? "Free Output" : "Capture Output";
4089 * 2 is really 1 because there will be one real entry and
4090 * one entry of "" because of the get_prev_hist above.
4092 if(items_in_hist(history
) > 2){
4093 pipe_opt
[ku
].name
= HISTORY_UP_KEYNAME
;
4094 pipe_opt
[ku
].label
= HISTORY_KEYLABEL
;
4095 pipe_opt
[ku
+1].name
= HISTORY_DOWN_KEYNAME
;
4096 pipe_opt
[ku
+1].label
= HISTORY_KEYLABEL
;
4099 pipe_opt
[ku
].name
= "";
4100 pipe_opt
[ku
].label
= "";
4101 pipe_opt
[ku
+1].name
= "";
4102 pipe_opt
[ku
+1].label
= "";
4105 flags
= OE_APPEND_CURRENT
| OE_SEQ_SENSITIVE
;
4106 rc
= optionally_enter(pipe_command
, -FOOTER_ROWS(ps_global
), 0,
4107 sizeof(pipe_command
), prompt
,
4108 pipe_opt
, help
, &flags
);
4110 q_status_message(SM_ORDER
| SM_DING
, 3, 4,
4111 "Internal problem encountered");
4115 raw
= !raw
; /* flip raw text */
4118 capture
= !capture
; /* flip capture output */
4121 flagsforhist
= (raw
? 0x2 : 0) + (capture
? 0x1 : 0);
4122 if((p
= get_prev_hist(history
, pipe_command
, flagsforhist
, NULL
)) != NULL
){
4123 strncpy(pipe_command
, p
, sizeof(pipe_command
));
4124 pipe_command
[sizeof(pipe_command
)-1] = '\0';
4125 if(history
->hist
[history
->curindex
]){
4126 flagsforhist
= history
->hist
[history
->curindex
]->flags
;
4127 raw
= (flagsforhist
& 0x2) ? 1 : 0;
4128 capture
= (flagsforhist
& 0x1) ? 1 : 0;
4135 flagsforhist
= (raw
? 0x2 : 0) + (capture
? 0x1 : 0);
4136 if((p
= get_next_hist(history
, pipe_command
, flagsforhist
, NULL
)) != NULL
){
4137 strncpy(pipe_command
, p
, sizeof(pipe_command
));
4138 pipe_command
[sizeof(pipe_command
)-1] = '\0';
4139 if(history
->hist
[history
->curindex
]){
4140 flagsforhist
= history
->hist
[history
->curindex
]->flags
;
4141 raw
= (flagsforhist
& 0x2) ? 1 : 0;
4142 capture
= (flagsforhist
& 0x1) ? 1 : 0;
4149 if(pipe_command
[0] == '\0'){
4150 cmd_cancelled("Pipe command");
4154 flagsforhist
= (raw
? 0x2 : 0) + (capture
? 0x1 : 0);
4155 save_hist(history
, pipe_command
, flagsforhist
, NULL
);
4157 flags
= PIPE_USER
| PIPE_WRITE
| PIPE_STDERR
;
4158 flags
|= (raw
? PIPE_RAW
: 0);
4164 ps_global
->mangled_screen
= 1;
4166 flags
|= PIPE_RESET
;
4169 if((syspipe
= open_system_pipe(pipe_command
,
4170 (flags
&PIPE_RESET
) ? NULL
: &resultfilename
,
4171 NULL
, flags
, 0, pipe_callback
, pipe_report_error
)) != NULL
){
4173 gf_io_t pc
; /* wire up a generic putchar */
4175 is_text
= (a
&& a
->body
&& a
->body
->type
== TYPETEXT
);
4177 gf_set_writec(&pc
, syspipe
, 0L, PipeStar
,
4178 (is_text
&& !raw
) ? WRITE_TO_LOCALE
: 0);
4180 /*------ Write the image to a temporary file ------*/
4181 if(raw
){ /* pipe raw text */
4182 FETCH_READC_S fetch_part
;
4187 we_cancel
= busy_cue(NULL
, NULL
, 1);
4192 fetch_readc_init(&fetch_part
, ps_global
->mail_stream
,
4193 msgno
, a
->number
, a
->body
->size
.bytes
, 0, 0);
4194 gf_link_filter(gf_nvtnl_local
, NULL
);
4195 err
= gf_pipe(FETCH_READC
, pc
);
4205 /* BUG: there's got to be a better way */
4207 ps_global
->print
= (PRINT_S
*) 1;
4210 err
= detach(ps_global
->mail_stream
, msgno
,
4211 a
->number
, 0L, (long *)NULL
, pc
, NULL
, 0);
4212 ps_global
->print
= (PRINT_S
*) NULL
;
4216 (void) close_system_pipe(&syspipe
, NULL
, pipe_callback
);
4219 q_status_message1(SM_ORDER
| SM_DING
, 3, 4,
4220 _("Error detaching for pipe: %s"), err
);
4222 display_output_file(resultfilename
,
4224 ? _("PIPE ATTACHMENT (ERROR)")
4225 : _("PIPE ATTACHMENT"),
4228 fs_give((void **) &resultfilename
);
4231 q_status_message(SM_ORDER
| SM_DING
, 3, 4,
4232 _("Error opening pipe"));
4237 cmd_cancelled("Pipe");
4241 help
= (help
== NO_HELP
) ? h_pipe_attach
: NO_HELP
;
4247 delete_attachment(long int msgno
, ATTACH_S
*a
)
4249 int expbits
, rv
= 0;
4251 if(!msgno_exceptions(ps_global
->mail_stream
, msgno
,
4252 a
->number
, &expbits
, FALSE
)
4253 || !(expbits
& MSG_EX_DELETE
)){
4254 expbits
|= MSG_EX_DELETE
;
4255 msgno_exceptions(ps_global
->mail_stream
, msgno
,
4256 a
->number
, &expbits
, TRUE
);
4258 q_status_message1(SM_ORDER
, 0, 3,
4259 _("Part %s will be omitted only if message is Saved"),
4264 q_status_message1(SM_ORDER
, 0, 3, _("Part %s already deleted"),
4272 undelete_attachment(long int msgno
, ATTACH_S
*a
, int *expbitsp
)
4276 if(msgno_exceptions(ps_global
->mail_stream
, msgno
,
4277 a
->number
, expbitsp
, FALSE
)
4278 && ((*expbitsp
) & MSG_EX_DELETE
)){
4279 (*expbitsp
) ^= MSG_EX_DELETE
;
4280 msgno_exceptions(ps_global
->mail_stream
, msgno
,
4281 a
->number
, expbitsp
, TRUE
);
4285 q_status_message1(SM_ORDER
, 0, 3, _("Part %s already UNdeleted"),
4292 /*----------------------------------------------------------------------
4293 Resolve any deferred tests for attachment displayability
4295 Args: attachment structure
4297 Returns: undefer's attachment's displayability test
4300 dispatch_attachment(ATTACH_S
*a
)
4302 if(a
->test_deferred
){
4303 a
->test_deferred
= 0;
4304 a
->can_display
= mime_can_display(a
->body
->type
, a
->body
->subtype
, a
->body
);
4307 return(a
->can_display
);
4313 scroll_att_popup(sparms
, in_handle
)
4317 MPopup scrat_popup
[20];
4321 scrat_popup
[++i
].type
= tIndex
;
4322 scrat_popup
[i
].label
.style
= lNormal
;
4323 scrat_popup
[i
].label
.string
= "View Selectable Item";
4324 scrat_popup
[i
].data
.val
= ctrl('L');
4327 scrat_popup
[++i
].type
= tQueue
;
4328 scrat_popup
[i
].label
.style
= lNormal
;
4329 scrat_popup
[i
].label
.string
= "&Save";
4330 scrat_popup
[i
].data
.val
= 'S';
4332 scrat_popup
[++i
].type
= tQueue
;
4333 scrat_popup
[i
].label
.style
= lNormal
;
4334 if(msgno_exceptions(ps_global
->mail_stream
,
4335 mn_m2raw(ps_global
->msgmap
,
4336 mn_get_cur(ps_global
->msgmap
)),
4337 scrat_attachp
->number
, &n
, FALSE
)
4338 && (n
& MSG_EX_DELETE
)){
4339 scrat_popup
[i
].label
.string
= "&Undelete";
4340 scrat_popup
[i
].data
.val
= 'U';
4343 scrat_popup
[i
].label
.string
= "&Delete";
4344 scrat_popup
[i
].data
.val
= 'D';
4347 if(MIME_MSG_A(scrat_attachp
) || MIME_DGST_A(scrat_attachp
)){
4348 scrat_popup
[++i
].type
= tQueue
;
4349 scrat_popup
[i
].label
.style
= lNormal
;
4350 scrat_popup
[i
].label
.string
= "&Reply";
4351 scrat_popup
[i
].data
.val
= 'R';
4353 scrat_popup
[++i
].type
= tQueue
;
4354 scrat_popup
[i
].label
.style
= lNormal
;
4355 scrat_popup
[i
].label
.string
= "&Forward";
4356 scrat_popup
[i
].data
.val
= 'f';
4359 scrat_popup
[++i
].type
= tSeparator
;
4361 scrat_popup
[++i
].type
= tQueue
;
4362 scrat_popup
[i
].label
.style
= lNormal
;
4363 scrat_popup
[i
].label
.string
= "Attachment Index";
4364 scrat_popup
[i
].data
.val
= '<';
4366 scrat_popup
[++i
].type
= tTail
;
4368 return(mswin_popup(scrat_popup
) == 0 && in_handle
);
4373 display_att_window(a
)
4376 #if !defined(DOS) && !defined(OS2)
4380 if(a
->body
->type
== TYPEMULTIPART
){
4381 if(a
->body
->subtype
){
4382 /* if(!strucmp(a->body->subtype, "digest"))
4383 display_digest_att(msgno, a, flags);
4385 q_status_message1(SM_ORDER
, 3, 5,
4386 "Can't display Multipart/%s",
4390 q_status_message(SM_ORDER
, 3, 5,
4391 "Can't display unknown Multipart Subtype");
4393 /* else if(MIME_VCARD_A(a))
4394 display_vcard_att_window(msgno, a, flags);*/
4395 else if(a
->body
->type
== TYPETEXT
)
4396 display_text_att_window(a
);
4397 else if(a
->body
->type
== TYPEMESSAGE
)
4398 display_msg_att_window(a
);
4403 display_text_att_window(a
)
4409 msgno
= mn_m2raw(ps_global
->msgmap
, mn_get_cur(ps_global
->msgmap
));
4411 if(store
= format_text_att(msgno
, a
, NULL
)){
4412 if (mswin_displaytext("ATTACHED TEXT",
4414 strlen((char *) so_text(store
)),
4415 NULL
, NULL
, 0) >= 0)
4416 store
->txt
= (void *) NULL
; /* free'd in mswin_displaytext */
4418 so_give(&store
); /* free resources associated with store */
4421 q_status_message(SM_ORDER
| SM_DING
, 3, 3,
4422 "Error allocating space for attachment.");
4427 display_msg_att_window(a
)
4435 msgno
= mn_m2raw(ps_global
->msgmap
, mn_get_cur(ps_global
->msgmap
));
4437 /* BUG, should check this return code */
4438 (void) pine_mail_fetchstructure(ps_global
->mail_stream
, msgno
, NULL
);
4440 /* initialize a storage object */
4441 if(store
= so_get(CharStar
, NULL
, EDIT_ACCESS
)){
4443 gf_set_so_writec(&pc
, store
);
4445 if(format_msg_att(msgno
, &ap
, NULL
, pc
, FM_DISPLAY
)
4446 && mswin_displaytext("ATTACHED MESSAGE", so_text(store
),
4447 strlen((char *) so_text(store
)),
4448 NULL
, NULL
, 0) >= 0)
4449 /* free'd in mswin_displaytext */
4450 store
->txt
= (void *) NULL
;
4452 gf_clear_so_writec(store
);
4457 q_status_message(SM_ORDER
| SM_DING
, 3, 3,
4458 "Error allocating space for message.");