Page Menu
Home
GnuPG
Search
Configure Global Search
Log In
Files
F23642663
mime-parser.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Size
24 KB
Subscribers
None
mime-parser.c
View Options
/* mime-parser.c - Parse MIME structures (high level rfc822 parser).
* Copyright (C) 2016 g10 Code GmbH
*
* This file is part of GnuPG.
*
* GnuPG is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* GnuPG is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include
<config.h>
#include
<stdio.h>
#include
<stdlib.h>
#include
<string.h>
#include
"util.h"
#include
"rfc822parse.h"
#include
"mime-parser.h"
enum
pgpmime_states
{
PGPMIME_NONE
=
0
,
PGPMIME_WAIT_ENCVERSION
,
PGPMIME_IN_ENCVERSION
,
PGPMIME_WAIT_ENCDATA
,
PGPMIME_IN_ENCDATA
,
PGPMIME_GOT_ENCDATA
,
PGPMIME_WAIT_SIGNEDDATA
,
PGPMIME_IN_SIGNEDDATA
,
PGPMIME_WAIT_SIGNATURE
,
PGPMIME_IN_SIGNATURE
,
PGPMIME_GOT_SIGNATURE
,
PGPMIME_INVALID
};
/* Definition of the mime parser object. */
struct
mime_parser_context_s
{
void
*
cookie
;
/* Cookie passed to all callbacks. */
/* The callback to announce a new part. */
gpg_error_t
(
*
new_part
)
(
void
*
cookie
,
const
char
*
mediatype
,
const
char
*
mediasubtype
);
/* The callback to return data of a part. */
gpg_error_t
(
*
part_data
)
(
void
*
cookie
,
const
void
*
data
,
size_t
datalen
);
/* The callback to collect encrypted data. */
gpg_error_t
(
*
collect_encrypted
)
(
void
*
cookie
,
const
char
*
data
);
/* The callback to collect signed data. */
gpg_error_t
(
*
collect_signeddata
)
(
void
*
cookie
,
const
char
*
data
);
/* The callback to collect a signature. */
gpg_error_t
(
*
collect_signature
)
(
void
*
cookie
,
const
char
*
data
);
/* Helper to convey error codes from user callbacks. */
gpg_error_t
err
;
int
nesting_level
;
/* The current nesting level. */
int
hashing_at_level
;
/* The nesting level at which we are hashing. */
enum
pgpmime_states
pgpmime
;
/* Current PGP/MIME state. */
unsigned
int
delay_hashing
:
1
;
/* Helper for PGPMIME_IN_SIGNEDDATA. */
unsigned
int
want_part
:
1
;
/* Return the current part. */
unsigned
int
decode_part
:
2
;
/* Decode the part. 1 = QP, 2 = Base64. */
unsigned
int
verbose
:
1
;
/* Enable verbose mode. */
unsigned
int
debug
:
1
;
/* Enable debug mode. */
/* Flags to help with debug output. */
struct
{
unsigned
int
n_skip
;
/* Skip showing these number of lines. */
unsigned
int
header
:
1
;
/* Show the header lines. */
unsigned
int
data
:
1
;
/* Show the data lines. */
unsigned
int
as_note
:
1
;
/* Show the next data line as a note. */
unsigned
int
boundary
:
1
;
}
show
;
struct
b64state
*
b64state
;
/* NULL or malloced Base64 decoder state. */
/* A buffer for reading a mail line, */
char
line
[
5000
];
};
/* Print the event received by the parser for debugging. */
static
void
show_message_parser_event
(
rfc822parse_event_t
event
)
{
const
char
*
s
;
switch
(
event
)
{
case
RFC822PARSE_OPEN
:
s
=
"Open"
;
break
;
case
RFC822PARSE_CLOSE
:
s
=
"Close"
;
break
;
case
RFC822PARSE_CANCEL
:
s
=
"Cancel"
;
break
;
case
RFC822PARSE_T2BODY
:
s
=
"T2Body"
;
break
;
case
RFC822PARSE_FINISH
:
s
=
"Finish"
;
break
;
case
RFC822PARSE_RCVD_SEEN
:
s
=
"Rcvd_Seen"
;
break
;
case
RFC822PARSE_LEVEL_DOWN
:
s
=
"Level_Down"
;
break
;
case
RFC822PARSE_LEVEL_UP
:
s
=
"Level_Up"
;
break
;
case
RFC822PARSE_BOUNDARY
:
s
=
"Boundary"
;
break
;
case
RFC822PARSE_LAST_BOUNDARY
:
s
=
"Last_Boundary"
;
break
;
case
RFC822PARSE_BEGIN_HEADER
:
s
=
"Begin_Header"
;
break
;
case
RFC822PARSE_PREAMBLE
:
s
=
"Preamble"
;
break
;
case
RFC822PARSE_EPILOGUE
:
s
=
"Epilogue"
;
break
;
default
:
s
=
"[unknown event]"
;
break
;
}
log_debug
(
"*** RFC822 event %s
\n
"
,
s
);
}
/* Do in-place decoding of quoted-printable data of LENGTH in BUFFER.
Returns the new length of the buffer and stores true at R_SLBRK if
the line ended with a soft line break; false is stored if not.
This function asssumes that a complete line is passed in
buffer. */
static
size_t
qp_decode
(
char
*
buffer
,
size_t
length
,
int
*
r_slbrk
)
{
char
*
d
,
*
s
;
if
(
r_slbrk
)
*
r_slbrk
=
0
;
/* Fixme: We should remove trailing white space first. */
for
(
s
=
d
=
buffer
;
length
;
length
--
)
{
if
(
*
s
==
'='
)
{
if
(
length
>
2
&&
hexdigitp
(
s
+
1
)
&&
hexdigitp
(
s
+
2
))
{
s
++
;
*
(
unsigned
char
*
)
d
++
=
xtoi_2
(
s
);
s
+=
2
;
length
-=
2
;
}
else
if
(
length
>
2
&&
s
[
1
]
==
'\r'
&&
s
[
2
]
==
'\n'
)
{
/* Soft line break. */
s
+=
3
;
length
-=
2
;
if
(
r_slbrk
&&
length
==
1
)
*
r_slbrk
=
1
;
}
else
if
(
length
>
1
&&
s
[
1
]
==
'\n'
)
{
/* Soft line break with only a Unix line terminator. */
s
+=
2
;
length
-=
1
;
if
(
r_slbrk
&&
length
==
1
)
*
r_slbrk
=
1
;
}
else
if
(
length
==
1
)
{
/* Soft line break at the end of the line. */
s
+=
1
;
if
(
r_slbrk
)
*
r_slbrk
=
1
;
}
else
*
d
++
=
*
s
++
;
}
else
*
d
++
=
*
s
++
;
}
return
d
-
buffer
;
}
/* This function is called by parse_mail to communicate events. This
* callback communicates with the caller using a structure passed in
* OPAQUE. Should return 0 on success or set ERRNO and return -1. */
static
int
parse_message_cb
(
void
*
opaque
,
rfc822parse_event_t
event
,
rfc822parse_t
msg
)
{
mime_parser_t
ctx
=
opaque
;
const
char
*
s
;
int
rc
=
0
;
if
(
ctx
->
debug
)
show_message_parser_event
(
event
);
if
(
event
==
RFC822PARSE_BEGIN_HEADER
||
event
==
RFC822PARSE_T2BODY
)
{
/* We need to check here whether to start collecting signed data
* because attachments might come without header lines and thus
* we won't see the BEGIN_HEADER event. */
if
(
ctx
->
pgpmime
==
PGPMIME_WAIT_SIGNEDDATA
)
{
if
(
ctx
->
debug
)
log_debug
(
"begin_hash
\n
"
);
ctx
->
hashing_at_level
=
ctx
->
nesting_level
;
ctx
->
pgpmime
=
PGPMIME_IN_SIGNEDDATA
;
ctx
->
delay_hashing
=
0
;
}
}
if
(
event
==
RFC822PARSE_OPEN
)
{
/* Initialize for a new message. */
ctx
->
show
.
header
=
1
;
}
else
if
(
event
==
RFC822PARSE_T2BODY
)
{
rfc822parse_field_t
field
;
ctx
->
want_part
=
0
;
ctx
->
decode_part
=
0
;
field
=
rfc822parse_parse_field
(
msg
,
"Content-Type"
,
-1
);
if
(
field
)
{
const
char
*
s1
,
*
s2
;
s1
=
rfc822parse_query_media_type
(
field
,
&
s2
);
if
(
s1
)
{
if
(
ctx
->
verbose
)
log_debug
(
"h media: %*s%s %s
\n
"
,
ctx
->
nesting_level
*
2
,
""
,
s1
,
s2
);
if
(
ctx
->
pgpmime
==
PGPMIME_WAIT_ENCVERSION
)
{
if
(
!
strcmp
(
s1
,
"application"
)
&&
!
strcmp
(
s2
,
"pgp-encrypted"
))
{
if
(
ctx
->
debug
)
log_debug
(
"c begin_encversion
\n
"
);
ctx
->
pgpmime
=
PGPMIME_IN_ENCVERSION
;
}
else
{
log_error
(
"invalid PGP/MIME structure;"
" expected '%s', got '%s/%s'
\n
"
,
"application/pgp-encrypted"
,
s1
,
s2
);
ctx
->
pgpmime
=
PGPMIME_INVALID
;
}
}
else
if
(
ctx
->
pgpmime
==
PGPMIME_WAIT_ENCDATA
)
{
if
(
!
strcmp
(
s1
,
"application"
)
&&
!
strcmp
(
s2
,
"octet-stream"
))
{
if
(
ctx
->
debug
)
log_debug
(
"c begin_encdata
\n
"
);
ctx
->
pgpmime
=
PGPMIME_IN_ENCDATA
;
}
else
{
log_error
(
"invalid PGP/MIME structure;"
" expected '%s', got '%s/%s'
\n
"
,
"application/octet-stream"
,
s1
,
s2
);
ctx
->
pgpmime
=
PGPMIME_INVALID
;
}
}
else
if
(
ctx
->
pgpmime
==
PGPMIME_WAIT_SIGNATURE
)
{
if
(
!
strcmp
(
s1
,
"application"
)
&&
!
strcmp
(
s2
,
"pgp-signature"
))
{
if
(
ctx
->
debug
)
log_debug
(
"c begin_signature
\n
"
);
ctx
->
pgpmime
=
PGPMIME_IN_SIGNATURE
;
}
else
{
log_error
(
"invalid PGP/MIME structure;"
" expected '%s', got '%s/%s'
\n
"
,
"application/pgp-signature"
,
s1
,
s2
);
ctx
->
pgpmime
=
PGPMIME_INVALID
;
}
}
else
if
(
!
strcmp
(
s1
,
"multipart"
)
&&
!
strcmp
(
s2
,
"encrypted"
))
{
s
=
rfc822parse_query_parameter
(
field
,
"protocol"
,
0
);
if
(
s
)
{
if
(
ctx
->
debug
)
log_debug
(
"h encrypted.protocol: %s
\n
"
,
s
);
if
(
!
strcmp
(
s
,
"application/pgp-encrypted"
))
{
if
(
ctx
->
pgpmime
)
log_error
(
"note: "
"ignoring nested PGP/MIME signature
\n
"
);
else
ctx
->
pgpmime
=
PGPMIME_WAIT_ENCVERSION
;
}
else
if
(
ctx
->
verbose
)
log_debug
(
"# this protocol is not supported
\n
"
);
}
}
else
if
(
!
strcmp
(
s1
,
"multipart"
)
&&
!
strcmp
(
s2
,
"signed"
))
{
s
=
rfc822parse_query_parameter
(
field
,
"protocol"
,
1
);
if
(
s
)
{
if
(
ctx
->
debug
)
log_debug
(
"h signed.protocol: %s
\n
"
,
s
);
if
(
!
strcmp
(
s
,
"application/pgp-signature"
))
{
if
(
ctx
->
pgpmime
)
log_error
(
"note: "
"ignoring nested PGP/MIME signature
\n
"
);
else
ctx
->
pgpmime
=
PGPMIME_WAIT_SIGNEDDATA
;
}
else
if
(
ctx
->
verbose
)
log_debug
(
"# this protocol is not supported
\n
"
);
}
}
else
if
(
ctx
->
new_part
)
{
ctx
->
err
=
ctx
->
new_part
(
ctx
->
cookie
,
s1
,
s2
);
if
(
!
ctx
->
err
)
ctx
->
want_part
=
1
;
else
if
(
gpg_err_code
(
ctx
->
err
)
==
GPG_ERR_FALSE
)
ctx
->
err
=
0
;
else
if
(
gpg_err_code
(
ctx
->
err
)
==
GPG_ERR_TRUE
)
{
ctx
->
want_part
=
ctx
->
decode_part
=
1
;
ctx
->
err
=
0
;
}
}
}
else
{
if
(
ctx
->
debug
)
log_debug
(
"h media: %*s none
\n
"
,
ctx
->
nesting_level
*
2
,
""
);
if
(
ctx
->
new_part
)
{
ctx
->
err
=
ctx
->
new_part
(
ctx
->
cookie
,
""
,
""
);
if
(
!
ctx
->
err
)
ctx
->
want_part
=
1
;
else
if
(
gpg_err_code
(
ctx
->
err
)
==
GPG_ERR_FALSE
)
ctx
->
err
=
0
;
else
if
(
gpg_err_code
(
ctx
->
err
)
==
GPG_ERR_TRUE
)
{
ctx
->
want_part
=
ctx
->
decode_part
=
1
;
ctx
->
err
=
0
;
}
}
}
rfc822parse_release_field
(
field
);
}
else
{
if
(
ctx
->
verbose
)
log_debug
(
"h media: %*stext plain [assumed]
\n
"
,
ctx
->
nesting_level
*
2
,
""
);
if
(
ctx
->
new_part
)
{
ctx
->
err
=
ctx
->
new_part
(
ctx
->
cookie
,
"text"
,
"plain"
);
if
(
!
ctx
->
err
)
ctx
->
want_part
=
1
;
else
if
(
gpg_err_code
(
ctx
->
err
)
==
GPG_ERR_FALSE
)
ctx
->
err
=
0
;
else
if
(
gpg_err_code
(
ctx
->
err
)
==
GPG_ERR_TRUE
)
{
ctx
->
want_part
=
ctx
->
decode_part
=
1
;
ctx
->
err
=
0
;
}
}
}
/* Figure out the encoding if needed. */
if
(
ctx
->
decode_part
)
{
char
*
value
;
size_t
valueoff
;
ctx
->
decode_part
=
0
;
/* Fallback for unknown encoding. */
value
=
rfc822parse_get_field
(
msg
,
"Content-Transfer-Encoding"
,
-1
,
&
valueoff
);
if
(
value
)
{
if
(
!
stricmp
(
value
+
valueoff
,
"quoted-printable"
))
ctx
->
decode_part
=
1
;
else
if
(
!
stricmp
(
value
+
valueoff
,
"base64"
))
{
ctx
->
decode_part
=
2
;
if
(
ctx
->
b64state
)
b64dec_finish
(
ctx
->
b64state
);
/* Reuse state. */
else
{
ctx
->
b64state
=
xtrymalloc
(
sizeof
*
ctx
->
b64state
);
if
(
!
ctx
->
b64state
)
rc
=
gpg_error_from_syserror
();
}
if
(
!
rc
)
rc
=
b64dec_start
(
ctx
->
b64state
,
NULL
);
}
free
(
value
);
/* Right, we need a plain free. */
}
}
ctx
->
show
.
header
=
0
;
ctx
->
show
.
data
=
1
;
ctx
->
show
.
n_skip
=
1
;
}
else
if
(
event
==
RFC822PARSE_PREAMBLE
)
ctx
->
show
.
as_note
=
1
;
else
if
(
event
==
RFC822PARSE_LEVEL_DOWN
)
{
if
(
ctx
->
debug
)
log_debug
(
"b down
\n
"
);
ctx
->
nesting_level
++
;
}
else
if
(
event
==
RFC822PARSE_LEVEL_UP
)
{
if
(
ctx
->
debug
)
log_debug
(
"b up
\n
"
);
if
(
ctx
->
nesting_level
)
ctx
->
nesting_level
--
;
else
log_error
(
"invalid structure (bad nesting level)
\n
"
);
}
else
if
(
event
==
RFC822PARSE_BOUNDARY
||
event
==
RFC822PARSE_LAST_BOUNDARY
)
{
ctx
->
show
.
data
=
0
;
ctx
->
show
.
boundary
=
1
;
if
(
event
==
RFC822PARSE_BOUNDARY
)
{
ctx
->
show
.
header
=
1
;
ctx
->
show
.
n_skip
=
1
;
if
(
ctx
->
debug
)
log_debug
(
"b part
\n
"
);
}
else
if
(
ctx
->
debug
)
log_debug
(
"b last
\n
"
);
if
(
ctx
->
pgpmime
==
PGPMIME_IN_ENCDATA
)
{
if
(
ctx
->
debug
)
log_debug
(
"c end_encdata
\n
"
);
ctx
->
pgpmime
=
PGPMIME_GOT_ENCDATA
;
/* FIXME: We should assert (event == LAST_BOUNDARY). */
}
else
if
(
ctx
->
pgpmime
==
PGPMIME_IN_SIGNEDDATA
&&
ctx
->
nesting_level
==
ctx
->
hashing_at_level
)
{
if
(
ctx
->
debug
)
log_debug
(
"c end_hash
\n
"
);
ctx
->
pgpmime
=
PGPMIME_WAIT_SIGNATURE
;
if
(
ctx
->
collect_signeddata
)
ctx
->
err
=
ctx
->
collect_signeddata
(
ctx
->
cookie
,
NULL
);
}
else
if
(
ctx
->
pgpmime
==
PGPMIME_IN_SIGNATURE
)
{
if
(
ctx
->
debug
)
log_debug
(
"c end_signature
\n
"
);
ctx
->
pgpmime
=
PGPMIME_GOT_SIGNATURE
;
/* FIXME: We should assert (event == LAST_BOUNDARY). */
}
else
if
(
ctx
->
want_part
)
{
if
(
ctx
->
part_data
)
{
/* FIXME: We may need to flush things. */
ctx
->
err
=
ctx
->
part_data
(
ctx
->
cookie
,
NULL
,
0
);
}
ctx
->
want_part
=
0
;
}
}
return
rc
;
}
/* Create a new mime parser object. COOKIE is a values which will be
* used as first argument for all callbacks registered with this
* parser object. */
gpg_error_t
mime_parser_new
(
mime_parser_t
*
r_parser
,
void
*
cookie
)
{
mime_parser_t
ctx
;
*
r_parser
=
NULL
;
ctx
=
xtrycalloc
(
1
,
sizeof
*
ctx
);
if
(
!
ctx
)
return
gpg_error_from_syserror
();
ctx
->
cookie
=
cookie
;
*
r_parser
=
ctx
;
return
0
;
}
/* Release a mime parser object. */
void
mime_parser_release
(
mime_parser_t
ctx
)
{
if
(
!
ctx
)
return
;
if
(
ctx
->
b64state
)
{
b64dec_finish
(
ctx
->
b64state
);
xfree
(
ctx
->
b64state
);
}
xfree
(
ctx
);
}
/* Set verbose and debug mode. */
void
mime_parser_set_verbose
(
mime_parser_t
ctx
,
int
level
)
{
if
(
!
level
)
{
ctx
->
verbose
=
0
;
ctx
->
debug
=
0
;
}
else
{
ctx
->
verbose
=
1
;
if
(
level
>
10
)
ctx
->
debug
=
1
;
}
}
/* Set the callback used to announce a new part. It will be called
* with the media type and media subtype of the part. If no
* Content-type header was given both values are the empty string.
* The callback should return 0 on success or an error code. The
* error code GPG_ERR_FALSE indicates that the caller is not
* interested in the part and data shall not be returned via a
* registered part_data callback. The error code GPG_ERR_TRUE
* indicates that the parts shall be redurned in decoded format
* (i.e. base64 or QP encoding is removed). */
void
mime_parser_set_new_part
(
mime_parser_t
ctx
,
gpg_error_t
(
*
fnc
)
(
void
*
cookie
,
const
char
*
mediatype
,
const
char
*
mediasubtype
))
{
ctx
->
new_part
=
fnc
;
}
/* Set the callback used to return the data of a part to the caller.
* The end of the part is indicated by passing NUL for DATA. */
void
mime_parser_set_part_data
(
mime_parser_t
ctx
,
gpg_error_t
(
*
fnc
)
(
void
*
cookie
,
const
void
*
data
,
size_t
datalen
))
{
ctx
->
part_data
=
fnc
;
}
/* Set the callback to collect encrypted data. A NULL passed to the
* callback indicates the end of the encrypted data; the callback may
* then decrypt the collected data. */
void
mime_parser_set_collect_encrypted
(
mime_parser_t
ctx
,
gpg_error_t
(
*
fnc
)
(
void
*
cookie
,
const
char
*
data
))
{
ctx
->
collect_encrypted
=
fnc
;
}
/* Set the callback to collect signed data. A NULL passed to the
* callback indicates the end of the signed data. */
void
mime_parser_set_collect_signeddata
(
mime_parser_t
ctx
,
gpg_error_t
(
*
fnc
)
(
void
*
cookie
,
const
char
*
data
))
{
ctx
->
collect_signeddata
=
fnc
;
}
/* Set the callback to collect the signature. A NULL passed to the
* callback indicates the end of the signature; the callback may the
* verify the signature. */
void
mime_parser_set_collect_signature
(
mime_parser_t
ctx
,
gpg_error_t
(
*
fnc
)
(
void
*
cookie
,
const
char
*
data
))
{
ctx
->
collect_signature
=
fnc
;
}
/* Read and parse a message from FP and call the appropriate
* callbacks. */
gpg_error_t
mime_parser_parse
(
mime_parser_t
ctx
,
estream_t
fp
)
{
gpg_error_t
err
;
rfc822parse_t
msg
=
NULL
;
unsigned
int
lineno
=
0
;
size_t
length
,
nbytes
;
char
*
line
;
line
=
ctx
->
line
;
msg
=
rfc822parse_open
(
parse_message_cb
,
ctx
);
if
(
!
msg
)
{
err
=
gpg_error_from_syserror
();
log_error
(
"can't open mail parser: %s"
,
gpg_strerror
(
err
));
goto
leave
;
}
/* Fixme: We should not use fgets because it can't cope with
embedded nul characters. */
while
(
es_fgets
(
ctx
->
line
,
sizeof
(
ctx
->
line
),
fp
))
{
lineno
++
;
if
(
lineno
==
1
&&
!
strncmp
(
line
,
"From "
,
5
))
continue
;
/* We better ignore a leading From line. */
length
=
strlen
(
line
);
if
(
length
&&
line
[
length
-
1
]
==
'\n'
)
line
[
--
length
]
=
0
;
else
log_error
(
"mail parser detected too long or"
" non terminated last line (lnr=%u)
\
n
", lineno)
;
if
(
length
&&
line
[
length
-
1
]
==
'\r'
)
line
[
--
length
]
=
0
;
ctx
->
err
=
0
;
if
(
rfc822parse_insert
(
msg
,
line
,
length
))
{
err
=
gpg_error_from_syserror
();
log_error
(
"mail parser failed: %s"
,
gpg_strerror
(
err
));
goto
leave
;
}
if
(
ctx
->
err
)
{
/* Error from a callback detected. */
err
=
ctx
->
err
;
goto
leave
;
}
/* Debug output. Note that the boundary is shown before n_skip
* is evaluated. */
if
(
ctx
->
show
.
boundary
)
{
if
(
ctx
->
debug
)
log_debug
(
"# Boundary: %s
\n
"
,
line
);
ctx
->
show
.
boundary
=
0
;
}
if
(
ctx
->
show
.
n_skip
)
ctx
->
show
.
n_skip
--
;
else
if
(
ctx
->
show
.
data
)
{
if
(
ctx
->
show
.
as_note
)
{
if
(
ctx
->
verbose
)
log_debug
(
"# Note: %s
\n
"
,
line
);
ctx
->
show
.
as_note
=
0
;
}
else
if
(
ctx
->
debug
)
log_debug
(
"# Data: %s
\n
"
,
line
);
}
else
if
(
ctx
->
show
.
header
&&
ctx
->
verbose
)
log_debug
(
"# Header: %s
\n
"
,
line
);
if
(
ctx
->
pgpmime
==
PGPMIME_IN_ENCVERSION
)
{
trim_trailing_spaces
(
line
);
if
(
!*
line
)
;
/* Skip empty lines. */
else
if
(
!
strcmp
(
line
,
"Version: 1"
))
ctx
->
pgpmime
=
PGPMIME_WAIT_ENCDATA
;
else
{
log_error
(
"invalid PGP/MIME structure;"
" garbage in pgp-encrypted part ('%s')
\n
"
,
line
);
ctx
->
pgpmime
=
PGPMIME_INVALID
;
}
}
else
if
(
ctx
->
pgpmime
==
PGPMIME_IN_ENCDATA
)
{
if
(
ctx
->
collect_encrypted
)
{
err
=
ctx
->
collect_encrypted
(
ctx
->
cookie
,
line
);
if
(
!
err
)
err
=
ctx
->
collect_encrypted
(
ctx
->
cookie
,
"
\r\n
"
);
if
(
err
)
goto
leave
;
}
}
else
if
(
ctx
->
pgpmime
==
PGPMIME_GOT_ENCDATA
)
{
ctx
->
pgpmime
=
PGPMIME_NONE
;
if
(
ctx
->
collect_encrypted
)
ctx
->
collect_encrypted
(
ctx
->
cookie
,
NULL
);
}
else
if
(
ctx
->
pgpmime
==
PGPMIME_IN_SIGNEDDATA
)
{
/* If we are processing signed data, store the signed data.
* We need to delay the hashing of the CR/LF because the
* last line ending belongs to the next boundary. This is
* the reason why we can't use the PGPMIME state as a
* condition. */
if
(
ctx
->
debug
)
log_debug
(
"# hashing %s'%s'
\n
"
,
ctx
->
delay_hashing
?
"CR,LF+"
:
""
,
line
);
if
(
ctx
->
collect_signeddata
)
{
if
(
ctx
->
delay_hashing
)
ctx
->
collect_signeddata
(
ctx
->
cookie
,
"
\r\n
"
);
ctx
->
collect_signeddata
(
ctx
->
cookie
,
line
);
}
ctx
->
delay_hashing
=
1
;
}
else
if
(
ctx
->
pgpmime
==
PGPMIME_IN_SIGNATURE
)
{
if
(
ctx
->
collect_signeddata
)
{
ctx
->
collect_signature
(
ctx
->
cookie
,
line
);
ctx
->
collect_signature
(
ctx
->
cookie
,
"
\r\n
"
);
}
}
else
if
(
ctx
->
pgpmime
==
PGPMIME_GOT_SIGNATURE
)
{
ctx
->
pgpmime
=
PGPMIME_NONE
;
if
(
ctx
->
collect_signeddata
)
ctx
->
collect_signature
(
ctx
->
cookie
,
NULL
);
}
else
if
(
ctx
->
want_part
)
{
if
(
ctx
->
part_data
)
{
if
(
ctx
->
decode_part
==
1
)
{
length
=
qp_decode
(
line
,
length
,
NULL
);
}
else
if
(
ctx
->
decode_part
==
2
)
{
log_assert
(
ctx
->
b64state
);
err
=
b64dec_proc
(
ctx
->
b64state
,
line
,
length
,
&
nbytes
);
if
(
err
)
goto
leave
;
length
=
nbytes
;
}
err
=
ctx
->
part_data
(
ctx
->
cookie
,
line
,
length
);
if
(
err
)
goto
leave
;
}
}
}
rfc822parse_close
(
msg
);
msg
=
NULL
;
err
=
0
;
leave
:
rfc822parse_cancel
(
msg
);
return
err
;
}
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Tue, Jun 3, 5:35 AM (10 h, 10 m)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
29/ec/313a36029ea67889205771eea336
Attached To
rG GnuPG
Event Timeline
Log In to Comment