Skip to content
Toggle navigation
Toggle navigation
This project
Loading...
Sign in
John McEleney
/
mailutils
Go to a project
Toggle navigation
Toggle navigation pinning
Projects
Groups
Snippets
Help
Project
Activity
Repository
Pipelines
Graphs
Issues
0
Merge Requests
0
Wiki
Network
Create a new issue
Builds
Commits
Issue Boards
Files
Commits
Network
Compare
Branches
Tags
Commit
fbb38622
...
fbb3862280d6c6ef5ca49a05d4e571a23df8a241
authored
2003-03-17 15:15:21 +0000
by
Sergey Poznyakoff
Browse Files
Options
Browse Files
Tag
Download
Email Patches
Plain Diff
Implemented store mode.
1 parent
43c9a8a3
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
749 additions
and
76 deletions
mh/mhn.c
mh/mhn.c
View file @
fbb3862
...
...
@@ -18,6 +18,9 @@
/* MH mhn command */
#include <mh.h>
#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free
#include <obstack.h>
const
char
*
argp_program_version
=
"mhn ("
PACKAGE_STRING
")"
;
static
char
doc
[]
=
N_
(
"GNU MH mhn
\v
"
...
...
@@ -57,15 +60,15 @@ static struct argp_option options[] = {
{
"form"
,
ARG_FORM
,
N_
(
"FILE"
),
0
,
N_
(
"Read mhl format from FILE"
),
22
},
{
"pause"
,
ARG_PAUSE
,
N_
(
"BOOL"
),
OPTION_ARG_OPTIONAL
,
N_
(
"
*
Pause prior to displaying content"
),
22
},
N_
(
"Pause prior to displaying content"
),
22
},
{
"nopause"
,
ARG_NOPAUSE
,
NULL
,
OPTION_HIDDEN
,
""
,
22
},
{
N_
(
"Saving options"
),
0
,
NULL
,
OPTION_DOC
,
NULL
,
30
},
{
"store"
,
ARG_STORE
,
N_
(
"BOOL"
),
OPTION_ARG_OPTIONAL
,
N_
(
"
*
Store the contents of the messages on disk"
),
31
},
N_
(
"Store the contents of the messages on disk"
),
31
},
{
"nostore"
,
ARG_NOSTORE
,
NULL
,
OPTION_HIDDEN
,
""
,
31
},
{
"auto"
,
ARG_AUTO
,
N_
(
"BOOL"
),
OPTION_ARG_OPTIONAL
,
N_
(
"
*
Use filenames from the content headers"
),
31
},
N_
(
"Use filenames from the content headers"
),
31
},
{
"noauto"
,
ARG_NOAUTO
,
NULL
,
OPTION_HIDDEN
,
""
,
31
},
{
N_
(
"Other options"
),
0
,
NULL
,
OPTION_DOC
,
NULL
,
40
},
...
...
@@ -76,6 +79,8 @@ static struct argp_option options[] = {
{
"verbose"
,
ARG_VERBOSE
,
N_
(
"BOOL"
),
OPTION_ARG_OPTIONAL
,
N_
(
"Print additional information"
),
41
},
{
"noverbose"
,
ARG_NOVERBOSE
,
NULL
,
OPTION_HIDDEN
,
""
,
41
},
{
"quiet"
,
ARG_QUIET
,
0
,
0
,
N_
(
"Be quiet"
)},
{
NULL
}
};
...
...
@@ -125,6 +130,7 @@ static enum mhn_mode mode = mode_compose;
#define OPT_AUTO 010
#define OPT_SERIALONLY 020
#define OPT_VERBOSE 040
#define OPT_QUIET 100
static
int
mode_options
=
OPT_HEADERS
;
static
char
*
formfile
;
...
...
@@ -138,6 +144,12 @@ static mailbox_t mbox;
static
message_t
message
;
static
msg_part_t
req_part
;
/* Show flags */
#define MHN_EXCLUSIVE_EXEC 001
#define MHN_STDIN 002
#define MHN_LISTING 004
#define MHN_CONFIRM 010
void
sfree
(
char
**
ptr
)
{
...
...
@@ -170,6 +182,60 @@ split_content (const char *content, char **type, char **subtype)
}
}
int
_get_hdr_value
(
header_t
hdr
,
const
char
*
name
,
char
**
value
)
{
int
status
=
header_aget_value
(
hdr
,
name
,
value
);
if
(
status
==
0
)
{
/* Remove the newlines. */
char
*
nl
;
while
((
nl
=
strchr
(
*
value
,
'\n'
))
!=
NULL
)
*
nl
=
' '
;
}
return
status
;
}
int
_get_content_type
(
header_t
hdr
,
char
**
value
,
char
**
rest
)
{
char
*
type
=
NULL
;
_get_hdr_value
(
hdr
,
MU_HEADER_CONTENT_TYPE
,
&
type
);
if
(
type
==
NULL
||
*
type
==
'\0'
)
{
if
(
type
)
free
(
type
);
type
=
strdup
(
"text/plain"
);
/* Default. */
if
(
rest
)
*
rest
=
NULL
;
}
else
{
char
*
p
=
strchr
(
type
,
';'
);
if
(
p
)
*
p
++
=
0
;
if
(
rest
)
*
rest
=
p
;
}
*
value
=
type
;
return
0
;
}
static
int
_get_content_encoding
(
header_t
hdr
,
char
**
value
)
{
char
*
encoding
=
NULL
;
_get_hdr_value
(
hdr
,
MU_HEADER_CONTENT_TRANSFER_ENCODING
,
&
encoding
);
if
(
encoding
==
NULL
||
*
encoding
==
'\0'
)
{
if
(
encoding
)
free
(
encoding
);
encoding
=
strdup
(
"7bit"
);
/* Default. */
}
*
value
=
encoding
;
return
0
;
}
static
int
opt_handler
(
int
key
,
char
*
arg
,
void
*
unused
,
struct
argp_state
*
state
)
{
...
...
@@ -316,7 +382,11 @@ opt_handler (int key, char *arg, void *unused, struct argp_state *state)
case
ARG_PART
:
req_part
=
msg_part_parse
(
arg
);
break
;
case
ARG_QUIET
:
mode_options
|=
OPT_QUIET
;
break
;
default:
return
1
;
}
...
...
@@ -405,6 +475,50 @@ msg_part_print (msg_part_t p, int max_width)
putchar
(
' '
);
}
char
*
msg_part_format
(
msg_part_t
p
)
{
int
i
;
int
width
=
0
;
char
*
str
,
*
s
;
char
buf
[
64
];
for
(
i
=
1
;
i
<=
p
->
level
;
i
++
)
{
if
(
i
>
1
)
width
++
;
width
+=
snprintf
(
buf
,
sizeof
buf
,
"%lu"
,
(
unsigned
long
)
p
->
part
[
i
]);
}
str
=
s
=
xmalloc
(
width
+
1
);
for
(
i
=
1
;
i
<=
p
->
level
;
i
++
)
{
if
(
i
>
1
)
*
s
++
=
'.'
;
s
+=
sprintf
(
s
,
"%lu"
,
(
unsigned
long
)
p
->
part
[
i
]);
}
*
s
=
0
;
return
str
;
}
void
msg_part_format_stk
(
struct
obstack
*
stk
,
msg_part_t
p
)
{
int
i
;
char
buf
[
64
];
for
(
i
=
1
;
i
<=
p
->
level
;
i
++
)
{
int
len
;
if
(
i
>
1
)
obstack_1grow
(
stk
,
'.'
);
len
=
snprintf
(
buf
,
sizeof
buf
,
"%lu"
,
(
unsigned
long
)
p
->
part
[
i
]);
obstack_grow
(
stk
,
buf
,
len
);
}
}
msg_part_t
msg_part_parse
(
char
*
str
)
{
...
...
@@ -449,58 +563,239 @@ msg_part_subpart (msg_part_t p, int level)
}
/* ***********************
*** Message iterators **
************************* */
/* ***********************
Context file accessors
************************* */
int
_
get_hdr_value
(
header_t
hdr
,
const
char
*
name
,
char
**
value
)
char
*
_
mhn_profile_get
(
char
*
prefix
,
char
*
type
,
char
*
subtype
,
char
*
defval
)
{
int
status
=
header_aget_value
(
hdr
,
name
,
value
);
if
(
status
==
0
)
char
*
str
,
*
name
;
if
(
subtype
)
{
/* Remove the newlines. */
char
*
nl
;
while
((
nl
=
strchr
(
*
value
,
'\n'
))
!=
NULL
)
*
nl
=
' '
;
asprintf
(
&
name
,
"mhn-%s-%s/%s"
,
prefix
,
type
,
subtype
);
str
=
mh_global_profile_get
(
name
,
NULL
);
free
(
name
);
if
(
!
str
)
return
_mhn_profile_get
(
prefix
,
type
,
NULL
,
defval
);
}
return
status
;
else
{
asprintf
(
&
name
,
"mhn-%s-%s"
,
prefix
,
type
);
str
=
mh_global_profile_get
(
name
,
defval
);
free
(
name
);
}
return
str
;
}
int
_get_content_type
(
header_t
hdr
,
char
**
valu
e
)
char
*
mhn_show_command
(
message_t
msg
,
msg_part_t
part
,
int
*
flags
,
char
**
tempfil
e
)
{
char
*
type
=
NULL
;
_get_hdr_value
(
hdr
,
MU_HEADER_CONTENT_TYPE
,
&
type
);
if
(
type
==
NULL
||
*
type
==
'\0'
)
char
*
p
,
*
str
,
*
tmp
;
char
*
typestr
,
*
type
,
*
subtype
,
*
typeargs
;
struct
obstack
stk
;
header_t
hdr
;
message_get_header
(
msg
,
&
hdr
);
_get_content_type
(
hdr
,
&
typestr
,
&
typeargs
);
split_content
(
typestr
,
&
type
,
&
subtype
);
str
=
_mhn_profile_get
(
"show"
,
type
,
subtype
,
NULL
);
if
(
!
str
)
/* FIXME */
return
NULL
;
/* Expand macro-notations:
%a additional arguments
%e exclusive execution
%f filename containing content
%F %e, %f, and stdin is terminal not content
%l display listing prior to displaying content
%p %l, and ask for confirmation
%s subtype
%d content description */
obstack_init
(
&
stk
);
for
(
p
=
str
;
*
p
&&
isspace
(
*
p
);
p
++
)
;
if
(
*
p
==
'|'
)
p
++
;
for
(
;
*
p
;
p
++
)
{
if
(
type
)
free
(
type
);
type
=
strdup
(
"text/plain"
);
/* Default. */
if
(
*
p
==
'%'
)
{
switch
(
*++
p
)
{
case
'a'
:
/* additional arguments */
obstack_grow
(
&
stk
,
typeargs
,
strlen
(
typeargs
));
break
;
case
'e'
:
/* exclusive execution */
*
flags
|=
MHN_EXCLUSIVE_EXEC
;
break
;
case
'f'
:
/* filename containing content */
if
(
!*
tempfile
)
*
tempfile
=
mu_tempname
(
NULL
);
obstack_grow
(
&
stk
,
*
tempfile
,
strlen
(
*
tempfile
));
break
;
case
'F'
:
/* %e, %f, and stdin is terminal not content */
*
flags
|=
MHN_STDIN
|
MHN_EXCLUSIVE_EXEC
;
if
(
!*
tempfile
)
*
tempfile
=
mu_tempname
(
NULL
);
obstack_grow
(
&
stk
,
*
tempfile
,
strlen
(
*
tempfile
));
break
;
case
'l'
:
/* display listing prior to displaying content */
*
flags
|=
MHN_LISTING
;
break
;
case
'p'
:
/* %l, and ask for confirmation */
*
flags
|=
MHN_LISTING
|
MHN_CONFIRM
;
break
;
case
's'
:
/* subtype */
obstack_grow
(
&
stk
,
subtype
,
strlen
(
subtype
));
break
;
case
'd'
:
/* content description */
if
(
header_aget_value
(
hdr
,
MU_HEADER_CONTENT_DESCRIPTION
,
&
tmp
)
==
0
)
{
obstack_grow
(
&
stk
,
tmp
,
strlen
(
tmp
));
free
(
tmp
);
}
break
;
default
:
obstack_1grow
(
&
stk
,
*
p
);
p
++
;
}
}
else
obstack_1grow
(
&
stk
,
*
p
);
}
obstack_1grow
(
&
stk
,
0
);
free
(
typestr
);
free
(
type
);
free
(
subtype
);
str
=
obstack_finish
(
&
stk
);
for
(
p
=
str
;
*
p
&&
isspace
(
*
p
);
p
++
)
;
if
(
!*
p
)
str
=
NULL
;
else
{
char
*
p
=
strchr
(
type
,
';'
);
if
(
p
)
*
p
=
0
;
}
*
value
=
type
;
return
0
;
str
=
strdup
(
str
);
obstack_free
(
&
stk
,
NULL
);
return
str
;
}
static
int
_get_content_encoding
(
header_t
hdr
,
char
**
valu
e
)
char
*
mhn_store_command
(
message_t
msg
,
msg_part_t
part
,
char
*
nam
e
)
{
char
*
encoding
=
NULL
;
_get_hdr_value
(
hdr
,
MU_HEADER_CONTENT_TRANSFER_ENCODING
,
&
encoding
);
if
(
encoding
==
NULL
||
*
encoding
==
'\0'
)
char
*
p
,
*
str
,
*
tmp
;
char
*
typestr
,
*
type
,
*
subtype
,
*
typeargs
;
struct
obstack
stk
;
header_t
hdr
;
char
buf
[
64
];
message_get_header
(
msg
,
&
hdr
);
_get_content_type
(
hdr
,
&
typestr
,
&
typeargs
);
split_content
(
typestr
,
&
type
,
&
subtype
);
str
=
_mhn_profile_get
(
"show"
,
type
,
subtype
,
"%m%P.%s"
);
/* Expand macro-notations:
%m message number
%P .part
%p part
%s subtype */
obstack_init
(
&
stk
);
for
(
p
=
str
;
*
p
;
p
++
)
{
if
(
encoding
)
free
(
encoding
);
encoding
=
strdup
(
"7bit"
);
/* Default. */
if
(
*
p
==
'%'
)
{
switch
(
*++
p
)
{
case
'a'
:
/* additional arguments */
obstack_grow
(
&
stk
,
typeargs
,
strlen
(
typeargs
));
break
;
case
'm'
:
if
(
name
)
obstack_grow
(
&
stk
,
name
,
strlen
(
name
));
else
{
snprintf
(
buf
,
sizeof
buf
,
"%lu"
,
(
unsigned
long
)
msg_part_subpart
(
part
,
0
));
obstack_grow
(
&
stk
,
buf
,
strlen
(
buf
));
}
break
;
case
'P'
:
obstack_1grow
(
&
stk
,
'.'
);
/*FALLTHRU*/
case
'p'
:
msg_part_format_stk
(
&
stk
,
part
);
break
;
case
's'
:
/* subtype */
obstack_grow
(
&
stk
,
subtype
,
strlen
(
subtype
));
break
;
case
'd'
:
/* content description */
if
(
header_aget_value
(
hdr
,
MU_HEADER_CONTENT_DESCRIPTION
,
&
tmp
)
==
0
)
{
obstack_grow
(
&
stk
,
tmp
,
strlen
(
tmp
));
free
(
tmp
);
}
break
;
default
:
obstack_1grow
(
&
stk
,
*
p
);
p
++
;
}
}
else
obstack_1grow
(
&
stk
,
*
p
);
}
*
value
=
encoding
;
return
0
;
obstack_1grow
(
&
stk
,
*
p
);
free
(
typestr
);
free
(
type
);
free
(
subtype
);
str
=
obstack_finish
(
&
stk
);
for
(
p
=
str
;
*
p
&&
isspace
(
*
p
);
p
++
)
;
if
(
!*
p
)
str
=
NULL
;
else
str
=
strdup
(
str
);
obstack_free
(
&
stk
,
NULL
);
return
str
;
}
/* ************************** Message iterators *************************** */
typedef
int
(
*
msg_handler_t
)
__PMT
((
message_t
msg
,
msg_part_t
part
,
char
*
type
,
char
*
encoding
,
void
*
data
));
...
...
@@ -518,8 +813,11 @@ match_content (char *content)
split_content
(
content
,
&
type
,
&
subtype
);
if
(
strcasecmp
(
content_type
,
type
)
==
0
)
rc
=
strcasecmp
(
content_subtype
,
subtype
);
if
((
rc
=
strcasecmp
(
content_type
,
type
))
==
0
)
{
if
(
content_subtype
)
rc
=
strcasecmp
(
content_subtype
,
subtype
);
}
else
rc
=
strcasecmp
(
content_type
,
subtype
);
...
...
@@ -548,7 +846,7 @@ handle_message (message_t msg, msg_part_t part, msg_handler_t fun, void *data)
int
ismime
=
0
;
message_get_header
(
msg
,
&
hdr
);
_get_content_type
(
hdr
,
&
type
);
_get_content_type
(
hdr
,
&
type
,
NULL
);
_get_content_encoding
(
hdr
,
&
encoding
);
fun
(
msg
,
part
,
type
,
encoding
,
data
);
...
...
@@ -570,12 +868,12 @@ handle_message (message_t msg, msg_part_t part, msg_handler_t fun, void *data)
if
(
message_get_part
(
msg
,
i
,
&
message
)
==
0
)
{
message_get_header
(
message
,
&
hdr
);
_get_content_type
(
hdr
,
&
type
);
_get_content_type
(
hdr
,
&
type
,
NULL
);
_get_content_encoding
(
hdr
,
&
encoding
);
msg_part_set_subpart
(
part
,
i
);
if
(
strcasecmp
(
type
,
"multipart/mixed"
)
==
0
)
if
(
message_is_multipart
(
message
,
&
ismime
)
==
0
&&
ismime
)
handle_message
(
message
,
part
,
fun
,
data
);
else
call_handler
(
message
,
part
,
type
,
encoding
,
fun
,
data
);
...
...
@@ -641,18 +939,23 @@ list_handler (message_t msg, msg_part_t part, char *type, char *encoding,
header_t
hdr
;
if
(
msg_part_level
(
part
)
==
0
)
printf
(
"%
3lu
"
,
(
unsigned
long
)
msg_part_subpart
(
part
,
0
));
printf
(
"%
4lu
"
,
(
unsigned
long
)
msg_part_subpart
(
part
,
0
));
else
{
printf
(
" "
);
msg_part_print
(
part
,
5
);
printf
(
"
"
);
msg_part_print
(
part
,
4
);
putchar
(
' '
);
}
printf
(
"%-2
6
s"
,
type
);
printf
(
"%-2
5
s"
,
type
);
mhn_message_size
(
msg
,
&
size
);
printf
(
"%4lu"
,
(
unsigned
long
)
size
);
if
(
size
<
1024
)
printf
(
" %4lu"
,
(
unsigned
long
)
size
);
else
if
(
size
<
1024
*
1024
)
printf
(
"%4luK"
,
(
unsigned
long
)
size
/
1024
);
else
printf
(
"%4luM"
,
(
unsigned
long
)
size
/
1024
/
1024
);
if
(
message_get_header
(
msg
,
&
hdr
)
==
0
)
{
char
*
descr
;
...
...
@@ -670,7 +973,11 @@ list_handler (message_t msg, msg_part_t part, char *type, char *encoding,
int
list_message
(
message_t
msg
,
size_t
num
)
{
msg_part_t
part
=
msg_part_create
(
num
);
size_t
uid
;
msg_part_t
part
;
mh_message_number
(
msg
,
&
uid
);
part
=
msg_part_create
(
uid
);
handle_message
(
msg
,
part
,
list_handler
,
NULL
);
msg_part_destroy
(
part
);
return
0
;
...
...
@@ -688,7 +995,7 @@ mhn_list ()
int
rc
;
if
(
mode_options
&
OPT_HEADERS
)
printf
(
_
(
"
msg part type/subtype size
description
\n
"
));
printf
(
_
(
"
msg part type/subtype size
description
\n
"
));
if
(
message
)
rc
=
list_message
(
message
,
0
);
...
...
@@ -717,43 +1024,189 @@ cat_message (stream_t out, stream_t in)
}
int
show_internal
(
message_t
msg
,
msg_part_t
part
,
char
*
encoding
,
stream_t
out
)
{
int
rc
;
body_t
body
=
NULL
;
stream_t
dstr
,
bstr
;
if
((
rc
=
message_get_body
(
msg
,
&
body
)))
{
mh_error
(
_
(
"%lu: can't get message body: %s"
),
(
unsigned
long
)
msg_part_subpart
(
part
,
0
),
mu_strerror
(
rc
));
return
0
;
}
body_get_stream
(
body
,
&
bstr
);
rc
=
filter_create
(
&
dstr
,
bstr
,
encoding
,
MU_FILTER_DECODE
,
MU_STREAM_READ
);
if
(
rc
==
0
)
bstr
=
dstr
;
cat_message
(
out
,
bstr
);
if
(
dstr
)
stream_destroy
(
&
dstr
,
stream_get_owner
(
dstr
));
return
0
;
}
int
exec_internal
(
message_t
msg
,
msg_part_t
part
,
char
*
encoding
,
char
*
cmd
)
{
int
rc
;
stream_t
tmp
;
rc
=
prog_stream_create
(
&
tmp
,
cmd
,
MU_STREAM_WRITE
);
if
(
rc
)
{
mh_error
(
_
(
"can't create proc stream (command %s): %s"
),
cmd
,
mu_strerror
(
rc
));
return
rc
;
}
rc
=
stream_open
(
tmp
);
if
(
rc
)
{
mh_error
(
_
(
"can't open proc stream (command %s): %s"
),
cmd
,
mu_strerror
(
rc
));
return
rc
;
}
show_internal
(
msg
,
part
,
encoding
,
tmp
);
stream_destroy
(
&
tmp
,
stream_get_owner
(
tmp
));
return
rc
;
}
/* FIXME: stdin is always opened when invoking subprocess, no matter
what the MHN_STDIN bit is */
int
mhn_run_command
(
message_t
msg
,
msg_part_t
part
,
char
*
encoding
,
char
*
cmd
,
int
flags
,
char
*
tempfile
)
{
int
rc
=
0
;
if
(
tempfile
)
{
/* pass content via a tempfile */
int
status
;
int
argc
;
char
**
argv
;
stream_t
tmp
;
if
(
argcv_get
(
cmd
,
""
,
"#"
,
&
argc
,
&
argv
))
{
mh_error
(
_
(
"can't parse command line `%s'"
),
cmd
);
return
ENOSYS
;
}
rc
=
file_stream_create
(
&
tmp
,
tempfile
,
MU_STREAM_RDWR
);
if
(
rc
)
{
mh_error
(
_
(
"can't create temporary stream (file %s): %s"
),
tempfile
,
mu_strerror
(
rc
));
argcv_free
(
argc
,
argv
);
return
rc
;
}
rc
=
stream_open
(
tmp
);
if
(
rc
)
{
mh_error
(
_
(
"can't open temporary stream (file %s): %s"
),
tempfile
,
mu_strerror
(
rc
));
stream_destroy
(
&
tmp
,
stream_get_owner
(
tmp
));
argcv_free
(
argc
,
argv
);
return
rc
;
}
show_internal
(
msg
,
part
,
encoding
,
tmp
);
stream_destroy
(
&
tmp
,
stream_get_owner
(
tmp
));
rc
=
mu_spawnvp
(
argv
[
0
],
argv
,
&
status
);
if
(
status
)
rc
=
status
;
argcv_free
(
argc
,
argv
);
}
else
rc
=
exec_internal
(
msg
,
part
,
encoding
,
cmd
);
return
rc
;
}
int
show_handler
(
message_t
msg
,
msg_part_t
part
,
char
*
type
,
char
*
encoding
,
void
*
data
)
{
stream_t
out
=
data
;
if
(
strncasecmp
(
type
,
"multipart"
,
9
)
==
0
)
char
*
cmd
;
int
flags
=
0
;
char
buf
[
64
];
int
fd
=
1
;
char
*
tempfile
=
NULL
;
int
ismime
;
if
(
message_is_multipart
(
msg
,
&
ismime
)
==
0
&&
ismime
)
return
0
;
if
(
mhl_format
)
mhl_format_run
(
mhl_format
,
width
,
0
,
MHL_DECODE
,
msg
,
out
);
else
stream_get_fd
(
out
,
&
fd
);
if
(
mode_options
&
OPT_PAUSE
)
flags
|=
MHN_CONFIRM
;
cmd
=
mhn_show_command
(
msg
,
part
,
&
flags
,
&
tempfile
);
if
(
!
cmd
)
flags
|=
MHN_LISTING
;
if
(
flags
&
MHN_LISTING
)
{
int
rc
;
body_t
body
=
NULL
;
stream_t
dstr
,
bstr
;
if
((
rc
=
message_get_body
(
msg
,
&
body
)))
char
*
str
;
size_t
size
=
0
;
str
=
_
(
"part "
);
stream_sequential_write
(
out
,
str
,
strlen
(
str
));
str
=
msg_part_format
(
part
);
stream_sequential_write
(
out
,
str
,
strlen
(
str
));
free
(
str
);
stream_sequential_write
(
out
,
" "
,
1
);
stream_sequential_write
(
out
,
type
,
strlen
(
type
));
mhn_message_size
(
msg
,
&
size
);
snprintf
(
buf
,
sizeof
buf
,
" %lu"
,
(
unsigned
long
)
size
);
stream_sequential_write
(
out
,
buf
,
strlen
(
buf
));
stream_sequential_write
(
out
,
"
\n
"
,
1
);
stream_flush
(
out
);
}
if
(
flags
&
MHN_CONFIRM
)
{
if
(
isatty
(
fd
)
&&
isatty
(
0
))
{
mh_error
(
_
(
"%lu: can't get message body: %s"
),
(
unsigned
long
)
msg_part_subpart
(
part
,
0
),
mu_strerror
(
rc
));
return
0
;
printf
(
_
(
"Press <return> to show content..."
));
if
(
!
fgets
(
buf
,
sizeof
buf
,
stdin
)
||
buf
[
0
]
!=
'\n'
)
return
0
;
}
body_get_stream
(
body
,
&
bstr
);
rc
=
filter_create
(
&
dstr
,
bstr
,
encoding
,
MU_FILTER_DECODE
,
MU_STREAM_READ
);
if
(
rc
==
0
)
bstr
=
dstr
;
cat_message
(
out
,
bstr
);
if
(
dstr
)
stream_destroy
(
&
dstr
,
stream_get_owner
(
dstr
));
}
if
(
!
cmd
)
{
char
*
pager
=
mh_global_profile_get
(
"moreproc"
,
getenv
(
"PAGER"
));
if
(
pager
)
exec_internal
(
msg
,
part
,
encoding
,
pager
);
else
show_internal
(
msg
,
part
,
encoding
,
out
);
}
else
{
mhn_run_command
(
msg
,
part
,
encoding
,
cmd
,
flags
,
tempfile
);
free
(
cmd
);
unlink
(
tempfile
);
free
(
tempfile
);
}
return
0
;
}
int
show_message
(
message_t
msg
,
size_t
num
,
void
*
data
)
{
msg_part_t
part
=
msg_part_create
(
num
);
if
(
mhl_format
)
mhl_format_run
(
mhl_format
,
width
,
0
,
MHL_DISABLE_BODY
,
msg
,
(
stream_t
)
data
);
handle_message
(
msg
,
part
,
show_handler
,
data
);
msg_part_destroy
(
part
);
return
0
;
...
...
@@ -762,7 +1215,12 @@ show_message (message_t msg, size_t num, void *data)
void
show_iterator
(
mailbox_t
mbox
,
message_t
msg
,
size_t
num
,
void
*
data
)
{
msg_part_t
part
;
mh_message_number
(
msg
,
&
num
);
part
=
msg_part_create
(
num
);
show_message
(
msg
,
num
,
data
);
msg_part_destroy
(
part
);
}
int
...
...
@@ -807,6 +1265,222 @@ mhn_show ()
rc
=
mh_iterate
(
mbox
,
&
msgset
,
show_iterator
,
ostr
);
return
rc
;
}
/* ***************************** Store Mode ****************************** */
char
*
normalize_path
(
char
*
cwd
,
char
*
path
)
{
int
len
;
char
*
p
;
char
*
pcwd
=
NULL
;
if
(
!
path
)
return
path
;
if
(
path
[
0
]
==
'/'
)
return
NULL
;
if
(
!
cwd
)
cwd
=
pcwd
=
mu_getcwd
();
len
=
strlen
(
cwd
)
+
strlen
(
path
)
+
2
;
p
=
xmalloc
(
len
);
sprintf
(
p
,
"%s/%s"
,
cwd
,
path
);
path
=
p
;
/* delete trailing delimiter if any */
if
(
len
&&
path
[
len
-
1
]
==
'/'
)
path
[
len
-
1
]
=
0
;
/* Eliminate any /../ */
for
(
p
=
strchr
(
path
,
'.'
);
p
;
p
=
strchr
(
p
,
'.'
))
{
if
(
p
>
path
&&
p
[
-
1
]
==
'/'
)
{
if
(
p
[
1
]
==
'.'
&&
(
p
[
2
]
==
0
||
p
[
2
]
==
'/'
))
/* found */
{
char
*
q
,
*
s
;
/* Find previous delimiter */
for
(
q
=
p
-
2
;
*
q
!=
'/'
&&
q
>=
path
;
q
--
)
;
if
(
q
<
path
)
break
;
/* Copy stuff */
s
=
p
+
2
;
p
=
q
;
while
(
*
q
++
=
*
s
++
)
;
continue
;
}
}
p
++
;
}
if
(
path
[
0
]
==
0
)
{
path
[
0
]
=
'/'
;
path
[
1
]
=
0
;
}
len
=
strlen
(
cwd
);
if
(
strlen
(
path
)
<
len
||
memcmp
(
path
,
cwd
,
len
))
sfree
(
&
path
);
else
memmove
(
path
,
path
+
len
+
1
,
strlen
(
path
)
-
len
);
free
(
pcwd
);
return
path
;
}
int
store_handler
(
message_t
msg
,
msg_part_t
part
,
char
*
type
,
char
*
encoding
,
void
*
data
)
{
char
*
prefix
=
data
;
char
*
name
=
NULL
;
char
*
tmp
;
int
ismime
;
int
rc
;
stream_t
out
;
char
*
dir
=
mh_global_profile_get
(
"mhn-storage"
,
NULL
);
if
(
message_is_multipart
(
msg
,
&
ismime
)
==
0
&&
ismime
)
return
0
;
if
(
mode_options
&
OPT_AUTO
)
{
header_t
hdr
;
char
*
val
;
if
(
message_get_header
(
msg
,
&
hdr
)
==
0
&&
header_aget_value
(
hdr
,
MU_HEADER_CONTENT_DISPOSITION
,
&
val
)
==
0
)
{
int
argc
;
char
**
argv
;
if
(
argcv_get
(
val
,
"="
,
NULL
,
&
argc
,
&
argv
)
==
0
)
{
int
i
;
for
(
i
=
0
;
i
<
argc
;
i
++
)
{
if
(
strcmp
(
argv
[
i
],
"filename"
)
==
0
&&
++
i
<
argc
&&
argv
[
i
][
0
]
==
'='
&&
++
i
<
argc
)
{
name
=
normalize_path
(
dir
,
argv
[
i
]);
break
;
}
}
argcv_free
(
argc
,
argv
);
}
free
(
val
);
}
}
if
(
!
name
)
{
char
*
fname
=
mhn_store_command
(
msg
,
part
,
prefix
);
if
(
dir
)
asprintf
(
&
name
,
"%s/%s"
,
dir
,
fname
);
else
name
=
fname
;
}
tmp
=
msg_part_format
(
part
);
if
(
prefix
)
printf
(
_
(
"storing message %s part %s as file %s
\n
"
),
prefix
,
tmp
,
name
);
else
printf
(
_
(
"storing message %lu part %s as file %s
\n
"
),
(
unsigned
long
)
msg_part_subpart
(
part
,
0
),
tmp
,
name
);
free
(
tmp
);
if
(
!
(
mode_options
&
OPT_QUIET
)
&&
access
(
name
,
R_OK
)
==
0
)
{
char
*
p
;
int
rc
;
asprintf
(
&
p
,
_
(
"File %s already exists. Rewrite"
),
name
);
rc
=
mh_getyn
(
p
);
free
(
p
);
if
(
!
rc
)
{
free
(
name
);
return
0
;
}
}
rc
=
file_stream_create
(
&
out
,
name
,
MU_STREAM_WRITE
|
MU_STREAM_CREAT
);
if
(
rc
)
{
mh_error
(
_
(
"can't create output stream (file %s): %s"
),
name
,
mu_strerror
(
rc
));
free
(
name
);
return
rc
;
}
rc
=
stream_open
(
out
);
if
(
rc
)
{
mh_error
(
_
(
"can't open output stream (file %s): %s"
),
name
,
mu_strerror
(
rc
));
free
(
name
);
stream_destroy
(
&
out
,
stream_get_owner
(
out
));
return
rc
;
}
show_internal
(
msg
,
part
,
encoding
,
out
);
stream_destroy
(
&
out
,
stream_get_owner
(
out
));
free
(
name
);
return
0
;
}
void
store_message
(
message_t
msg
,
void
*
data
)
{
size_t
uid
;
msg_part_t
part
;
mh_message_number
(
msg
,
&
uid
);
part
=
msg_part_create
(
uid
);
handle_message
(
msg
,
part
,
store_handler
,
data
);
msg_part_destroy
(
part
);
}
void
store_iterator
(
mailbox_t
mbox
,
message_t
msg
,
size_t
num
,
void
*
data
)
{
store_message
(
msg
,
data
);
}
int
mhn_store
()
{
int
rc
=
0
;
if
(
message
)
{
char
*
p
=
strrchr
(
input_file
,
'/'
);
if
(
p
)
p
++
;
else
p
=
input_file
;
store_message
(
message
,
p
);
}
else
rc
=
mh_iterate
(
mbox
,
&
msgset
,
store_iterator
,
NULL
);
return
rc
;
}
...
...
@@ -859,8 +1533,7 @@ main (int argc, char **argv)
break
;
case
mode_store
:
mh_error
(
"mode is not yet implemented"
);
rc
=
1
;
rc
=
mhn_store
();
break
;
default
:
...
...
Please
register
or
sign in
to post a comment