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
efc4fcd5
...
efc4fcd5d14ff42b4159cbd80d60ba7eea7df772
authored
2003-03-18 23:15:36 +0000
by
Sergey Poznyakoff
Browse Files
Options
Browse Files
Tag
Download
Email Patches
Plain Diff
Added framework for compose mode.
1 parent
513b47a4
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
444 additions
and
2 deletions
mh/mhn.c
mh/mhn.c
View file @
efc4fcd
...
...
@@ -18,6 +18,7 @@
/* MH mhn command */
#include <mh.h>
#include <mailutils/mime.h>
#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free
#include <obstack.h>
...
...
@@ -1483,6 +1484,433 @@ mhn_store ()
}
/* ***************************** Compose Mode **************************** */
int
stream_getline
(
stream_t
str
,
char
**
buf
,
size_t
*
bufsize
,
size_t
*
pnum
)
{
int
rc
;
size_t
numread
,
n
;
if
(
!*
buf
)
{
*
bufsize
=
128
;
*
buf
=
xmalloc
(
*
bufsize
);
}
numread
=
0
;
while
((
rc
=
stream_sequential_readline
(
str
,
*
buf
+
numread
,
*
bufsize
,
&
n
))
==
0
&&
n
>
0
)
{
numread
+=
n
;
if
((
*
buf
)[
numread
-
1
]
!=
'\n'
)
{
if
(
numread
==
*
bufsize
)
{
*
bufsize
+=
128
;
*
buf
=
xrealloc
(
*
buf
,
*
bufsize
);
}
continue
;
}
break
;
}
if
(
pnum
)
*
pnum
=
numread
;
return
rc
;
}
struct
compose_env
{
stream_t
input
;
mime_t
mime
;
size_t
line
;
};
size_t
mhn_error_loc
(
struct
compose_env
*
env
)
{
header_t
hdr
=
NULL
;
size_t
n
=
0
;
message_get_header
(
message
,
&
hdr
);
header_lines
(
hdr
,
&
n
);
return
n
+
1
+
env
->
line
;
}
static
int
parse_brace
(
char
**
pval
,
char
**
cmd
,
int
c
,
struct
compose_env
*
env
)
{
char
*
val
;
int
len
;
char
*
rest
=
*
cmd
;
char
*
sp
=
strchr
(
rest
,
c
);
if
(
!
sp
)
{
mh_error
(
"%s:%lu: missing %c"
,
input_file
,
(
unsigned
long
)
mhn_error_loc
(
env
),
c
);
return
1
;
}
len
=
sp
-
rest
;
val
=
xmalloc
(
len
+
1
);
memcpy
(
val
,
rest
,
len
);
val
[
len
]
=
0
;
*
cmd
=
sp
+
1
;
*
pval
=
val
;
return
0
;
}
/* cmd is: type "/" subtype
0*(";" attribute "=" value)
[ "(" comment ")" ]
[ "<" id ">" ]
[ "[" description "]" ]
*/
int
parse_type_command
(
char
*
cmd
,
char
**
prest
,
struct
compose_env
*
env
,
header_t
hdr
)
{
int
status
=
0
,
stop
=
0
;
char
*
sp
;
char
*
type
=
NULL
;
char
*
subtype
=
NULL
;
char
*
comment
=
NULL
,
*
descr
=
NULL
,
*
id
=
NULL
;
struct
obstack
stk
;
char
*
rest
=
*
prest
;
while
(
*
rest
&&
isspace
(
*
rest
))
rest
++
;
split_content
(
cmd
,
&
type
,
&
subtype
);
if
(
!
subtype
)
{
if
(
*
rest
!=
'/'
)
{
mh_error
(
"%s:%lu: expected / but found %s"
,
input_file
,
(
unsigned
long
)
mhn_error_loc
(
env
),
rest
);
return
1
;
}
for
(
rest
++
;
*
rest
&&
isspace
(
*
rest
);
rest
++
)
;
if
(
!*
rest
)
{
mh_error
(
"%s:%lu: missing subtype"
,
input_file
,
(
unsigned
long
)
mhn_error_loc
(
env
));
return
1
;
}
subtype
=
strtok_r
(
rest
,
";
\n
"
,
&
sp
);
subtype
=
strdup
(
subtype
);
rest
=
sp
;
}
obstack_init
(
&
stk
);
obstack_grow
(
&
stk
,
type
,
strlen
(
type
));
obstack_1grow
(
&
stk
,
'/'
);
obstack_grow
(
&
stk
,
subtype
,
strlen
(
subtype
));
while
(
stop
==
0
&&
status
==
0
&&
*
rest
)
{
switch
(
*
rest
++
)
{
case
'('
:
if
(
comment
)
{
mh_error
(
"%s:%lu: comment redefined"
,
input_file
,
(
unsigned
long
)
mhn_error_loc
(
env
));
status
=
1
;
break
;
}
status
=
parse_brace
(
&
comment
,
&
rest
,
')'
,
env
);
break
;
case
'['
:
if
(
descr
)
{
mh_error
(
"%s:%lu: description redefined"
,
input_file
,
(
unsigned
long
)
mhn_error_loc
(
env
));
status
=
1
;
break
;
}
status
=
parse_brace
(
&
descr
,
&
rest
,
']'
,
env
);
break
;
case
'<'
:
if
(
id
)
{
mh_error
(
"%s:%lu: content id redefined"
,
input_file
,
(
unsigned
long
)
mhn_error_loc
(
env
));
status
=
1
;
break
;
}
status
=
parse_brace
(
&
id
,
&
rest
,
'>'
,
env
);
break
;
case
';'
:
obstack_1grow
(
&
stk
,
';'
);
while
(
*
rest
&&
isspace
(
*
rest
))
rest
++
;
sp
=
rest
;
for
(;
*
rest
&&
!
isspace
(
*
rest
);
rest
++
)
obstack_1grow
(
&
stk
,
*
rest
);
while
(
*
rest
&&
isspace
(
*
rest
))
rest
++
;
if
(
*
rest
!=
'='
)
{
mh_error
(
"%s:%lu: syntax error"
,
input_file
,
(
unsigned
long
)
mhn_error_loc
(
env
));
status
=
1
;
break
;
}
obstack_1grow
(
&
stk
,
'='
);
while
(
*
rest
&&
isspace
(
*
rest
))
rest
++
;
for
(;
*
rest
;
rest
++
)
{
if
(
strchr
(
";<[("
,
*
rest
))
break
;
obstack_1grow
(
&
stk
,
*
rest
);
}
break
;
default:
stop
=
1
;
break
;
}
}
obstack_1grow
(
&
stk
,
0
);
header_set_value
(
hdr
,
MU_HEADER_CONTENT_TYPE
,
obstack_finish
(
&
stk
),
1
);
obstack_free
(
&
stk
,
NULL
);
if
(
!
id
)
id
=
mh_create_message_id
(
1
);
header_set_value
(
hdr
,
MU_HEADER_CONTENT_ID
,
id
,
1
);
free
(
comment
);
/* FIXME: comment was not used */
free
(
descr
);
free
(
id
);
*
prest
=
rest
;
return
status
;
}
int
edit_extern
(
char
*
cmd
,
char
*
rest
,
struct
compose_env
*
env
,
int
level
)
{
return
0
;
}
int
edit_forw
(
char
*
cmd
,
struct
compose_env
*
env
,
int
level
)
{
return
0
;
}
int
edit_mime
(
char
*
cmd
,
char
*
rest
,
struct
compose_env
*
env
,
int
level
)
{
int
rc
;
message_t
msg
;
header_t
hdr
;
message_create
(
&
msg
,
NULL
);
message_get_header
(
msg
,
&
hdr
);
rc
=
parse_type_command
(
cmd
,
&
rest
,
env
,
hdr
);
if
(
rc
==
0
)
mime_add_part
(
env
->
mime
,
msg
);
message_unref
(
msg
);
return
rc
;
}
int
mhn_edit
(
struct
compose_env
*
env
,
int
level
)
{
int
status
=
0
;
char
*
buf
=
NULL
;
size_t
bufsize
=
0
,
n
;
body_t
body
;
stream_t
output
;
message_t
msg
=
NULL
;
while
(
status
==
0
&&
stream_getline
(
env
->
input
,
&
buf
,
&
bufsize
,
&
n
)
==
0
&&
n
>
0
)
{
env
->
line
++
;
if
(
!
msg
)
{
/* Create new message */
message_create
(
&
msg
,
NULL
);
/*FIXME: Headers*/
message_get_body
(
msg
,
&
body
);
body_get_stream
(
body
,
&
output
);
stream_seek
(
output
,
0
,
SEEK_SET
);
}
if
(
buf
[
0
]
==
'#'
)
{
if
(
buf
[
1
]
==
'#'
)
stream_sequential_write
(
output
,
buf
+
1
,
n
-
1
);
else
{
char
*
b2
=
NULL
;
size_t
bs
=
0
,
n2
;
char
*
tok
,
*
sp
;
/* Collect the whole line */
while
(
n
>
2
&&
buf
[
n
-
2
]
==
'\\'
)
{
int
rc
=
stream_getline
(
env
->
input
,
&
b2
,
&
bs
,
&
n2
);
env
->
line
++
;
if
(
rc
==
0
&&
n2
>
0
)
{
if
(
n
+
n2
>
bufsize
)
{
bufsize
+=
128
;
buf
=
xrealloc
(
buf
,
bufsize
);
}
memcpy
(
buf
+
n
-
2
,
b2
,
n2
);
n
+=
n2
-
2
;
}
}
free
(
b2
);
/* Close and append the previous part */
stream_close
(
output
);
mime_add_part
(
env
->
mime
,
msg
);
message_unref
(
msg
);
msg
=
NULL
;
/* Execute the directive */
tok
=
strtok_r
(
buf
,
"
\n
"
,
&
sp
);
if
(
tok
[
1
]
==
'@'
)
status
=
edit_extern
(
tok
+
2
,
sp
,
env
,
level
);
else
if
(
strcmp
(
tok
,
"#forw"
)
==
0
)
status
=
edit_forw
(
sp
,
env
,
level
);
else
if
(
strcmp
(
tok
,
"#begin"
)
==
0
)
{
struct
compose_env
new_env
;
message_t
new_msg
;
new_env
.
input
=
env
->
input
;
new_env
.
line
=
env
->
line
;
mime_create
(
&
new_env
.
mime
,
NULL
,
0
);
status
=
mhn_edit
(
&
new_env
,
level
+
1
);
env
->
line
=
new_env
.
line
;
if
(
status
==
0
)
{
mime_get_message
(
new_env
.
mime
,
&
new_msg
);
mime_add_part
(
env
->
mime
,
new_msg
);
message_unref
(
new_msg
);
}
}
else
if
(
strcmp
(
tok
,
"#end"
)
==
0
)
{
if
(
level
==
0
)
{
mh_error
(
"%s:%lu: unmatched #end"
,
input_file
,
(
unsigned
long
)
mhn_error_loc
(
env
));
status
=
1
;
}
break
;
}
else
status
=
edit_mime
(
tok
+
1
,
sp
,
env
,
level
);
}
}
else
stream_sequential_write
(
output
,
buf
,
n
);
}
free
(
buf
);
if
(
msg
)
{
stream_close
(
output
);
mime_add_part
(
env
->
mime
,
msg
);
message_unref
(
msg
);
}
return
status
;
}
void
copy_header
(
message_t
msg
,
stream_t
stream
)
{
header_t
hdr
;
stream_t
in
;
char
*
buf
=
NULL
;
size_t
bufsize
,
n
;
message_get_header
(
msg
,
&
hdr
);
header_get_stream
(
hdr
,
&
in
);
stream_seek
(
in
,
0
,
SEEK_SET
);
while
(
stream_getline
(
in
,
&
buf
,
&
bufsize
,
&
n
)
==
0
&&
n
>
0
)
{
if
(
n
==
1
&&
buf
[
0
]
==
'\n'
)
break
;
stream_sequential_write
(
stream
,
buf
,
n
);
}
free
(
buf
);
}
int
mhn_compose
()
{
int
rc
;
mime_t
mime
=
NULL
;
body_t
body
;
stream_t
stream
,
in
;
struct
compose_env
env
;
message_t
msg
;
char
*
name
;
mime_create
(
&
mime
,
NULL
,
0
);
message_get_body
(
message
,
&
body
);
body_get_stream
(
body
,
&
stream
);
stream_seek
(
stream
,
0
,
SEEK_SET
);
env
.
mime
=
mime
;
env
.
input
=
stream
;
rc
=
mhn_edit
(
&
env
,
0
);
if
(
rc
)
return
rc
;
mime_get_message
(
mime
,
&
msg
);
asprintf
(
&
name
,
"%s/draft.mhn"
,
mu_path_folder_dir
);
unlink
(
name
);
rc
=
file_stream_create
(
&
stream
,
name
,
MU_STREAM_RDWR
|
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
(
stream
);
if
(
rc
)
{
mh_error
(
_
(
"can't open output stream (file %s): %s"
),
name
,
mu_strerror
(
rc
));
free
(
name
);
stream_destroy
(
&
stream
,
stream_get_owner
(
stream
));
return
rc
;
}
free
(
name
);
copy_header
(
message
,
stream
);
message_get_stream
(
msg
,
&
in
);
cat_message
(
stream
,
in
);
stream_destroy
(
&
stream
,
stream_get_owner
(
stream
));
return
0
;
}
/* *************************** Main Entry Point ************************** */
...
...
@@ -1511,6 +1939,18 @@ main (int argc, char **argv)
if
(
!
message
)
return
1
;
}
else
if
(
mode
==
mode_compose
)
{
if
(
argc
>
1
)
{
mh_error
(
_
(
"extra arguments"
));
return
1
;
}
input_file
=
argc
==
1
?
argv
[
0
]
:
"draft"
;
message
=
mh_file_to_message
(
mu_path_folder_dir
,
input_file
);
if
(
!
message
)
return
1
;
}
else
{
mbox
=
mh_open_folder
(
current_folder
,
0
);
...
...
@@ -1520,8 +1960,10 @@ main (int argc, char **argv)
switch
(
mode
)
{
case
mode_compose
:
mh_error
(
"mode is not yet implemented"
);
rc
=
1
;
/* Prepare filename for diagnostic purposes */
if
(
input_file
[
0
]
!=
'/'
)
asprintf
(
&
input_file
,
"%s/%s"
,
mu_path_folder_dir
,
input_file
);
rc
=
mhn_compose
();
break
;
case
mode_list
:
...
...
Please
register
or
sign in
to post a comment