static char rcsid[] = "@(#)$Id: attach_menu.c,v 1.104.2.2 2007/11/03 13:22:53 hurtta Exp $";
/******************************************************************************
* The Elm (ME+) Mail System - $Revision: 1.104.2.2 $ $State: Exp $
*
* Modified by: Kari Hurtta <hurtta+elm@posti.FMI.FI>
* (was hurtta+elm@ozone.FMI.FI)
*
* Initially written by: Michael Elkins <elkins@aero.org>, 1995
*****************************************************************************/
#include "def_elm.h"
#include "s_elm.h"
#include "s_me.h"
DEBUG_VAR(Debug,__FILE__,"mime");
#include <errno.h>
#ifndef ANSI_C
extern int errno;
#endif
static unsigned char *s2us P_((char *str));
static unsigned char *s2us(str)
char *str;
{
return (unsigned char *)str;
}
static char *us2s P_((unsigned char *str));
static char *us2s(str)
unsigned char *str;
{
return (char *)str;
}
static FILE * get_attachment P_((FILE *F, mime_t *att));
static FILE * get_attachment(F,att)
FILE *F;
mime_t *att;
{
FILE * result = NULL;
if (att->magic != MIME_magic)
mime_panic(__FILE__,__LINE__,"get_attachment",
"Bad magic number");
if (att->pathname0) {
if (can_open(att->pathname0,"r") != 0) {
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmErrorReadableUser,
"%S isn't readable by user!"),
att->dispname);
sleep_message();
return NULL;
}
result = fopen(att->pathname0,"r");
if (!result) {
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmCantOpenAttach,
"Can't open attachment: %S"),
att->dispname);
sleep_message();
}
} else {
result = F;
if (-1 == fseek(F,att->offset,SEEK_SET)) {
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmFailedSeekAttach,
"Failed to seek beginning of attachment!"));
sleep_message();
}
}
return result;
}
static void close_attachment P_((FILE *F, FILE *tmpfd));
static void close_attachment(F, tmpfd)
FILE *F;
FILE *tmpfd;
{
if (!tmpfd)
return;
if (F != tmpfd)
fclose(tmpfd);
}
static FILE * get_decoded_attachment P_((FILE *F, mime_t *att,
int *isdecoded));
static FILE * get_decoded_attachment(F,att, isdecoded)
FILE *F;
mime_t *att;
int *isdecoded; /* return 1 is result is contetn-transfer-encdoing
decoded */
{
if (att->magic != MIME_magic)
mime_panic(__FILE__,__LINE__,"get_attachment",
"Bad magic number");
if (att->pathname0) {
FILE *result = NULL;
if (can_open(att->pathname0,"r") != 0) {
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmErrorReadableUser,
"%S isn't readable by user!"),
att->dispname);
sleep_message();
return NULL;
}
result = fopen(att->pathname0,"r");
if (!result) {
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmCantOpenAttach,
"Can't open attachment: %S"),
att->dispname);
sleep_message();
}
*isdecoded = 1;
return result;
} else {
in_state_t state_in;
out_state_t state_out;
char *tmp = give_dt_estr_as_str(&temp_dir_e,"tmpdir");
char *fname;
FILE * tmpfp = NULL;
charset_t vector[2];
in_state_clear(&state_in, STATE_in_file);
out_state_clear(&state_out, STATE_out_file);
if (-1 == fseek(F,att->offset,SEEK_SET)) {
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmFailedSeekAttach,
"Failed to seek beginning of attachment!"));
return NULL;
}
if (!tmp)
return NULL;
fname = elm_message(FRM("%selmdecode.%d"),
tmp, getpid ());
if (NULL == (tmpfp = safeopen_rdwr(fname))) {
lib_error(CATGETS(elm_msg_cat, MeSet, MeDecodeFailedCreate,
"Failed to create file for decoding."));
return NULL;
}
unlink(fname);
set_out_state_file(tmpfp,&state_out);
state_out.displaying = FALSE; /* No messages */
state_out.prefix = NULL;
vector[0] = RAW_BUFFER; /* We want just raw bytes */
vector[1] = NULL;
state_out.display_charset = vector;
set_in_state_file(F,&state_in);
if (run_cte_decoder(att,&state_in,&state_out)) {
*isdecoded = 1;
} else {
int r = state_copy_range(&state_in, &state_out, att->length);
*isdecoded = 0;
if (-1 == r)
lib_error(CATGETS(elm_msg_cat, MeSet,
MeDecodeUnexpectedEOF,
"Unexpected EOF when copying encoded mime part."));
if (0 == r)
lib_error(CATGETS(elm_msg_cat, MeSet, MeDecodeFailedCopy1,
"Failed to copy encoded mime part."));
}
if (EOF == fflush(tmpfp)) {
lib_error(CATGETS(elm_msg_cat, MeSet, MeDecodeErrorFlush,
"Error when flushing temporary file."));
}
rewind(tmpfp); /* Rewind it for reading */
out_state_destroy(&state_out);
in_state_destroy(&state_in);
return tmpfp;
}
}
static void attachment_copy P_((mime_t *att, FILE *tmpfd, FILE *outfd,
charset_t defcharset));
static void attachment_copy(att, tmpfd, outfd, defcharset)
mime_t *att;
FILE *tmpfd, *outfd;
charset_t defcharset;
{
if (att->magic != MIME_magic)
mime_panic(__FILE__,__LINE__,"attachment_copy",
"Bad magic number");
if (att->pathname0) { /* Already decoded */
char buf[VERY_LONG_STRING];
int len;
while (0 < (len = fread(buf,1,sizeof(buf),tmpfd))) {
if (fwrite(buf,1,len,outfd) != len) {
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmWriteErrorAttach,
"Write error when copying attachment!"));
sleep_message();
break;
}
}
if (ferror(tmpfd)) {
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmErrorReadingS,
"Error reading from %S"),
att->dispname);
sleep_message();
}
} else { /* Needs decode */
in_state_t state_in;
out_state_t state_out;
charset_t vector[2];
int disp = att -> disposition;
in_state_clear(&state_in, STATE_in_file);
out_state_clear(&state_out, STATE_out_file);
set_out_state_file(outfd,&state_out);
state_out.displaying = FALSE;
vector[0] = display_charset;
vector[1] = NULL;
state_out.display_charset = vector;
set_in_state_file(tmpfd,&state_in);
att -> disposition = DISP_INLINE; /* Show it ! */
mime_decode(att,&state_in, &state_out,
defcharset, NULL, mime_signature_mismatch);
att -> disposition = disp;
in_state_destroy(&state_in);
out_state_destroy(&state_out);
}
}
static void attach_print P_((FILE *F, mime_t *att, charset_t defcharset,
struct menu_context *page));
static void attach_print (F,att, defcharset,page)
FILE *F;
mime_t *att;
charset_t defcharset;
struct menu_context *page;
{
char tempfile[STRING];
char buf1[VERY_LONG_STRING];
char *tmp;
char * metamail_val;
char * printout_val;
if (att->magic != MIME_magic)
mime_panic(__FILE__,__LINE__,"attach_print",
"Bad magic number");
if (!(printout_val=have_printout()))
return;
tmp = give_dt_estr_as_str(&temp_dir_e,"tmpdir");
if (!tmp)
return;
elm_sfprintf(tempfile,sizeof tempfile,
FRM("%selm.%d"), tmp, getpid());
if (get_major_type_code(att->TYPE) == MIME_TYPE_TEXT &&
istrcmp(get_subtype_name(att->TYPE),"plain") == 0) {
FILE *f_out, *f_in;
int ret;
DPRINT(Debug,3,
(&Debug,"attach_print: printing directly: %s\n",
printout_val));
if (!(f_out = safeopen(tempfile))) {
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmErrorCreatTempfile,
"Error creating tempfile %s"),
tempfile);
sleep_message();
return;
}
if (!(f_in = get_attachment(F,att))) {
fclose(f_out);
unlink(tempfile);
return;
}
attachment_copy(att,f_in,f_out, defcharset);
(void) elm_chown (tempfile, userid, groupid);
fclose(f_out);
elm_sfprintf(buf1, sizeof buf1,
FRM(printout_val), tempfile);
ret = system_call(buf1,0, NULL);
if (ret == 0)
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmJobSpooled,
"Print job spooled."));
else
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmErrorPrinting,
"Error while printing!"));
unlink(tempfile);
close_attachment(F,f_in);
} else if (NULL != (metamail_val=have_metamail())) {
DPRINT(Debug,3,
(&Debug,"attach_print: printing via metamail: %s\n",
metamail_val));
if (att->pathname0)
elm_sfprintf(buf1,sizeof buf1,
FRM("%s -m Elm -h -b -c %s/%s %s"),
metamail_val,
get_major_type_name(att->TYPE),
get_subtype_name(att->TYPE),
att->pathname0);
else {
char copy_buf[VERY_LONG_STRING];
FILE *fpout;
out_state_t state_out;
fpout = safeopen(tempfile);
if (!fpout) {
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmErrorCreatTempfile,
"Error creating tempfile %s"),
tempfile);
sleep_message();
return;
}
(void) elm_chown (tempfile, userid, groupid);
out_state_clear(&state_out, STATE_out_file);
set_out_state_file(fpout,&state_out);
state_out.EOLN_is_CRLF = 0;
/* !! Metamail do not cope with CRLF */
/* the headers plus the message to a temp file */
fseek(F,att->begin_offset,SEEK_SET);
while (ftell(F) < att->offset + att->length) {
int len = mail_gets(copy_buf,sizeof copy_buf,F);
if (len <= 0)
break; /* Error ? */
/* Take care of CRLF => LF conversion (or
LF -> CRLF conversion)
-- metamail do not cope with CRLF
*/
state_convert_EOLN(copy_buf,&len,sizeof copy_buf,
&state_out);
state_put(copy_buf,len,&state_out);
}
out_state_destroy(&state_out);
fclose(fpout);
/* Option -z causes that metamail unlinks tempfile */
elm_sfprintf(buf1,sizeof buf1,
FRM("%s -m Elm -h -z %s"),
metamail_val, tempfile);
}
Raw(OFF);
system_call(buf1,SY_ENV_METAMAIL, NULL);
PressAnyKeyToContinue();
Raw(ON);
menu_trigger_redraw(page);
} else
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmNotKnowPrint,
"Don't know how to print this type of data!"));
}
struct string * pick_name(str)
const struct string *str;
{
int L = string_len(str);
struct string *ret = NULL;
int i;
int pos = 0;
for (i = 0; i < L; i++) {
uint16 code = give_unicode_from_string(str,i);
if (0x002F /* / */ == code ||
code < 0x0020 ||
0x005C /* \ */ == code)
pos = i+1;
}
ret = clip_from_string(str,&pos,L);
return ret;
}
static CONST char * pick_name_ascii P_((const char *str));
static CONST char * pick_name_ascii(str)
const char *str;
{
const char *ret = str;
const char *p;
for (p = str; *p; p++) {
if ('/' == *p ||
'\\' == *p ||
isascii(*p) && iscntrl(*p))
ret = p+1;
}
return ret;
}
static char * give_extension P_((struct string * testname));
static char * give_extension(str)
struct string * str;
{
int L = string_len(str);
int i;
int pos = -1;
for (i = 0; i < L; i++) {
uint16 code = give_unicode_from_string(str,i);
if (0x002F /* / */ == code ||
code < 0x0020 ||
0x005C /* \ */ == code)
pos = -1;
if (0x002E /* . */ == code)
pos = i+1;
}
if (-1 == pos)
return 0;
/* FIXME: -- this may produce unexpected results if
extension is non-ascii
but that should not cause problems,
because that is just matched agaist
mime.types
*/
return us2s(streamclip_from_string(str,&pos,L,NULL,NULL));
}
/*
* We need check type= parameters from default elm.mimetypes
*/
static int filter_scanlist_OK P_((const mime_t * att,
const struct mime_types_item *type_item));
static int filter_scanlist_OK(att,type_item)
CONST mime_t * att;
CONST struct mime_types_item *type_item;
{
charset_t cs = NULL;
int r = 1;
CONST char * params = mime_type_to_params(type_item,&cs);
char * temp,* opt;
char * walk = NULL;
if (!params)
return 1;
if (!att->TYPE_opts) {
DPRINT(Debug,9,(&Debug,
"filter_scanlist_OK: no parms -- paramlist %s\n",
params));
return 0;
}
temp = safe_strdup(params);
for (opt = mime_parse_content_opts(temp, &walk);
opt;
opt = mime_parse_content_opts(NULL, &walk)) {
char * q = strchr(opt,'=');
char *val;
CONST char *val1;
if (!q) {
DPRINT(Debug,9,(&Debug,
"filter_scanlist_OK: bad param '%s' -- bad paramlist %s\n",
opt,params));
r = 0;
goto fail;
}
*q++ = '\0';
if (NULL != strchr(opt,'*')) {
DPRINT(Debug,9,(&Debug,
"filter_scanlist_OK: unsupported param '%s' -- bad paramlist %s\n",
opt,params));
r = 0;
goto fail;
}
val1 = get_mime_param_ascii(att->TYPE_opts,opt);
if (!val1) {
DPRINT(Debug,9,(&Debug,
"filter_scanlist_OK: param '%s' not found -- paramlist %s\n",
opt,params));
r = 0;
goto fail;
}
val = dequote_opt(q,strlen(q));
if (0 != strcmp(val,val1)) {
DPRINT(Debug,9,(&Debug,
"filter_scanlist_OK: param '%s' -- values not match %s <> %s -- paramlist %s\n",
opt,val,val1,
params));
r = 0;
}
free(val);
}
if (r) {
DPRINT(Debug,9,(&Debug,
"filter_scanlist_OK: paramlist OK: %s\n",
params));
}
fail:
free(temp);
return r;
}
static void attach_save P_((FILE *F, mime_t *a, struct AliasView *aview,
struct menu_context *page,
struct screen_parts *LOC));
static void attach_save (F,a,aview, page, LOC)
FILE *F;
mime_t *a;
struct AliasView *aview;
struct menu_context *page;
struct screen_parts *LOC;
{
char buf[VERY_LONG_STRING];
int bytes=0, err, is_text;
in_state_t state_in;
FILE *f_in = NULL;
int code;
int br_flags = 0;
struct string * savefile = NULL;
struct string * msgname = NULL;
struct string * default_extension = NULL;
struct folder_browser * br = new_browser(selection_file);
WRITE_STATE handle = NULL;
int use_attachment_dir = 0;
int was_decoded = 0;
int LINES, COLUMNS;
char * attachment_dir_val =
give_dt_estr_as_str(&attachment_dir_e,
"attachment-dir");
menu_get_sizes(page,&LINES,&COLUMNS);
in_state_clear(&state_in, STATE_in_file);
if (attachment_dir_val &&
0 == access(attachment_dir_val,ACCESS_EXISTS)) {
DPRINT(Debug,15,(&Debug,
"attach_save: attachment-dir=%s set and exists\n",
attachment_dir_val));
use_attachment_dir++;
}
if (a->magic != MIME_magic)
mime_panic(__FILE__,__LINE__,"attach_save",
"Bad magic number");
if (get_major_type_code(a->TYPE) == MIME_TYPE_APPLICATION &&
istrcmp (get_subtype_name(a->TYPE), "octet-stream") == 0) {
int mp = give_dt_enumerate_as_int(&mime_parameters);
CONST struct string *pv;
CONST char * pva;
struct string * testname = NULL;
/* 0 == plain
1 == encoded
2 == plain-and-encoded
*/
/* See if there is a name=<...> field for the default filename */
if ( mp &&
(pv = get_mime_param(a->TYPE_opts,"name"))) {
struct string * p = pick_name(pv);
msgname = dup_string(p);
if (use_attachment_dir) {
testname = format_string(FRM("{doc}/%S"),p);
} else {
testname = format_string(FRM("./%S"),p);
}
free_string(&p);
} else if ((pva = get_mime_param_compat(a->TYPE_opts,"name"))) {
CONST char * p = pick_name_ascii(pva);
msgname = format_string(FRM("%s"),p);
if (use_attachment_dir) {
testname = format_string(FRM("{doc}/%s"),p);
} else {
testname = format_string(FRM("./%s"),p);
}
}
if (testname) {
int ok = select_dir_item(br,&testname);
if (ok) {
int flags = give_dir_flags(br);
if (0 == (flags & BROWSER_EXIST)) {
if (savefile)
free_string(&savefile);
savefile = dup_string(testname);
}
}
free_string(&testname);
}
}
/* See if there is a filename=<...> field for the default filename */
{
int mp = give_dt_enumerate_as_int(&mime_parameters);
CONST struct string *pv;
CONST char * pva;
struct string * testname = NULL;
if ( mp &&
(pv = get_mime_param(a->DISPOSITION_opts,"filename"))) {
struct string * p = pick_name(pv);
if (p) {
if (msgname)
free_string(&msgname);
msgname = dup_string(p);
if (use_attachment_dir) {
testname = format_string(FRM("{doc}/%S"),p);
} else {
testname = format_string(FRM("./%S"),p);
}
free_string(&p);
}
} else if ( (pva = get_mime_param_compat(a->DISPOSITION_opts,
"filename"))) {
CONST char * p = pick_name_ascii(pva);
if (p) {
if (msgname)
free_string(&msgname);
msgname = format_string(FRM("%s"),p);
if (use_attachment_dir) {
testname = format_string(FRM("{doc}/%s"),p);
} else {
testname = format_string(FRM("./%s"),p);
}
}
}
if (testname) {
int ok = select_dir_item(br,&testname);
if (ok) {
int flags = give_dir_flags(br);
if (0 == (flags & BROWSER_EXIST)) {
if (savefile)
free_string(&savefile);
savefile = dup_string(testname);
}
}
free_string(&testname);
}
}
if (!savefile && use_attachment_dir)
savefile = format_string(FRM("{doc}/"));
if (!(f_in = get_decoded_attachment(F,a, &was_decoded))) {
goto clean;
}
if (!was_decoded) {
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmUnsupportedEncoding,
"Unsupported encoding! Decode manually!"));
if (attachment_fix_extension)
default_extension = format_string(FRM("encoded"));
} else if (attachment_fix_extension || check_type_pattern) {
struct scan_list *scanlist = NULL;
struct scan_list *Y;
int ch;
struct mime_types_item *found;
char * ext = NULL;
if (user_mimetypes_map)
scanlist = get_scan_list_by_type(user_mimetypes_map,a->TYPE);
if (system_mimetypes_map) {
struct scan_list * X = get_scan_list_by_type(system_mimetypes_map,
a->TYPE);
if (X) {
if (scanlist) {
append_scanlist(scanlist,X);
free_scan_list(&X);
} else
scanlist = X;
}
}
Y = get_scan_list_by_type(builtin_mimetypes_map,a->TYPE);
if (Y) {
if (scanlist) {
append_scanlist(scanlist,Y);
free_scan_list(&Y);
} else
scanlist = Y;
}
if (!scanlist) {
DPRINT(Debug,7,(&Debug,
"attach_save --- no scanlist\n"));
goto no_scan;
}
filter_scanlist(scanlist,a,filter_scanlist_OK);
if (! have_scanlist(scanlist)) {
DPRINT(Debug,7,(&Debug,
"attach_save --- empty scanlist\n"));
goto no_scan1;
}
while (EOF != (ch = getc(f_in))) {
int need_more = 0;
need_more = scanlist_need_more(scanlist,ch);
if (!need_more) {
DPRINT(Debug,9,(&Debug,
"attach_save: magic scan finished\n"));
break;
}
}
if (msgname) {
DPRINT(Debug,9,(&Debug,
"attach_save: filename %S\n",
msgname));
ext = give_extension(msgname);
}
if ( ext) {
DPRINT(Debug,9,(&Debug,
"attach_save: extension %s\n",ext));
found = loc_mime_type_from_scan_extension(scanlist,ext);
} else {
DPRINT(Debug,9,(&Debug,
"attach_save: No extension\n"));
found = loc_mime_type_from_scan(scanlist);
}
if (found && attachment_fix_extension) {
CONST char * ext1 = mime_type_to_extension(found);
if (ext1) {
DPRINT(Debug,9,(&Debug,
"attach_save: Fixed extension: %s\n",
ext1));
default_extension = format_string(FRM("%s"),
ext1);
}
}
if (!found) {
if (get_major_type_code(a->TYPE) == MIME_TYPE_APPLICATION &&
0 == istrcmp(get_subtype_name(a->TYPE),"octet-stream")) {
DPRINT(Debug,5,(&Debug,
"attach-save -- APPLICATION/octet-stream is unkonw/anonymous type\n"));
} else if (msgname)
lib_error(CATGETS(elm_msg_cat, MeSet, MeMiscMatchMessage1,
"Signature of %S do not match to type %s/%s"),
msgname,
get_major_type_name(a->TYPE),
get_subtype_name(a->TYPE));
else
lib_error(CATGETS(elm_msg_cat, MeSet, MeMiscMatchMessage2,
"Signature of this attachment do not match to type %s/%s"),
get_major_type_name(a->TYPE),
get_subtype_name(a->TYPE));
}
no_scan1:
free_scan_list(&scanlist);
no_scan:
rewind(f_in);
if (ext)
free(ext);
}
if (msgname)
free_string(&msgname);
code = file_browser(page,br,&savefile,word_save,
aview,default_extension,
CATGETS(elm_msg_cat, MeSet, MeToFile,
"To file: "));
if (!code) {
ClearLine(LINES-3);
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmMailNotSaved,
"Mail not saved."));
goto clean;
}
if (savefile)
free_string(&savefile);
if (default_extension)
free_string(&default_extension);
savefile = selection_name_dir(br);
br_flags = give_dir_flags(br);
DPRINT(Debug,4, (&Debug,
"*** %S have flags:%s%s%s%s%s%s%s%s\n",
savefile,
br_flags & BROWSER_NODIR ? " NODIR": "",
br_flags & BROWSER_NOFOLDER ? " NOFOLDER": "",
br_flags & BROWSER_MARKED ? " MARKED": "",
br_flags & BROWSER_MAILFILE ? " MAILFILE": "",
br_flags & BROWSER_SELECTED ? " SELECTED": "",
br_flags & BROWSER_EXIST ? " EXIST" : "",
br_flags & BROWSER_DIRPREFIX ? " DIRPREFIX" : "",
!br_flags ? " none" : ""));
if ((br_flags & BROWSER_EXIST) == 0) {
/* Create it now ... */
if (!create_selection_dir(br)) {
ClearLine(LINES-3);
goto clean;
}
} else {
/* Confirm overwrite */
char * msg_buffer = NULL;
char answer;
msg_buffer = elm_message(CATGETS(elm_msg_cat, ElmSet,
ElmConfirmFileOverwrite,
"Overwrite existing file `%S'? (%c/%c) "),
savefile,
*def_ans_yes, *def_ans_no);
answer = want_to(msg_buffer, *def_ans_no, LINES-3, 1,
page);
free(msg_buffer);
if (answer != *def_ans_yes) {
ClearLine(LINES-3);
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmMailNotSaved,
"Mail not saved."));
goto clean;
}
}
ClearLine(LINES-3);
if (!prepare_write_folder(br,&handle))
goto clean;
else {
out_state_t state_out;
charset_t charset_vector[2];
out_state_clear(&state_out, STATE_out_dir);
/* Needed by STATE_out_dir */
charset_vector[0] = RAW_BUFFER;
charset_vector[1] = NULL;
set_in_state_file(f_in,&state_in);
state_out.display_charset = charset_vector;
set_out_state_dir(br,handle, &state_out);
state_out.prefix = NULL;
state_out.displaying = 0;
if (!state_copy(&state_in,&state_out)) {
lib_error(CATGETS(elm_msg_cat, MeSet, MeDecodeFailedCopy,
"Failed to copy file when decoding."));
}
out_state_destroy(&state_out);
}
err = !end_write_folder(br,&handle);
if (err)
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmErrorSaving,
"Error saving file!"));
else
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmMailSaved,
"Mail saved."));
clean:
in_state_destroy(&state_in);
if (f_in)
close_attachment(F,f_in);
if (savefile)
free_string(&savefile);
free_dir(&br);
menu_trigger_redraw(LOC->prompt_page);
menu_trigger_redraw(LOC->menu_page);
return;
}
static int attach_info P_((mime_t *ptr,struct mailer_info *mailer_info,
int new));
static void attach_edit P_((mime_t *ptr, struct mailer_info *mailer_info));
static void attach_edit (ptr,mailer_info)
mime_t *ptr;
struct mailer_info *mailer_info;
{
int savetime;
struct stat sb;
char buf[STRING];
char *editor_val;
if (ptr->magic != MIME_magic)
mime_panic(__FILE__,__LINE__,"attach_edit",
"Bad magic number");
if (!ptr->pathname0)
return;
if (-1 == stat (ptr->pathname0, &sb)) {
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmCantStat,
"Can't stat file!"));
sleep_message();
return;
}
editor_val = give_dt_estr_as_str(&editor_e,"editor");
if (!editor_val ||
strlen(ptr->pathname0) + strlen(editor_val) > STRING-5)
return;
savetime = sb.st_mtime;
Raw(OFF);
elm_sfprintf (buf, sizeof buf,
FRM("%s %s"), editor_val, ptr->pathname0);
system_call (buf, 0, NULL);
Raw(ON);
if (stat (ptr->pathname0, &sb) == -1 || sb.st_mtime != savetime)
(void) attach_info (ptr,mailer_info,0); /* update the information on this attachment */
return;
}
static void attach_viewer P_((FILE *F,mime_t *a,
struct header_rec *hdr,
struct menu_context *page));
static void attach_viewer (F,a, hdr, page)
FILE *F;
mime_t *a;
struct header_rec *hdr;
struct menu_context *page;
{
char buf1[LONG_STRING];
struct header_rec tmp;
FILE *tmpfp = NULL;
struct stat sb;
int is_need_meta = 0;
/* The next line is required so that mime_t_clear() doesn't call
* mime_destroy() or free() on bad pointers
*/
header_zero(&tmp);
mime_t_clear (&tmp.mime_rec);
if (a->magic != MIME_magic)
mime_panic(__FILE__,__LINE__,"attach_viewer",
"Bad magic number");
/* So that metapager() doesn't try to do special handling */
tmp.status = MIME_MESSAGE; /* Now I test again MIME_MESSAGE
* - K E H <hurtta@dionysos.FMI.FI>
*/
tmp.header_charset = display_charset;
if (hdr)
tmp.override_charset = hdr->override_charset;
#ifdef USE_PGP
tmp.pgp = 0;
#endif
if (a->pathname0) {
menu_ClearScreen(page); /* Extra clear for mime_parse_routine ... */
if (can_open(a->pathname0,"r") != 0) {
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmErrorReadableUser,
"%S isn't readable by user!"),
a->dispname);
sleep_message();
return;
}
tmpfp = fopen (a->pathname0, "r");
if (! tmpfp) {
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmCouldOpenReading,
"Could not open file for reading!"));
sleep_message();
return;
}
tmp.mime_rec.TYPE = a->TYPE;
if (a->TYPE_opts) {
tmp.mime_rec.TYPE_opts = copy_mime_param(a->TYPE_opts);
}
tmp.mime_rec.mime_flags = a->mime_flags;
/* NOTPLAIN_need_metamail 0x01
NOTPLAIN_need_mailcap 0x02
NOTPLAIN_canuse_mailcap 0x04
*/
tmp.mime_rec.disposition = DISP_INLINE; /* Show it ! */
tmp.offset = tmp.mime_rec.offset = 0;
tmp.mime_rec.encoding = ENCODING_7BIT;
stat(a->pathname0, &sb);
tmp.content_length = tmp.mime_rec.length = sb.st_size;
mime_parse_routine(NULL,&tmp, tmpfp);
} else {
/* Make copy of mime structure: */
mime_t_copy(&(tmp.mime_rec),a);
tmp.mime_rec.disposition = DISP_INLINE; /* Show it ! */
tmp.offset = tmp.mime_rec.offset = a -> offset;
tmp.content_length = tmp.mime_rec.length = a->length;
#ifdef USE_PGP
if (hdr)
tmp.pgp = hdr->pgp;
#endif
}
/* This value is used for selecting external pager versus internal
* pager.
*/
if (tmp.lines < 1)
tmp.lines = tmp.content_length / 60;
/* there is nothing to display! */
if (tmp.mime_rec.length <= 0)
goto fail;
DPRINT(Debug,9,
(&Debug,"attach_viewer: Looking %p=%s/%s ...\n",
tmp.mime_rec.TYPE,
get_major_type_name(tmp.mime_rec.TYPE),
get_subtype_name(tmp.mime_rec.TYPE)));
/* mime_t_copy() is called copy_parser_data() so
mime_parser_parse() need not to be called
... however classification is not copied!!
*/
mime_classify_media(&(tmp.mime_rec),&tmp);
is_need_meta = need_meta(&tmp,0,0);
if (is_need_meta < 0) {
goto fail;
}
if (!is_need_meta) {
struct pager_page *PP = init_pager_page(NULL);
if (tmpfp)
metapager (tmpfp, &tmp, FALSE, 0,0, PP);
else if (F)
metapager (F, &tmp, FALSE, 0,0, PP);
exit_pager_page(&PP,page);
} else {
struct menu_context *cpage;
char * metamail_val =
give_dt_estr_as_str(&metamail_path_e, "metamail");
if (!metamail_val)
goto fail;
/* otherwise call metamail */
if (!a->pathname0) {
char tmpfile[STRING];
char copy_buf[VERY_LONG_STRING];
FILE *out;
out_state_t state_out;
char *tmp;
tmp = give_dt_estr_as_str(&temp_dir_e,"tmpdir");
if (!tmp)
goto fail;
elm_sfprintf (tmpfile, sizeof tmpfile,
FRM("%selm.%d"), tmp, getpid());
out = safeopen(tmpfile);
if (out == NULL) {
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmErrorCreatTempfile,
"Error creating tempfile %s"),
tmpfile);
sleep_message();
goto fail;
}
(void) elm_chown (tmpfile, userid, groupid);
out_state_clear(&state_out, STATE_out_file);
set_out_state_file(out,&state_out);
state_out.EOLN_is_CRLF = 0;
/* !! Metamail do not cope with CRLF */
/* copy the headers plus the message to a temp file */
fseek(F,a->begin_offset,SEEK_SET);
while (ftell(F) < a->offset + a->length) {
int len = mail_gets(copy_buf,sizeof copy_buf,F);
if (len <= 0)
break; /* Error ? */
/* Take care of CRLF => LF conversion (or
LF -> CRLF conversion)
-- metamail do not cope with CRLF
*/
state_convert_EOLN(copy_buf,&len,sizeof copy_buf,
&state_out);
state_put(copy_buf,len,&state_out);
}
out_state_destroy(&state_out);
fclose(out);
/* Option -z causes that metamail unlinks tempfile */
elm_sfprintf (buf1, sizeof buf1,
FRM("%s -m Elm -p -z %s"), metamail_val,tmpfile);
} else
/* This is the case when we are viewing attachments for an outgoing
* message.
*/
elm_sfprintf(buf1,sizeof buf1,
FRM("%s -m Elm -p -b -c %s/%s %s"),
metamail_val,
get_major_type_name(a->TYPE),
get_subtype_name(a->TYPE),
a->pathname0);
/* Option -z causes that metamail deletes input file */
cpage = Raw (OFF);
menu_ClearScreen(cpage);
printf ("Executing: %s\n", buf1);
system_call (buf1, SY_ENAB_SIGINT|SY_ENV_METAMAIL, NULL);
PressAnyKeyToContinue();
Raw (ON);
}
fail:
mime_t_clear (&(tmp.mime_rec));
if (tmpfp) {
fclose (tmpfp);
}
return;
}
/* Check initial attachments */
int Check_attachments()
{
if (attach_files.attachment_count > 0) {
int i;
/* this is not necessary correct ... */
struct mailer_info *mailer_info = get_mailer_info();
if (!mailer_info) {
/* mailer not available */
sleep_message();
return 0;
}
for (i = 0; i < attach_files.attachment_count; i++) {
int need_enc;
int is_text;
if (!attach_files.attach_files[i].dispname)
attach_files.attach_files[i].dispname =
new_string2(system_charset,
s2us(attach_files.attach_files[i].pathname0));
need_enc = attach_info (&(attach_files.attach_files[i]),
mailer_info,1);
if (need_enc < 0) {
return 0;
}
/* 7bit and 8bit are only allowed for line orienteed types */
/* But do not check attach_files.attach_files[i].encoding
agaist ENCODING_NONE, ENCODING_7BIT, ENCODING_8BIT
when sending
*/
is_text = give_text_type_code(attach_files.attach_files[i].
TYPE);
if (is_text < 0 && (attach_files.attach_files[i].encoding ==
ENCODING_QUOTED ||
attach_files.attach_files[i].encoding ==
ENCODING_BASE64)) {
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmStrucredNoEncoding,
"%S: Structured types don't allow encoding of data."),
attach_files.attach_files[i].dispname);
sleep_message();
return 0;
}
}
free_mailer_info(&mailer_info);
}
return 1;
}
/* Make initial attachment */
int Attach_it(pathname)
char *pathname;
{
mime_t tmp;
if (access(pathname,READ_ACCESS) < 0) {
int err = errno;
lib_error(FRM("%.45s: %.33s"),
pathname,error_description(err));
return 0;
}
mime_t_zero(&tmp);
tmp.pathname0 = safe_strdup(pathname);
tmp.dispname = NULL; /* Filled later */
/* Default disposition for attachments: attachment */
tmp.disposition = DISP_ATTACH;
add_Attachments(&attach_files,&tmp);
return 1;
}
static void forgot_previous P_((mime_t *att));
static void forgot_previous(att)
mime_t *att;
{
if (att->pathname0) {
if (att->unlink) {
if (unlink(att->pathname0) == 0) {
DPRINT(Debug,5, (&Debug,
"attach_modify: Unlinking cache %s\n",
att->pathname0));
}
}
free (att->pathname0);
att->pathname0 = NULL;
}
if (att->dispname)
free_string(& (att->dispname));
}
static int attach_modify P_((mime_t *att, int new,
struct mailer_info *mailer_info,
struct AliasView *aview));
static int attach_modify (att, new, mailer_info,aview)
mime_t *att;
int new;
struct mailer_info *mailer_info;
struct AliasView *aview;
{
int ret_value = FALSE;
int update = TRUE, prompt = TRUE, need_enc = 0;
int is_text = -1, ch = '\0';
struct folder_browser * br = new_browser(selection_file);
struct menu_context *page = new_menu_context();
if (att->magic != MIME_magic)
mime_panic(__FILE__,__LINE__,"attach_modify",
"Bad magic number");
DPRINT(Debug,6, (&Debug, "attach_modify: att=%p, new=%d\n",att,new));
if (new) {
/* Default disposition for attachments: attachment */
att->disposition = DISP_ATTACH;
/* force a prompt for a filename */
prompt = FALSE;
ch = 'f';
att->unlink = 0;
} else {
need_enc = attach_info (att, mailer_info,0);
if (need_enc < 0) {
prompt = FALSE;
ch = 'f';
}
}
main_loop:
/* 1 if is text type (true)
* 0 if not text type
* -1 if can't be encoded (ie structured) Message/ or Multpart/
*/
/* 7bit and 8bit are only allowed for line orienteed types */
/* But do not check attach_files.attach_files[i].encoding
agaist ENCODING_NONE, ENCODING_7BIT, ENCODING_8BIT
when sending
*/
is_text = give_text_type_code(att->TYPE);
for (;;) {
int LINES, COLUMNS;
resize_mark:
menu_get_sizes(page,&LINES,&COLUMNS);
if (menu_resized(page)) {
menu_get_sizes(page,&LINES,&COLUMNS);
update++;
} else if (menu_need_redraw(page))
update++;
if (update) {
struct string * Title =
format_string(CATGETS(elm_msg_cat, MeSet, MeAttachTitle,
"Attachment Configuration"));
int add = 0;
int Width = COLUMNS - 16;
if (Width < 40)
Width = 40;
menu_ClearScreen(page);
print_center(1,Title);
free_string(&Title);
if (att->unlink == 2)
PutLineX(3, 0,
CATGETS(elm_msg_cat, MeSet, MeAttachFilenameS,
"Filename : %.*S"),
Width,att->dispname);
else if (att->dispname)
PutLineX(3, 0,
CATGETS(elm_msg_cat, MeSet, MeAttachFilename3,
"F)ilename : %.*S"),
Width,att->dispname);
else
PutLineX(3, 0,
CATGETS(elm_msg_cat, MeSet, MeAttachFilename0,
"F)ilename : <none>"));
if (!att->description)
att->description = new_string(display_charset);
PutLineX(4, 0,
CATGETS(elm_msg_cat, MeSet, MeAttachDescription,
"D)escription : %.*S"),
Width, att->description);
PutLineX(5, 0,
CATGETS(elm_msg_cat, MeSet, MeAttachContentType,
"Content-T)ype : %.15s/%.30s%s"),
get_major_type_name(att->TYPE),
get_subtype_name(att->TYPE),
att->TYPE_opts ? ";" : "");
if (att->TYPE_opts) {
struct string * X = show_mime_params(att->TYPE_opts);
if (X) {
PutLineX(6+add, 28, FRM("%S"),X);
add++;
free_string(&X);
}
}
PutLineX(6+add, 0,
CATGETS(elm_msg_cat, MeSet, MeAttachContentTE,
"Content-transfer-E)ncoding: %s"),
ENCODING(att->encoding));
PutLineX(7+add, 0,
CATGETS(elm_msg_cat, MeSet, MeAttachContentTE,
"Content-disP)osition : %.15s%s"),
DISPOSITION(att->disposition),
att->DISPOSITION_opts ? ";" : "");
if (att->DISPOSITION_opts) {
struct string * X = show_mime_params(att->DISPOSITION_opts);
if (X) {
PutLineX(8+add, 28, FRM("%S"), X);
add++;
free_string(&X);
}
}
if (is_text < 0)
PutLineX(9+add, 0,
CATGETS(elm_msg_cat, MeSet, MeAttachContentCRLF1,
"CRLF-conversions : structured (direct content-encoding not allowed)"));
else if (is_text)
PutLineX(9+add, 0,
CATGETS(elm_msg_cat, MeSet, MeAttachContentCRLF2,
"CRLF-conversions : Text (line orienteed, convert LF <-> CRLF)"));
else
PutLineX(9+add, 0,
CATGETS(elm_msg_cat, MeSet, MeAttachContentCRLF3,
"CRLF-conversions : Binary (no conversions)"));
update = FALSE;
show_last_error();
}
if (prompt) {
menu_PutLineX (page,
LINES-3, 0,
CATGETS(elm_msg_cat, MeSet, MeAttachEnter1,
"Enter letter or RETURN to quit: "));
menu_CleartoEOS(page);
ch = menu_ReadCh(page,REDRAW_MARK|READCH_resize|READCH_sig_char);
clear_error();
}
if (ch == '\n' || ch == 'q' || ch == 'Q' || ch == 'x' || ch == 'X') {
ret_value = TRUE;
goto cleanup;
} else if (ch == RESIZE_MARK) {
DPRINT(Debug,4,(&Debug,
" ... resizing\n"));
goto resize_mark;
} else if (ch == ctrl('L') || ch == REDRAW_MARK)
update = TRUE;
else if (ch == TERMCH_interrupt_char)
goto cleanup;
else if (ch == 'f' || ch == 'F') {
struct string * tmpname = NULL;
int old_is_text = is_text;
int loop_count = 0;
int use_attachment_dir = 0;
char * attachment_dir_val =
give_dt_estr_as_str(&attachment_dir_e,
"attachment-dir");
int code;
if (att->unlink == 2) {
lib_error(CATGETS(elm_msg_cat, ElmSet,
ElmCantChangeFilename,
"You can't change filename!"));
continue;
}
if (attachment_dir_val &&
0 == access(attachment_dir_val,ACCESS_EXISTS)) {
DPRINT(Debug,15,(&Debug,
"attach_modify: attachment-dir=%s set and exists\n",
attachment_dir_val));
use_attachment_dir++;
}
if (!att->dispname) {
DPRINT(Debug,15,(&Debug,
"attach_modify: No dispname\n"));
} else
tmpname = dup_string(att->dispname);
if (!tmpname && use_attachment_dir)
tmpname = format_string(FRM("{doc}/"));
prompt = TRUE;
code = file_browser(page,br,&tmpname,word_read,
aview,
NULL,
CATGETS(elm_msg_cat, MeSet,
MeAttachEnterFilename,
"Filename: "));
if (!code) {
if (!tmpname || string_len(tmpname) == 0) {
if (tmpname)
free_string(&tmpname);
DPRINT(Debug,5, (&Debug,
"attach_modify: filename not given"));
if (att->pathname0) {
DPRINT(Debug,5, (&Debug, " pathname0=%s",
att->pathname0));
}
if (att->dispname) {
DPRINT(Debug,5, (&Debug, " dispname=%S",
att->dispname));
}
DPRINT(Debug,5, (&Debug, "\n"));
if (new) {
ret_value = FALSE;
goto cleanup;
} else
continue;
}
attach_failure:
if (tmpname)
free_string(&tmpname);
update = TRUE;
if (att->pathname0) {
if (att->unlink) {
if (unlink(att->pathname0) == 0) {
DPRINT(Debug,5,
(&Debug,
"attach_modify: Unlinking cache %s\n",
att->pathname0));
}
}
free (att->pathname0);
att->pathname0 = NULL;
}
if (new) {
ret_value = FALSE;
goto cleanup;
} else
continue;
}
update = TRUE;
do {
int br_flags = 0;
int iscopy;
old_is_text = is_text;
if (tmpname)
free_string(&tmpname);
tmpname = selection_name_dir(br);
br_flags = give_dir_flags(br);
DPRINT(Debug,4, (&Debug,
"*** %S have flags:%s%s%s%s%s%s%s%s\n",
tmpname,
br_flags & BROWSER_NODIR ? " NODIR": "",
br_flags & BROWSER_NOFOLDER ? " NOFOLDER": "",
br_flags & BROWSER_MARKED ? " MARKED": "",
br_flags & BROWSER_MAILFILE ? " MAILFILE": "",
br_flags & BROWSER_SELECTED ? " SELECTED": "",
br_flags & BROWSER_EXIST ? " EXIST" : "",
br_flags & BROWSER_DIRPREFIX ? " DIRPREFIX" : "",
!br_flags ? " none" : ""));
if ((br_flags & BROWSER_EXIST) == 0) {
lib_error(CATGETS(elm_msg_cat, MeSet, MeAttachNotExist,
"File %S not exist"),
tmpname);
goto attach_failure;
}
/* Now forgot previous file ....
forgot_previous: clears att->dispname
and att->pathname0
*/
forgot_previous(att);
att->dispname = tmpname;
tmpname = NULL;
iscopy = att->unlink;
if (!dir_make_ref(br, & (att->pathname0), & iscopy,
is_text)) {
att->unlink = iscopy;
goto attach_failure;
}
att->unlink = iscopy;
/* Set some information about this attachment */
need_enc = attach_info (att, mailer_info,1);
if (need_enc < 0)
continue;
/* 1 if is text type (true)
* 0 if not text type
* -1 if can't be encoded (ie structured) Message/ or Multpart/
*/
/* 7bit and 8bit are only allowed for line orienteed types */
/* But do not check attach_files.attach_files[i].encoding
agaist ENCODING_NONE, ENCODING_7BIT, ENCODING_8BIT
when sending
*/
is_text = give_text_type_code(att->TYPE);
if (old_is_text != is_text) {
DPRINT(Debug,1,
(&Debug,
"attach_modify: OPPS! CLRF encoding changed...\n"));
}
} while (old_is_text != is_text && loop_count++ < 5);
if (is_text > 0 && (need_enc & HAVE_BINARY)) {
lib_error(CATGETS(elm_msg_cat, ElmSet,
ElmWarningBINARY,
"Warning: BINARY data? Check Content-Type!"));
}
if (is_text < 0 && (att->encoding == ENCODING_QUOTED ||
att->encoding == ENCODING_BASE64)) {
/* Reconsider encoding ... */
ch = 'e';
prompt = FALSE;
update = TRUE;
lib_error(CATGETS(elm_msg_cat, ElmSet,
ElmStructuredNoencoding,
"%S: Structured types don't allow encoding of data."),
att->dispname);
sleep_message();
break;
}
/* now let the user do what they want */
if (new)
prompt = TRUE;
}
else if (ch == 'd' || ch == 'D') {
int code = optionally_enter2(page,
&(att->description),
LINES-3, 0,
OE_APPEND_CURRENT|OE_REDRAW_MARK|
OE_SIG_CHAR /* Ctrl-C */,
CATGETS(elm_msg_cat, MeSet,
MeAttachEnterDescription,
"Description: "));
prompt = TRUE;
if (REDRAW_MARK == code) {
update = TRUE;
prompt = FALSE;
continue;
}
if (code != 0)
continue;
update = TRUE;
}
else if (ch == 't' || ch == 'T') {
int old_is_text = is_text;
int loop_count = 0;
int code;
struct string *buf1 = NULL;
char **X;
prompt = TRUE;
if (att->TYPE_opts) {
struct string *buf2 = NULL;
buf2 = show_mime_params(att->TYPE_opts);
if (buf2) {
buf1 = format_string(FRM("%.15s/%.30s; %S"),
get_major_type_name(att->TYPE),
get_subtype_name(att->TYPE),
buf2);
free_string(&buf2);
} else
buf1 = format_string(FRM("%.15s/%.30s"),
get_major_type_name(att->TYPE),
get_subtype_name(att->TYPE));
} else
buf1 = format_string(FRM("%.15s/%.30s"),
get_major_type_name(att->TYPE),
get_subtype_name(att->TYPE));
code = optionally_enter2(page,&buf1,
LINES-3, 0,
OE_APPEND_CURRENT|
OE_REDRAW_MARK|OE_SIG_CHAR /* Ctrl-C */,
CATGETS(elm_msg_cat, MeSet,
MeAttachEnterContentType,
"Content-Type: "));
if (REDRAW_MARK == code) {
update = TRUE;
prompt = FALSE;
if (buf1)
free_string(&buf1);
continue;
}
if (0 != code) {
if (buf1)
free_string(&buf1);
continue;
}
{
int mp = give_dt_enumerate_as_int(&mime_parameters);
/* 0 == plain
1 == encoded
2 == ascii-and-encoded
*/
switch (mp) {
case 0:
X = split_mime_params(& (att->TYPE_opts),buf1,0,1);
break;
case 1:
X = split_mime_params(& (att->TYPE_opts),buf1,0,0);
break;
default:
X = split_mime_params(& (att->TYPE_opts),buf1,
MAX_COMPAT_LEN,0);
break;
}
}
free_string(&buf1);
if (X) {
media_type_t T = NULL;
if (X[0] &&
X[1] && 0 == strcmp(X[1],"/") &&
X[2])
T = give_media_type(X[0],X[2],1);
if (T)
att->TYPE = T;
free_rfc822tokenized(X);
}
if (get_major_type_code(att->TYPE) == MIME_TYPE_TEXT &&
(need_enc & HAVE_8BIT) &&
!(get_mime_param_compat(att->TYPE_opts,"charset")) &&
display_charset->MIME_name)
mime_params_add_compat(& (att->TYPE_opts),
"charset", display_charset->MIME_name);
do {
int iscopy;
old_is_text = is_text;
/* 1 if is text type (true)
* 0 if not text type
* -1 if can't be encoded (ie structured) Message/ or Multpart/
*/
/* 7bit and 8bit are only allowed for line orienteed types */
/* But do not check attach_files.attach_files[i].encoding
agaist ENCODING_NONE, ENCODING_7BIT, ENCODING_8BIT
when sending
*/
is_text = give_text_type_code(att->TYPE);
if (is_text == 0 &&
(att->encoding == ENCODING_7BIT ||
att->encoding == ENCODING_8BIT))
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmWarningEncoding,
"%s is allowed only for line orienteed types -- check encoding"),
ENCODING(att->encoding));
/* We reload file if it is user suplied */
if (old_is_text != is_text && att->dispname) {
struct string *XX = att->dispname;
/* forgot_previous() frees att->dispname */
att->dispname = NULL;
DPRINT(Debug,1,
(&Debug,
"attach_modify: OPPS! CLRF encoding changed...\n"));
forgot_previous(att);
if (!select_dir_item(br,&XX)) {
ch = 'f';
prompt = FALSE;
free_string(&XX);
goto main_loop;
}
iscopy = att->unlink;
if (!dir_make_ref(br, & (att->pathname0), & iscopy,
is_text)) {
ch = 'f';
prompt = FALSE;
att->unlink = iscopy;
free_string(&XX);
goto main_loop;
}
att->dispname = XX;
att->unlink = iscopy;
/* Set some information about this attachment */
need_enc = attach_info (att, mailer_info,0);
if (need_enc < 0) {
ch = 'f';
prompt = FALSE;
goto main_loop;
}
}
} while (old_is_text != is_text && loop_count++ < 5 &&
att->dispname);
update = TRUE;
if (is_text < 0 && (att->encoding == ENCODING_QUOTED ||
att->encoding == ENCODING_BASE64)) {
/* Reconsider encoding ... */
ch = 'e';
prompt = FALSE;
lib_error(CATGETS(elm_msg_cat, ElmSet,
ElmStructuredNoencoding,
"%S: Structured types don't allow encoding of data."),
att->dispname);
sleep_message();
}
}
else if (ch == 'p' || ch == 'P') {
int code;
struct string *buf1 = NULL;
char **X;
prompt = TRUE;
if (att->DISPOSITION_opts) {
struct string *buf2 = NULL;
buf2 = show_mime_params(att->DISPOSITION_opts);
if (buf2) {
buf1 = format_string(FRM("%.30s; %S"),
DISPOSITION(att->disposition),
buf2);
free_string(&buf2);
} else
buf1 = format_string(FRM("%.30s"),
DISPOSITION(att->disposition));
} else
buf1 = format_string(FRM("%.30s"),
DISPOSITION(att->disposition));
code = optionally_enter2(page,&buf1,
LINES-3, 0,
OE_APPEND_CURRENT|
OE_REDRAW_MARK|OE_SIG_CHAR /* Ctrl-C */,
CATGETS(elm_msg_cat, MeSet,
MeAttachEnterContentDisp,
"Content-Disposition: "));
if (REDRAW_MARK == code) {
update = TRUE;
prompt = FALSE;
if (buf1)
free_string(&buf1);
continue;
}
if (0 != code) {
if (buf1)
free_string(&buf1);
continue;
}
{
int mp = give_dt_enumerate_as_int(&mime_parameters);
/* 0 == plain
1 == encoded
2 == ascii-and-encoded
*/
switch (mp) {
case 0:
X = split_mime_params(& (att->DISPOSITION_opts),buf1, 0,1);
break;
case 1:
X = split_mime_params(& (att->DISPOSITION_opts),buf1, 0,0);
break;
default:
X = split_mime_params(& (att->DISPOSITION_opts),buf1,
MAX_COMPAT_LEN,0);
}
}
free_string(&buf1);
if (X) {
media_type_t T = NULL;
if (X[0]) {
if (istrcmp (X[0], "inline") != 0)
att->disposition = DISP_ATTACH;
else
att->disposition = DISP_INLINE;
}
free_rfc822tokenized(X);
}
update = TRUE;
}
else if (ch == 'e' || ch == 'E') {
int oldenc = att->encoding;
prompt = TRUE;
PutLineX (LINES-3, 0,
CATGETS(elm_msg_cat, MeSet, MeAttachEnterContentTE,
"Content-Transfer-Encoding: "));
/* !!! */
Centerline (LINES-2,
"<SPACE> for next value, <RETURN> to accept.",
page);
for (;;) {
DPRINT(Debug,9, (&Debug,
"... changing content-transfer-encoding, need_enc=%d, enc=%s\n",
need_enc,ENCODING(att->encoding)));
menu_MoveCursor (page,
LINES-3, 27);
menu_CleartoEOLN(page);
#define NEXT_ENCODING { \
att->encoding++; \
if (att->encoding > 5) att->encoding = 1; \
continue; \
}
if (!mailer_info ||
!query_mailer_info(mailer_info,MI_HAVE_8BITMIME)) {
int an = give_dt_enumerate_as_int(&allow_no_encoding);
DPRINT(Debug,8,(&Debug,
"mailer does not support 8BITMIME\n"));
if (an < 1) {
if (att->encoding == ENCODING_8BIT) {
/* Mailer won't support ! */
/* TRY next encosing instead */
NEXT_ENCODING;
}
}
}
if (!mailer_info ||
!query_mailer_info(mailer_info,MI_HAVE_BINARYMIME)) {
int an = give_dt_enumerate_as_int(&allow_no_encoding);
DPRINT(Debug,8,(&Debug,
"mailer does not support BINARYMIME\n"));
if (an < 2) {
if (att->encoding == ENCODING_BINARY) {
/* Mailer won't support ! */
/* TRY next encoding instead */
NEXT_ENCODING;
}
}
}
/* Don't allow 7bit if the file contains 8bit chars...
* 7bit encoding is allowed if file includes control
* characters
*/
if (att->encoding == ENCODING_7BIT && (need_enc & HAVE_8BIT)) {
NEXT_ENCODING;
}
/* Don't allow 7bit or 8bit if the file required binary
* encoding according of Mime Standard.
*/
if ((att->encoding == ENCODING_7BIT ||
att->encoding == ENCODING_8BIT)
&& (need_enc & HAVE_BINARY)) {
NEXT_ENCODING;
}
/* Don't allow encoding for Multipart/ and Message/
* See Mime Standard. Be carefull that don't create
* infinitive loop! */
if (is_text < 0) {
static int again = 0; /* Prevent looping */
if (att->encoding == ENCODING_QUOTED ||
att->encoding == ENCODING_BASE64) {
if (again == att->encoding) {
lib_error(CATGETS(elm_msg_cat, ElmSet,
ElmStructuredLeaf,
"Structured types must be encoded in leaf type!"));
sleep_message();
/* prompt for new content-type */
prompt = FALSE;
ch = 't';
break;
} else {
if (!again)
again = att->encoding;
NEXT_ENCODING;
}
} else
again = 0;
}
menu_Write_to_screen (page,
FRM("%s"),ENCODING(att->encoding));
ch = menu_ReadCh(page,REDRAW_MARK|READCH_sig_char);
if (ch == '\n')
break;
else if (ch == TERMCH_interrupt_char) {
att->encoding = oldenc;
update = TRUE;
break;
} else if (ch == ' ') {
NEXT_ENCODING;
}
else if (ch == REDRAW_MARK) {
update = TRUE;
prompt = FALSE;
ch = 'e';
break;
}
}
#undef NEXT_ENCODING
ClearLine (LINES-2);
/* 1 if is text type (true)
* 0 if not text type
* -1 if can't be encoded (ie structured) Message/ or Multpart/
*/
is_text = give_text_type_code(att->TYPE);
if (is_text == 0 &&
(att->encoding == ENCODING_7BIT ||
att->encoding == ENCODING_8BIT))
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmWarningEncoding,
"%s is allowed only for line orienteed types -- check encoding"),
ENCODING(att->encoding));
update = TRUE;
}
else
lib_error(CATGETS(elm_msg_cat, ElmSet,
ElmUnknownCommand2,
"Unknown command."));
}
ret_value = FALSE;
cleanup:
if (br)
free_dir(&br);
erase_menu_context(&page);
DPRINT(Debug,5,
(&Debug,"attach_modify=%d\n",ret_value));
return ret_value;
}
char * compat_filename(orig,ok)
char * orig;
int *ok;
{
char * buf = safe_malloc(MAX_COMPAT_LEN+2);
char *x;
char *p;
*ok = 1;
for (p = buf, x=orig; *x; p++, x++) {
*p = *x;
if (p-buf > MAX_COMPAT_LEN) {
*ok = 0;
break;
}
if (!isascii(*p) || iscntrl(*p)) {
*ok = 0;
*p = '_';
}
}
*p = '\0';
return buf;
}
static void mime_add_name P_((mime_t *ptr));
static void mime_add_name(ptr)
mime_t *ptr;
{
char * compat = NULL;
int was_ok = 1;
char * p;
int mp = give_dt_enumerate_as_int(&mime_parameters);
/* 0 == plain
1 == encoded
2 == ascii-and-encoded
*/
int have_encoded = 0;
if (ptr->magic != MIME_magic)
mime_panic(__FILE__,__LINE__,"mime_add_name",
"Bad magic number");
DPRINT(Debug,3, (&Debug, "mime_add_name: pathname=%s\n",
ptr->pathname0));
if (ptr->magic != MIME_magic)
mime_panic(__FILE__,__LINE__,"mime_guess_content_type",
"Bad magic number");
/* Set the "filename" field for content-disposition */
p = strrchr (ptr->pathname0, '/');
if (p)
p++;
else
p = ptr->pathname0;
compat = compat_filename(p,&was_ok);
/* Assurance */
if (ptr->DISPOSITION_opts)
free_mime_param (& (ptr->DISPOSITION_opts));
if (mp > 0 &&
(!was_ok || !can_ascii_string(ptr->dispname))) {
struct string *p1 = pick_name(ptr->dispname);
if (p1) {
mime_params_add(& (ptr->DISPOSITION_opts),"filename", p1);
free_string(&p1);
have_encoded ++;
}
}
if (0 == mp ||
2 == mp ||
! have_encoded) {
mime_params_add_compat(& (ptr->DISPOSITION_opts),
"filename", compat);
free(compat); compat = NULL;
}
}
static void set_mime_type P_((mime_t *ptr,struct mime_types_item *XX));
static void set_mime_type(ptr,XX)
mime_t *ptr;
struct mime_types_item *XX;
{
charset_t CS = NULL;
CONST char * params = mime_type_to_params(XX,&CS);
if (ptr->TYPE_opts) {
free_mime_param(&(ptr->TYPE_opts));
}
ptr->TYPE = mime_type_to_media_type(XX);
if (params)
ptr->TYPE_opts = parse_mime_param("Content-Type",
params, CS,
NULL);
}
static int mime_guess_content_type1 P_((mime_t *ptr, struct scan_list *list));
static int mime_guess_content_type1 (ptr, list)
mime_t *ptr;
struct scan_list *list;
{
struct mime_types_item *XX = loc_mime_type_from_scan(list);
if (XX) {
set_mime_type(ptr,XX);
DPRINT(Debug,3,
(&Debug,
"mime_guess_content_type1: scanned as \"%s/%s\"\n",
get_major_type_name(ptr->TYPE),
get_subtype_name(ptr->TYPE)));
return 1;
}
return 0;
}
static void mime_guess_content_type P_((mime_t *ptr, char *ext));
static void mime_guess_content_type (ptr, ext)
mime_t *ptr;
char *ext;
{
/* This routine tries to guess the content-type of an attachment by looking
* at the suffix of ptr->pathname. It first looks to see if it can find
* an entry in ~/.elm/mime.types, then in "system_mime_types", and failing
* that, to a small list of builtin definitions.
*/
int i, found = FALSE;
for (i = 0; i < 3; i++) {
struct mime_types_item * mime_types_list = NULL;
struct mime_types_item * XX;
DPRINT(Debug,3,
(&Debug,
"mime_guess_content_type: searching \"%s\", i=%d\n",
ext,i));
if (i == 0) {
/* First try the user's mime.types file */
mime_types_list = user_mimetypes_map;
if (!mime_types_list)
continue;
}
else if (i == 1) {
/* If it wasn't there, try the system file... */
mime_types_list = system_mimetypes_map;
if (!mime_types_list)
continue;
}
else {
/* Couldn't find user or system mime.types file,
* use these defaults...
*/
mime_types_list = builtin_mimetypes_map;
}
XX = loc_mime_type(mime_types_list,ext);
if (XX) {
set_mime_type(ptr,XX);
if (i < 2) {
DPRINT(Debug,3,
(&Debug,
"mime_guess_content_type: user defined \"%s\" as \"%s/%s\"\n",
ext, get_major_type_name(ptr->TYPE),
get_subtype_name(ptr->TYPE)));
} else {
DPRINT(Debug,3,
(&Debug,
"mime_guess_content_type: built-in default \"%s\" as \"%s/%s\"\n",
ext, get_major_type_name(ptr->TYPE),
get_subtype_name(ptr->TYPE)));
}
break;
}
}
}
static int attach_info (ptr,mailer_info,new)
mime_t *ptr;
struct mailer_info *mailer_info;
int new;
{
struct stat sb;
FILE *fp;
int need_enc;
char *ext = NULL;
struct scan_list * scanlist = NULL;
if (ptr->magic != MIME_magic)
mime_panic(__FILE__,__LINE__,"attach_info",
"Bad magic number");
if (stat (ptr->pathname0, &sb) == -1) {
if (errno == ENOENT)
lib_error(CATGETS(elm_msg_cat, ElmSet,
ElmFileNotExistS,
"That file %S does not exist!"),
ptr->dispname);
else
lib_error(CATGETS(elm_msg_cat, ElmSet,
ElmCantStatFileS,
"Could not stat file %S!"),
ptr->dispname);
sleep_message();
return (-1);
}
ptr->length = sb.st_size;
if (can_open(ptr->pathname0,"r") != 0) {
lib_error(CATGETS(elm_msg_cat, ElmSet,
ElmNotReadableByUserS,
"%S isn't readable by user!"),
ptr->dispname);
sleep_message();
return (-1);
}
/* Figure out what the default encoding is... */
lib_transient(CATGETS(elm_msg_cat, ElmSet,
ElmCheckingEncodingS,
"Checking %S..."),
ptr->dispname);
fp = fopen (ptr->pathname0, "r");
if (!fp) {
lib_error(CATGETS(elm_msg_cat, ElmSet,
ElmCantOpenFileS,
"Can't open %S!"),
ptr->dispname);
sleep_message();
return -1;
}
if (new)
mime_add_name(ptr);
ext = strrchr (ptr->pathname0, '.');
if (ext)
ext++;
if (new) {
struct scan_list * Y;
if (user_mimetypes_map)
scanlist = get_scan_list(user_mimetypes_map,ext);
if (system_mimetypes_map) {
struct scan_list * X = get_scan_list(system_mimetypes_map,ext);
if (X) {
if (scanlist) {
append_scanlist(scanlist,X);
free_scan_list(&X);
} else
scanlist = X;
}
}
Y = get_scan_list(builtin_mimetypes_map,ext);
if (Y) {
if (scanlist) {
append_scanlist(scanlist,Y);
free_scan_list(&Y);
} else
scanlist = Y;
}
}
need_enc = needs_encoding (fp,scanlist);
if (need_enc & HAVE_CTRL) {
ptr->encoding = (need_enc & HAVE_BINARY)
? ENCODING_BASE64 : ENCODING_QUOTED;
if (new && (need_enc & HAVE_BINARY)) {
/* Set default to be application/octet-stream instead of
text/plain
*/
ptr->TYPE = give_media_type2(MIME_TYPE_APPLICATION,
"octet-stream", 1);
}
} else if (need_enc & HAVE_BINARY) {
/* HAVE_BINARY, but not HAVE_CTRL so that have long lines! */
if(mailer_info &&
query_mailer_info(mailer_info,MI_HAVE_BINARYMIME)) {
DPRINT(Debug,8,(&Debug,"mailer supports BINARYMIME\n"));
ptr->encoding = ENCODING_BINARY;
} else
ptr->encoding = ENCODING_QUOTED;
}
else if (need_enc & HAVE_8BIT) {
if(mailer_info &&
query_mailer_info(mailer_info,MI_HAVE_8BITMIME)) {
DPRINT(Debug,8,(&Debug,"mailer supports 8BITMIME\n"));
ptr->encoding = ENCODING_8BIT;
}
else
ptr->encoding = ENCODING_QUOTED;
}
fclose (fp);
clear_error(); /* Remove reading ... -message */
if (new) {
int found = 0;
/* Try to guess the content type of the data by the
scanned context (and filename extension) */
if (scanlist)
found = mime_guess_content_type1 (ptr,scanlist);
/* Try to guess the content type of the data by the
filename extension */
if (!found && ext)
mime_guess_content_type (ptr,ext);
if (get_major_type_code(ptr->TYPE) == MIME_TYPE_TEXT &&
(need_enc & HAVE_8BIT)) {
CONST char *cs;
cs = get_mime_param_compat(ptr->TYPE_opts,"charset");
if (!cs &&
display_charset && display_charset->MIME_name)
mime_params_add_compat(& (ptr->TYPE_opts),
"charset", display_charset->MIME_name);
}
}
if (scanlist)
free_scan_list(&scanlist);
DPRINT(Debug,3, (&Debug,
"attach_info: need_enc=%d, encoding=%d, pathname0=%s, type=%s/%s\n",
need_enc,ptr->encoding,ptr->pathname0,
get_major_type_name(ptr->TYPE),
get_subtype_name(ptr->TYPE)));
return (need_enc);
}
struct attach_structure {
int attachments_index; /* -1 if not on attachments list */
mime_t * current_node;
struct attach_structure *subnodes;
int subnodes_len;
int display_index;
int display_depth;
};
static void attach_header P_((struct attach_structure *S, int is_cur,
int use_desc, int offset,
struct menu_context *page));
static void attach_header (S, is_cur, use_desc, offset, page)
struct attach_structure *S;
int is_cur, offset, use_desc;
struct menu_context *page;
{
mime_t * mt = S -> current_node;
int row,col;
int i;
/* Displays a header for a menu for the specified attachment. */
char *Encoding = "???";
int x = S->display_depth;
int Width;
int LINES, COLUMNS;
menu_get_sizes(page, &LINES, &COLUMNS);
Width = COLUMNS;
Encoding = ENCODING(mt->encoding);
if (is_cur && has_highlighting && ! arrow_cursor)
menu_StartXX(page,pg_INVERSE);
if (is_cur && arrow_cursor) {
menu_PutLine0 (page,offset, 0, "->");
} else
menu_PutLine0 (page,offset, 0, " ");
menu_CleartoEOLN(page);
if (x < 0)
goto out;
menu_Write_to_screen(page,FRM("%2d"),S->display_index);
/* display the header value */
menu_GetXYLocation(page,&row, &col);
if (row != offset)
goto out;
menu_Writechar(page,' ');
col++;
for (i = 0; i < x && i < 5; i++) {
if (i < x-1) {
menu_Writechar(page,' ');
menu_Writechar(page,' ');
col += 2;
} else {
menu_Writechar(page,'|');
if (0 == S->subnodes_len &&
S->current_node->parser_data &&
mime_parser_subparts(S->current_node->parser_data) > 0)
menu_Writechar(page,'*');
else
menu_Writechar(page,'-');
col += 2;
}
}
x = Width - 46 - col;
if (x < 1)
goto out;
if (use_desc && mt->description)
menu_Write_to_screen(page,
FRM("%-*.*S (%d) "),
x,x,
mt->description,
mt->length);
else if (mt->dispname)
menu_Write_to_screen(page,
FRM("%-*.*S (%d) "),
x,x,
mt->dispname,
mt->length);
else
menu_Write_to_screen(page,
FRM("%-*.*s (%d) "),
x,x,
"",
mt->length);
menu_GetXYLocation(page,&row, &col);
if (row != offset)
goto out;
if (mt->length < 10) {
menu_Writechar(page,' ');
col++;
}
if (mt->length < 100) {
menu_Writechar(page,' ');
col++;
}
if (mt->length < 1000) {
menu_Writechar(page,' ');
col++;
}
x = Width -col;
if (x > 45)
x = 45;
x /= 3;
if (x < 1)
goto out;
menu_Write_to_screen(page,
FRM("%.*s/%.*s"),
x,
get_major_type_name(mt->TYPE),
2*x,
get_subtype_name(mt->TYPE));
menu_GetXYLocation(page,
&row, &col);
if (row != offset)
goto out;
if (col + strlen(Encoding) +3 >= Width) {
if (Width-col-7 < 1)
goto out;
menu_PutLineX(page,
row, col+1, FRM("%.*s..."),
Width-col-7,Encoding);
} else {
x = Width - strlen(Encoding) -3;
while (col < x) {
menu_Writechar(page,' ');
col++;
}
menu_PutLine0(page,
row, x, Encoding);
}
out:
if (is_cur && has_highlighting && ! arrow_cursor)
menu_EndXX(page,pg_INVERSE);
}
static void write_num P_((int num, int is_cur, int offset,
struct menu_context *page));
static void write_num(num, is_cur, offset,page)
int num, is_cur,offset;
struct menu_context *page;
{
char buf[10];
elm_sfprintf (buf,sizeof buf,
FRM("%4d"),num);
if (is_cur) {
buf[0] = '-';
buf[1] = '>';
}
menu_PutLine0 (page,offset, 0, buf);
}
static void free_structure P_((struct attach_structure **structure,
int *len));
static void free_structure(structure,len)
struct attach_structure **structure;
int *len;
{
int i;
if (*structure) {
for (i = 0; i < *len; i++) {
free_structure(& ((*structure)[i].subnodes),
& ((*structure)[i].subnodes_len));
}
free(*structure);
*structure = NULL;
}
*len = 0;
}
static void feed_attachments P_((struct Attachments *A,
struct attach_structure **structure,
int *len));
static void feed_attachments(A,structure,len)
struct Attachments *A;
struct attach_structure **structure;
int *len;
{
int L = A->attachment_count;
int i;
if (*structure)
free_structure(structure,len);
if (0 == L) {
*len = 0;
return;
}
*structure = safe_malloc(L * sizeof ((*structure)[0]));
*len = L;
/* bzero is defined on hdrs/defs.h */
bzero((void *)*structure, L * sizeof ((*structure)[0]));
for (i = 0; i < L; i++) {
(*structure)[i].attachments_index = i;
(*structure)[i].current_node = & (A->attach_files[i]);
(*structure)[i].subnodes = NULL;
(*structure)[i].subnodes_len = 0;
(*structure)[i].display_index = -1;
(*structure)[i].display_depth = -1;
}
}
static void expand_node P_((mime_t *T,
struct attach_structure **structure,
int *len,
charset_t defcharset,
FILE *F,
struct header_errors **header_error));
static void expand_node(T,structure,len,defcharset,F,header_error)
mime_t *T;
struct attach_structure **structure;
int *len;
charset_t defcharset;
FILE *F;
struct header_errors **header_error;
{
int L,i;
if (*structure)
free_structure(structure,len);
if (! T->parser_data) {
if (!F)
return;
if (!mime_parser_parse(T,defcharset,F,header_error))
return;
}
if (! T->parser_data) {
mime_panic(__FILE__,__LINE__,"expand_node",
"parser_data == NULL");
}
L = mime_parser_subparts(T->parser_data);
if (0 == L) {
*len = 0;
return;
}
*structure = safe_malloc(L * sizeof ((*structure)[0]));
*len = L;
/* bzero is defined on hdrs/defs.h */
bzero((void *)*structure, L * sizeof ((*structure)[0]));
for (i = 0; i < L; i++) {
(*structure)[i].attachments_index = -1;
(*structure)[i].current_node = mime_parser_index(T->parser_data,i);
(*structure)[i].subnodes = NULL;
(*structure)[i].subnodes_len = 0;
(*structure)[i].display_index = -1;
(*structure)[i].display_depth = -1;
}
}
struct display_vector {
struct attach_structure **vector;
int len;
};
static void count_len P_((struct attach_structure *structure,
int len,
int *index,
int depth,
struct display_vector * dv));
static void count_len(structure,len,index,depth,dv)
struct attach_structure *structure;
int len;
int *index;
int depth;
struct display_vector *dv;
{
int i;
for (i = 0; i < len; i++) {
structure[i].display_index = (*index)++;
structure[i].display_depth = depth;
dv->vector = safe_realloc(dv->vector,
(*index) * sizeof (dv->vector[0]));
if (dv->len < (*index)) {
while (dv->len < (*index)) {
dv->vector[dv->len] = NULL;
dv->len++;
}
} else
dv->len = (*index);
dv->vector[structure[i].display_index] = & structure[i];
count_len(structure[i].subnodes,
structure[i].subnodes_len,
index,depth+1,dv);
}
}
static void reset_display_vector P_((struct display_vector * dv));
static void reset_display_vector(dv)
struct display_vector * dv;
{
if (dv->vector)
free(dv->vector);
dv->vector = NULL;
dv->len = 0;
}
struct menu_anon_param {
struct attach_structure *top_structure;
int top_len;
struct display_vector DV;
};
enum { attach_mp_rdonly,
attach_mp_mime_structure,
attach_mp_LENGTH,
attach_mp_param,
attach_mp_COUNT };
#if ANSI_C
#define S_(x) static x;
#else
#define S_(x)
#endif
S_(subpage_simple_redraw sb_update_attach_menu)
static int sb_update_attach_menu(ptr,list)
struct menu_context *ptr;
struct menu_param *list;
{
int mime = mp_lookup_integer(list,attach_mp_mime_structure);
int rdonly = mp_lookup_integer(list,attach_mp_rdonly);
menu_ClearScreen(ptr);
if (!mime)
menu_print_format_center(ptr,0,
CATGETS(elm_msg_cat, MeSet, MeAttachMenuLine1a,
"To view attachment, press <return>. j = move down, k = move up"));
else
menu_print_format_center(ptr,0,
CATGETS(elm_msg_cat, MeSet, MeAttachMenuLine1,
"To view mime part, press <return>. j = move down, k = move up"));
if (rdonly)
menu_print_format_center(ptr,1,
CATGETS(elm_msg_cat, MeSet, MeAttachMenuLowRd,
"p)rint, s)ave, v)iew subparts, q)uit"));
else
menu_print_format_center(ptr,1,
CATGETS(elm_msg_cat, MeSet, MeAttachMenuLow,
"a)dd, e)dit, d)elete, m)odify, p)rint, s)ave, v)iew subparts, q)uit"));
return 1; /* menu completed */
}
S_(subpage_simple_redraw sb_update_attach_title)
static int sb_update_attach_title(ptr,list)
struct menu_context *ptr;
struct menu_param *list;
{
int mime = mp_lookup_integer(list,attach_mp_mime_structure);
int LENGTH = mp_lookup_integer(list,attach_mp_LENGTH);
menu_ClearScreen(ptr);
if (!mime)
menu_print_format_center(ptr,1,
CATGETS(elm_msg_cat, ElmSet, ElmAttachMenu,
"Attachment Menu (%d attachments)"),
LENGTH);
else
menu_print_format_center(ptr,1,
CATGETS(elm_msg_cat, ElmSet, ElmAttachMenu2,
"MIME structure Menu (%d visible parts)"),
LENGTH);
return 1; /* title completed */
}
S_(header_line_redraw hdr_attach_line_redraw)
static void hdr_attach_line_redraw P_((struct menu_context *ptr,
struct menu_param *list,
int line_number,
int index,
int is_current));
static void hdr_attach_line_redraw(ptr,list,line_number,index,is_current)
struct menu_context *ptr;
struct menu_param *list;
int line_number;
int index;
int is_current;
{
struct menu_anon_param *Ap = mp_lookup_anon(list,attach_mp_param);
if (0 <= index && index < Ap->DV.len)
attach_header(Ap->DV.vector[index],is_current,FALSE,line_number,ptr);
else {
menu_ClearLine(ptr,line_number);
}
}
S_(header_line_redraw hdr_attach_current_redraw)
static void hdr_attach_current_redraw P_((struct menu_context *ptr,
struct menu_param *list,
int line_number,
int index,
int is_current));
static void hdr_attach_current_redraw(ptr,list,line_number,index,is_current)
struct menu_context *ptr;
struct menu_param *list;
int line_number;
int index;
int is_current;
{
struct menu_anon_param *Ap = mp_lookup_anon(list,attach_mp_param);
if (0 <= index && index < Ap->DV.len) {
if (arrow_cursor)
write_num(index,is_current,line_number,ptr);
else
attach_header(Ap->DV.vector[index],is_current,FALSE,line_number,
ptr);
} else {
menu_ClearLine(ptr,line_number);
}
}
S_(header_line_redraw hdr_attach_status_redraw)
static void hdr_attach_status_redraw P_((struct menu_context *ptr,
struct menu_param *list,
int line_number,
int index,
int is_current));
static void hdr_attach_status_redraw(ptr,list,line_number,index,is_current)
struct menu_context *ptr;
struct menu_param *list;
int line_number;
int index;
int is_current;
{
/* FIXME ? ? */
hdr_attach_current_redraw(ptr,list,line_number,index,is_current);
}
/* FIXME: this should be more close to hadling of main screen ... */
static void set_attach_screen P_((struct menu_context *page,
struct screen_parts *LOC,
struct menu_param *LIST));
static void set_attach_screen(page,LOC, LIST)
struct menu_context *page;
struct screen_parts *LOC;
struct menu_param *LIST;
{
int LINES, COLUMNS;
menu_get_sizes(page,&LINES, &COLUMNS);
/* Title part */
if (! LOC->title_page)
LOC->title_page = new_menu_subpage(page,0,3,sb_update_attach_title,
LIST);
else
menu_subpage_relocate(LOC->title_page,page,0,3);
/* Attachments part */
if (! LOC->header_page)
LOC->header_page = new_menu_header(page,3,LINES-10,
hdr_attach_line_redraw,
hdr_attach_current_redraw,
null_header_param_changed,
hdr_attach_status_redraw,
LIST);
else
menu_header_relocate(LOC->header_page,page,3,LINES-10);
/* Menu part */
if (LOC->menu_page)
menu_subpage_relocate(LOC->menu_page,page,LINES-7,3);
else
LOC->menu_page = new_menu_subpage(page,LINES-7,3,
sb_update_attach_menu,LIST);
/* Prompt part */
if (LOC->prompt_page)
menu_subpage_relocate(LOC->prompt_page,page,LINES-4,4);
else
LOC->prompt_page = new_menu_subpage(page,LINES-4,4,
subpage_simple_noredraw,LIST);
}
static void check_attach_screen P_((struct screen_parts *LOC,
struct menu_param *list));
static void check_attach_screen(LOC,list)
struct screen_parts *LOC;
struct menu_param *list;
{
/* Title area */
if (menu_resized(LOC->title_page)) {
DPRINT(Debug,1, (&Debug, "title page resized\n"));
}
if (menu_need_redraw(LOC->title_page)) {
DPRINT(Debug,1, (&Debug, "title page redraw???\n"));
sb_update_attach_title(LOC->title_page,list);
}
/* Menu area */
if (menu_resized(LOC->menu_page)) {
DPRINT(Debug,1, (&Debug, "menu page resized\n"));
}
if (menu_need_redraw(LOC->menu_page)) {
DPRINT(Debug,1, (&Debug, "menu page redraw\n"));
sb_update_attach_menu(LOC->menu_page,list);
}
/* Prompt area */
if (menu_resized(LOC->prompt_page)) {
DPRINT(Debug,1, (&Debug, "prompt page resized\n"));
}
if (menu_need_redraw(LOC->prompt_page)) {
DPRINT(Debug,7, (&Debug, "prompt page redraw\n"));
menu_ClearScreen(LOC->prompt_page);
show_last_error(); /* for those operations that have to
* clear the footer except for a message.
*/
}
/* Attachments part */
if (menu_resized(LOC->header_page)) {
DPRINT(Debug,1, (&Debug, "attachment page resized\n"));
menu_trigger_redraw(LOC->header_page);
}
if (menu_need_redraw(LOC->header_page)) {
DPRINT(Debug,1, (&Debug, "attachment page redraw\n"));
menu_ClearScreen(LOC->header_page);
}
}
static void first_item P_((void));
static void first_item()
{
lib_error(CATGETS(elm_msg_cat, ElmSet,
ElmFirstAttachment,
"You are on the first attachment!"));
}
static void last_item P_((void));
static void last_item()
{
lib_error(CATGETS(elm_msg_cat, ElmSet,
ElmLastAttachment,
"You are on the last attachment!"));
}
static struct move_messages M = {
first_item,
last_item
};
void attach_menu (F,T,A,defcharset, mailer_info,hdr, aview,header_error)
FILE *F;
mime_t *T;
struct Attachments *A;
charset_t defcharset;
struct mailer_info *mailer_info;
struct header_rec *hdr;
struct AliasView *aview;
struct header_errors **header_error;
{
/* A generic attachment menu. "rdonly" controls whether or not the list
* of attachments "mt" may be edited.
*/
struct menu_anon_param Ap = { NULL, 0,
{ NULL, 0 }
};
int ch;
int update = TRUE;
int LENGTH = 0;
struct menu_context *page = new_menu_context();
int error_count = 0;
struct screen_parts LOC = { NULL, NULL, NULL, NULL };
struct menu_param PARAM[attach_mp_COUNT+1] = {
{ mp_integer, 0 },
{ mp_integer, 0 },
{ mp_integer, 0 },
{ mp_anon_param,0 },
{ mp_END,0 }
};
Ap.top_structure = NULL;
Ap.top_len = 0;
Ap.DV.vector = NULL;
Ap.DV.len = 0;
mp_list_set_integer(PARAM,attach_mp_rdonly,T != NULL);
if (A)
feed_attachments(A,&Ap.top_structure,&Ap.top_len);
else if (T) {
Ap.top_structure = safe_malloc(sizeof (Ap.top_structure[0]));
/* bzero is defined on hdrs/defs.h */
bzero((void *)Ap.top_structure, sizeof (Ap.top_structure[0]));
Ap.top_len = 1;
Ap.top_structure[0].attachments_index = -1;
Ap.top_structure[0].current_node = T;
Ap.top_structure[0].subnodes = NULL;
Ap.top_structure[0].subnodes_len = 0;
Ap.top_structure[0].display_index = 0;
Ap.top_structure[0].display_depth = 0;
expand_node(Ap.top_structure[0].current_node,
&Ap.top_structure[0].subnodes,
&Ap.top_structure[0].subnodes_len,
defcharset,F,
header_error);
mp_list_set_integer(PARAM,attach_mp_mime_structure,1);
}
count_len(Ap.top_structure,Ap.top_len,&LENGTH,0,&Ap.DV);
mp_list_set_integer(PARAM,attach_mp_LENGTH,LENGTH);
mp_list_set_anon(PARAM,attach_mp_param,&Ap);
set_attach_screen(page,&LOC,PARAM);
#if 0
if (!mailer_info && !rdonly)
mime_panic(__FILE__,__LINE__,
"attach_menu",
"No mailer information available");
#endif
for (;;) {
if (header_error) {
int ec = 0;
int cancel_it = 0;
if (*header_error)
ec = get_header_errors_count(*header_error);
if (ec > error_count) {
/* Print new errors .. if arriced during handling
if mime structure
*/
print_errors_att(*header_error,error_count,&cancel_it);
if (cancel_it)
goto OUT;
error_count = ec;
update = TRUE;
}
}
if (menu_resized(page)) {
set_attach_screen(page,&LOC,PARAM);
update = TRUE;
}
if (update || menu_need_redraw(page)) {
menu_ClearScreen(page);
/* Call refresh routines of children */
menu_redraw_children(page);
update = FALSE;
show_last_error();
}
check_attach_screen(&LOC,PARAM);
{
int lin,col;
menu_ClearLine(LOC.prompt_page,0);
menu_PutLineX (LOC.prompt_page,0, 0,
CATGETS(elm_msg_cat, MeSet, MeAttachMenuPrompt,
"Attachments: "));
menu_GetXYLocation(LOC.prompt_page,&lin,&col);
menu_CleartoEOS(LOC.prompt_page);
show_last_error();
menu_MoveCursor(LOC.prompt_page,lin,col);
ch = menu_ReadCh(LOC.prompt_page,
REDRAW_MARK|READCH_CURSOR|READCH_resize|
READCH_sig_char);
menu_CleartoEOS(LOC.prompt_page);
set_error(""); /* clear error buffer */
}
/* Translate keys not handled on do_movement()
to equivalent keys
*/
switch (ch) {
case LEFT_MARK: ch = PAGEUP_MARK; break;
case RIGHT_MARK: ch = PAGEDOWN_MARK; break;
case 'n':
case ctrl('N'): ch = DOWN_MARK; break;
case ctrl('K'): ch = UP_MARK; break;
}
ch = do_movement(LOC.header_page,ch,LENGTH,&M);
switch (ch) {
case RESIZE_MARK:
DPRINT(Debug,4, (&Debug, " ... resizing\n"));
continue;
case 's': {
int cur = menu_header_get(LOC.header_page,header_current);
menu_Write_to_screen(LOC.prompt_page,
CATGETS(elm_msg_cat, MeSet,
MeSaveToFile,
"Save to File"));
FlushBuffer();
if (cur < LENGTH &&
0 <= cur && cur < Ap.DV.len && Ap.DV.vector[cur]) {
attach_save (F,Ap.DV.vector[cur]->current_node,
aview, page, &LOC);
} else
lib_error(CATGETS(elm_msg_cat, ElmSet,
ElmNoAttachments,
"There are no attachments!"));
}
break;
case ' ':
case '\n': {
int cur = menu_header_get(LOC.header_page,header_current);
if (cur < LENGTH &&
0 <= cur && cur < Ap.DV.len && Ap.DV.vector[cur]) {
attach_viewer (F,Ap.DV.vector[cur]->current_node,hdr, page);
update = TRUE;
}
else
lib_error(CATGETS(elm_msg_cat, ElmSet,
ElmNoAttachments,
"There are no attachments!"));
}
break;
case 'p': {
int cur = menu_header_get(LOC.header_page,header_current);
menu_Write_to_screen(LOC.prompt_page,
CATGETS(elm_msg_cat, MeSet,
MePrintAttach,
"Print attachment"));
FlushBuffer();
if (cur < LENGTH &&
0 <= cur && cur < Ap.DV.len && Ap.DV.vector[cur]) {
attach_print(F,Ap.DV.vector[cur]->current_node,
defcharset,page);
}
else
lib_error(CATGETS(elm_msg_cat, ElmSet,
ElmNoAttachments,
"There are no attachments!"));
}
break;
case 'v': { /* Expand current node */
int cur = menu_header_get(LOC.header_page,header_current);
menu_Write_to_screen(LOC.prompt_page,
CATGETS(elm_msg_cat, MeSet,
MeViewSubparts,
"View MIME subparts"));
FlushBuffer();
if (cur < LENGTH &&
0 <= cur && cur < Ap.DV.len && Ap.DV.vector[cur]) {
expand_node(Ap.DV.vector[cur]->current_node,
& (Ap.DV.vector[cur]->subnodes),
& (Ap.DV.vector[cur]->subnodes_len),
defcharset,
F,
header_error);
LENGTH = 0;
reset_display_vector(&Ap.DV);
count_len(Ap.top_structure,Ap.top_len,&LENGTH,0,&Ap.DV);
mp_list_set_integer(PARAM,attach_mp_LENGTH,LENGTH);
menu_trigger_redraw(LOC.title_page);
menu_trigger_redraw(LOC.header_page);
} else
lib_error(CATGETS(elm_msg_cat, ElmSet,
ElmNoAttachments,
"There are no attachments!"));
}
break;
case 'e':
if (A) {
int cur = menu_header_get(LOC.header_page,header_current);
if (cur < LENGTH &&
0 <= cur && cur < Ap.DV.len && Ap.DV.vector[cur]) {
attach_edit (Ap.DV.vector[cur]->current_node,
mailer_info);
update = TRUE;
} else
lib_error(CATGETS(elm_msg_cat, ElmSet,
ElmNoAttachments,
"There are no attachments!"));
}
break;
case 'd':
if (A) {
int cur = menu_header_get(LOC.header_page,header_current);
if (cur < 0 || cur >= LENGTH || cur >= Ap.DV.len ) {
lib_error(CATGETS(elm_msg_cat, ElmSet,
ElmNoAttachments,
"There are no attachments!"));
break;
}
if (question_me) {
for(;;) {
/* FIXME */
menu_PutLine0(LOC.prompt_page,
0, 0, "Are you sure? (y/n): y");
menu_MoveCursor(LOC.prompt_page,
0, 21);
ch = menu_ReadCh(LOC.prompt_page, 0);
if (ch == 'y' || ch == '\n' || ch == 'n')
break;
}
menu_ClearLine(LOC.prompt_page,0);
if (ch == 'n')
break;
}
delete_it:
cur = menu_header_get(LOC.header_page,header_current);
if (cur < LENGTH &&
0 <= cur && cur < Ap.DV.len && Ap.DV.vector[cur] &&
Ap.DV.vector[cur] && A &&
Ap.DV.vector[cur]->attachments_index >= 0 &&
Ap.DV.vector[cur]->attachments_index <
A->attachment_count) {
int i = Ap.DV.vector[cur]->attachments_index;
mime_t_clear(& (A->attach_files[i]) );
for (; i < A->attachment_count-1; i++)
A->attach_files[i] = A->attach_files[i+1];
mime_t_zero ( & (A->attach_files[i]) );
A->attachment_count--;
free_structure(&Ap.top_structure,&Ap.top_len);
feed_attachments(A,&Ap.top_structure,&Ap.top_len);
LENGTH = 0;
reset_display_vector(&Ap.DV);
count_len(Ap.top_structure,Ap.top_len,&LENGTH,0,&Ap.DV);
mp_list_set_integer(PARAM,attach_mp_LENGTH,LENGTH);
menu_trigger_redraw(LOC.title_page);
menu_trigger_redraw(LOC.header_page);
}
}
break;
case 'a':
if (A) {
mime_t attach;
mime_t_zero(&attach);
if (attach_modify (&attach, TRUE, mailer_info, aview)) {
add_Attachments(A,&attach);
free_structure(&Ap.top_structure,&Ap.top_len);
feed_attachments(A,&Ap.top_structure,&Ap.top_len);
LENGTH = 0;
reset_display_vector(&Ap.DV);
count_len(Ap.top_structure,Ap.top_len,&LENGTH,0,&Ap.DV);
mp_list_set_integer(PARAM,attach_mp_LENGTH,LENGTH);
menu_header_change(LOC.header_page, header_current,
Ap.top_len-1);
menu_trigger_redraw(LOC.title_page);
menu_trigger_redraw(LOC.header_page);
} else {
mime_t_clear(& attach );
}
}
break;
case 'm':
if (A) {
int cur = menu_header_get(LOC.header_page,header_current);
if (cur < LENGTH &&
0 <= cur && cur < Ap.DV.len && Ap.DV.vector[cur]) {
attach_modify (Ap.DV.vector[cur]->current_node, FALSE,
mailer_info,
aview);
/* If there is not pathname it is otherwise assumed to be
* part from mailfile...!
*/
if (Ap.DV.vector[cur]->current_node->pathname0 == NULL)
goto delete_it;
update = TRUE;
} else
lib_error(CATGETS(elm_msg_cat, ElmSet,
ElmNoAttachments,
"There are no attachments!"));
}
break;
case 'i':
case 'q':
case 'x':
case TERMCH_interrupt_char:
goto OUT;
case ctrl('F'):
forget_passphrase();
break;
case ctrl('L'):
case REDRAW_MARK:
update = TRUE;
break;
#ifdef ALLOW_SUBSHELL
case '!':
subshell(NULL,page,LOC.prompt_page);
break;
#endif
case 0:
break;
default:
lib_error(CATGETS(elm_msg_cat, ElmSet,
ElmUnknownCommand3,
"Unknown command: %c"),
ch);
}
}
OUT:
reset_display_vector(&Ap.DV);
if (Ap.top_structure)
free_structure(&Ap.top_structure,&Ap.top_len);
free_mailbox_screen(&LOC);
erase_menu_context(&page);
return;
}
/*
* Local Variables:
* mode:c
* c-basic-offset:4
* buffer-file-coding-system: iso-8859-1
* End:
*/
syntax highlighted by Code2HTML, v. 0.9.1