Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F117885910
message.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Authored By
Unknown
Size
39 KB
Referenced Files
None
Subscribers
None
message.c
View Options
/*
* Message manipulation/parsing routines
*/
#include
<stdio.h>
#include
<ctype.h>
#include
<string.h>
#include
"imap_err.h"
#include
"mailbox.h"
#include
"parseadd.h"
#include
"xmalloc.h"
extern
PARSED_ADDRESS
*
AppendAddresses
();
/*
* Parsed form of a body-part
*/
struct
body
{
/* Content-* header information */
char
*
type
;
char
*
subtype
;
struct
param
*
params
;
char
*
id
;
char
*
description
;
char
*
encoding
;
char
*
md5
;
/* Location/size information */
long
header_offset
;
long
header_size
;
long
header_lines
;
long
content_offset
;
long
content_size
;
long
content_lines
;
long
boundary_size
;
/* Size of terminating boundary */
long
boundary_lines
;
int
numparts
;
/* For multipart types */
struct
body
*
subpart
;
/* For message/rfc822 and multipart types */
/*
* Other header information.
* Only meaningful for body-parts at top level or
* enclosed in message/rfc-822
*/
char
*
date
;
char
*
subject
;
PARSED_ADDRESS
*
from
;
PARSED_ADDRESS
*
sender
;
PARSED_ADDRESS
*
reply_to
;
PARSED_ADDRESS
*
to
;
PARSED_ADDRESS
*
cc
;
PARSED_ADDRESS
*
bcc
;
char
*
in_reply_to
;
char
*
message_id
;
};
/* List of Content-type parameters */
struct
param
{
struct
param
*
next
;
char
*
attribute
;
char
*
value
;
};
/* List of pending multipart boundaries */
struct
boundary
{
char
**
id
;
int
count
;
int
alloc
;
};
/* cyrus.cache file item buffer */
struct
ibuf
{
char
*
start
,
*
end
;
int
left
;
};
/* (draft standard) MIME tspecials */
#define TSPECIALS "()<>@,;:\\\"/[]?="
/* Default MIME Content-type */
#define DEFAULT_CONTENT_TYPE "TEXT/PLAIN; CHARSET=us-ascii"
/*
* Copy a message from 'from' to 'to', converting bare LF characters to CRLF.
*/
int
message_copy_byline
(
from
,
to
)
FILE
*
from
,
*
to
;
{
char
buf
[
4096
],
*
p
;
while
(
fgets
(
buf
,
sizeof
(
buf
)
-1
,
from
))
{
p
=
buf
+
strlen
(
buf
)
-
1
;
if
(
*
p
==
'\n'
)
{
if
(
p
==
buf
||
p
[
-1
]
!=
'\r'
)
{
p
[
0
]
=
'\r'
;
p
[
1
]
=
'\n'
;
p
[
2
]
=
'\0'
;
}
}
else
if
(
*
p
==
'\r'
)
{
/*
* We were unlucky enough to get a CR just before we ran
* out of buffer--put it back.
*/
ungetc
(
'\r'
,
from
);
*
p
=
'\0'
;
}
fputs
(
buf
,
to
);
}
fflush
(
to
);
if
(
ferror
(
from
)
||
ferror
(
to
)
||
fsync
(
fileno
(
to
)))
return
IMAP_IOERROR
;
return
0
;
}
/*
* Copy a message of 'size' bytes from 'from' to 'to',
* ensuring minimal RFC-822 compliance.
*/
int
message_copy_strict
(
from
,
to
,
size
)
FILE
*
from
;
FILE
*
to
;
{
char
buf
[
4096
+
1
];
unsigned
char
*
p
;
int
r
=
0
;
int
n
;
int
sawcr
=
0
,
sawnl
;
while
(
size
)
{
n
=
fread
(
buf
,
1
,
size
>
4096
?
4096
:
size
,
from
);
if
(
!
n
)
return
IMAP_IOERROR
;
buf
[
n
]
=
'\0'
;
if
(
n
!=
strlen
(
buf
))
r
=
IMAP_MESSAGE_CONTAINSNULL
;
size
-=
n
;
if
(
r
)
continue
;
for
(
p
=
buf
;
*
p
;
p
++
)
{
if
(
*
p
==
'\n'
)
{
if
(
!
sawcr
)
r
=
IMAP_MESSAGE_CONTAINSNL
;
sawcr
=
0
;
}
else
if
(
*
p
==
'\r'
)
{
sawcr
=
1
;
}
else
sawcr
=
0
;
}
fwrite
(
buf
,
1
,
n
,
to
);
}
if
(
r
)
return
r
;
fflush
(
to
);
if
(
ferror
(
to
)
||
fsync
(
fileno
(
to
)))
return
IMAP_IOERROR
;
rewind
(
to
);
/* Go back and check headers */
sawnl
=
1
;
for
(;;)
{
if
(
!
fgets
(
buf
,
sizeof
(
buf
),
to
))
return
IMAP_MESSAGE_NOBLANKLINE
;
/* End of header section */
if
(
sawnl
&&
buf
[
0
]
==
'\r'
)
return
0
;
/* Check for valid header name */
if
(
sawnl
&&
buf
[
0
]
!=
' '
&&
buf
[
0
]
!=
'\t'
)
{
if
(
buf
[
0
]
==
':'
)
return
IMAP_MESSAGE_BADHEADER
;
for
(
p
=
buf
;
*
p
!=
':'
;
p
++
)
{
if
(
*
p
<=
' '
)
return
IMAP_MESSAGE_BADHEADER
;
}
}
/* Check for non-ASCII character */
for
(
p
=
buf
;
*
p
;
p
++
)
{
if
(
*
p
>=
0x80
)
return
IMAP_MESSAGE_CONTAINS8BIT
;
}
sawnl
=
(
p
[
-1
]
==
'\n'
);
}
}
/*
* Parse the message 'infile' in 'mailbox'. Appends the message's
* cache information to the mailbox's cache file and fills in appropriate
* information in the index record pointed to by 'message_index'.
*/
message_parse
(
infile
,
mailbox
,
message_index
)
FILE
*
infile
;
struct
mailbox
*
mailbox
;
struct
index_record
*
message_index
;
{
struct
body
body
;
rewind
(
infile
);
message_parse_body
(
infile
,
mailbox
->
format
,
&
body
,
DEFAULT_CONTENT_TYPE
,
(
struct
boundary
*
)
0
);
message_index
->
size
=
body
.
header_size
+
body
.
content_size
;
message_index
->
header_size
=
body
.
header_size
;
message_index
->
content_offset
=
body
.
content_offset
;
message_index
->
cache_offset
=
ftell
(
mailbox
->
cache
);
message_write_cache
(
mailbox
->
cache
,
&
body
);
message_free_body
(
&
body
);
if
(
ferror
(
mailbox
->
cache
))
{
return
IMAP_IOERROR
;
}
return
0
;
}
/*
* Parse a body-part
*/
static
message_parse_body
(
infile
,
format
,
body
,
defaultContentType
,
boundaries
)
FILE
*
infile
;
int
format
;
struct
body
*
body
;
char
*
defaultContentType
;
struct
boundary
*
boundaries
;
{
struct
boundary
newboundaries
;
static
struct
body
zerobody
;
*
body
=
zerobody
;
newboundaries
.
id
=
0
;
/* No passed-in boundary structure, create a new, empty one */
if
(
!
boundaries
)
{
boundaries
=
&
newboundaries
;
boundaries
->
alloc
=
boundaries
->
count
=
0
;
}
message_parse_headers
(
infile
,
format
,
body
,
defaultContentType
,
boundaries
);
/* Recurse according to type */
if
(
strcmp
(
body
->
type
,
"MULTIPART"
)
==
0
)
{
message_parse_multipart
(
infile
,
format
,
body
,
boundaries
);
}
else
if
(
strcmp
(
body
->
type
,
"MESSAGE"
)
==
0
&&
strcmp
(
body
->
subtype
,
"RFC822"
)
==
0
)
{
body
->
subpart
=
(
struct
body
*
)
xmalloc
(
sizeof
(
struct
body
));
message_parse_body
(
infile
,
format
,
body
->
subpart
,
defaultContentType
,
boundaries
);
/* Calculate our size/lines information */
body
->
content_size
=
body
->
subpart
->
header_size
+
body
->
subpart
->
content_size
;
body
->
content_lines
=
body
->
subpart
->
header_lines
+
body
->
subpart
->
content_lines
;
/* Move any enclosing boundary information up to our level */
body
->
boundary_size
=
body
->
subpart
->
boundary_size
;
body
->
boundary_lines
=
body
->
subpart
->
boundary_lines
;
}
else
{
message_parse_content
(
infile
,
format
,
body
,
boundaries
);
}
/* Free up boundary storage if necessary */
if
(
newboundaries
.
id
)
free
(
newboundaries
.
id
);
}
/*
* Parse the headers of a body-part
*/
#define HEADGROWSIZE 1000
static
message_parse_headers
(
infile
,
format
,
body
,
defaultContentType
,
boundaries
)
FILE
*
infile
;
int
format
;
struct
body
*
body
;
char
*
defaultContentType
;
struct
boundary
*
boundaries
;
{
static
int
alloced
=
0
;
static
char
*
headers
;
int
left
,
len
;
char
*
next
;
body
->
header_offset
=
ftell
(
infile
);
if
(
!
alloced
)
{
headers
=
xmalloc
(
alloced
=
HEADGROWSIZE
);
}
next
=
headers
;
*
next
++
=
'\n'
;
/* Leading newline to prime the pump */
left
=
alloced
-
3
;
/* Allow for leading newline, added CR */
/* and trailing NUL */
/* Slurp up all of the headers into 'headers' */
while
(
fgets
(
next
,
left
,
infile
)
&&
(
next
[
-1
]
!=
'\n'
||
(
format
==
MAILBOX_FORMAT_NETNEWS
?
(
*
next
!=
'\n'
)
:
(
*
next
!=
'\r'
||
next
[
1
]
!=
'\n'
))))
{
if
(
next
[
-1
]
==
'\n'
&&
*
next
==
'-'
&&
PendingBoundary
(
next
,
boundaries
->
id
,
&
boundaries
->
count
))
{
body
->
boundary_size
=
strlen
(
next
)
+
(
format
==
MAILBOX_FORMAT_NETNEWS
);
body
->
boundary_lines
++
;
if
(
next
-
1
>
headers
)
{
body
->
boundary_size
+=
2
;
body
->
boundary_lines
++
;
next
[
-2
]
=
'\0'
;
}
else
{
*
next
=
'\0'
;
}
break
;
}
len
=
strlen
(
next
);
left
-=
len
;
next
+=
len
;
/* If reading netnews format, convert LF to CRLF */
if
(
format
==
MAILBOX_FORMAT_NETNEWS
&&
next
[
-1
]
==
'\n'
)
{
next
[
-1
]
=
'\r'
;
*
next
++
=
'\n'
;
*
next
=
'\0'
;
left
--
;
}
/* Allocate more header space if necessary */
if
(
left
<
100
)
{
len
=
next
-
headers
;
alloced
+=
HEADGROWSIZE
;
left
+=
HEADGROWSIZE
;
headers
=
xrealloc
(
headers
,
alloced
);
next
=
headers
+
len
;
}
}
body
->
content_offset
=
ftell
(
infile
);
body
->
header_size
=
strlen
(
headers
+
1
);
/* Scan over the slurped-up headers for interesting header information */
body
->
header_lines
=
-1
;
/* Correct for leading newline */
for
(
next
=
headers
;
*
next
;
next
++
)
{
if
(
*
next
==
'\n'
)
{
body
->
header_lines
++
;
switch
(
next
[
1
])
{
case
'b'
:
case
'B'
:
if
(
!
strncasecmp
(
next
+
2
,
"cc:"
,
3
))
{
message_parse_address
(
next
+
5
,
&
body
->
bcc
);
}
break
;
case
'c'
:
case
'C'
:
if
(
!
strncasecmp
(
next
+
2
,
"c:"
,
2
))
{
message_parse_address
(
next
+
4
,
&
body
->
cc
);
}
if
(
!
strncasecmp
(
next
+
2
,
"ontent-"
,
7
))
{
switch
(
next
[
9
])
{
case
'd'
:
case
'D'
:
if
(
!
strncasecmp
(
next
+
10
,
"escription:"
,
11
))
{
message_parse_string
(
next
+
21
,
&
body
->
description
);
}
break
;
case
'i'
:
case
'I'
:
if
(
!
strncasecmp
(
next
+
10
,
"d:"
,
2
))
{
message_parse_string
(
next
+
12
,
&
body
->
id
);
}
break
;
case
'm'
:
case
'M'
:
if
(
!
strncasecmp
(
next
+
10
,
"d5:"
,
3
))
{
message_parse_string
(
next
+
13
,
&
body
->
md5
);
}
break
;
case
't'
:
case
'T'
:
if
(
!
strncasecmp
(
next
+
10
,
"ransfer-encoding:"
,
17
))
{
message_parse_encoding
(
next
+
27
,
&
body
->
encoding
);
}
else
if
(
!
strncasecmp
(
next
+
10
,
"ype:"
,
4
))
{
message_parse_type
(
next
+
14
,
body
);
}
break
;
}
}
break
;
case
'd'
:
case
'D'
:
if
(
!
strncasecmp
(
next
+
2
,
"ate:"
,
4
))
{
message_parse_string
(
next
+
6
,
&
body
->
date
);
}
break
;
case
'f'
:
case
'F'
:
if
(
!
strncasecmp
(
next
+
2
,
"rom:"
,
4
))
{
message_parse_address
(
next
+
6
,
&
body
->
from
);
}
break
;
case
'i'
:
case
'I'
:
if
(
!
strncasecmp
(
next
+
2
,
"n-reply-to:"
,
11
))
{
message_parse_string
(
next
+
13
,
&
body
->
in_reply_to
);
}
break
;
case
'm'
:
case
'M'
:
if
(
!
strncasecmp
(
next
+
2
,
"essage-id:"
,
10
))
{
message_parse_string
(
next
+
12
,
&
body
->
message_id
);
}
break
;
case
'r'
:
case
'R'
:
if
(
!
strncasecmp
(
next
+
2
,
"eply-to:"
,
8
))
{
message_parse_address
(
next
+
10
,
&
body
->
reply_to
);
}
break
;
case
's'
:
case
'S'
:
if
(
!
strncasecmp
(
next
+
2
,
"ubject:"
,
7
))
{
message_parse_string
(
next
+
9
,
&
body
->
subject
);
}
if
(
!
strncasecmp
(
next
+
2
,
"ender:"
,
6
))
{
message_parse_address
(
next
+
8
,
&
body
->
sender
);
}
break
;
case
't'
:
case
'T'
:
if
(
!
strncasecmp
(
next
+
2
,
"o:"
,
2
))
{
message_parse_address
(
next
+
4
,
&
body
->
to
);
}
break
;
}
}
}
/* If didn't find Content-Type: header, use the passed-in default type */
if
(
!
body
->
type
)
{
message_parse_type
(
defaultContentType
,
body
);
}
}
/*
* Parse a list of RFC-822 addresses from a header, appending them
* to the address list pointed to by 'addrp'.
*/
static
message_parse_address
(
hdr
,
addrp
)
char
*
hdr
;
PARSED_ADDRESS
**
addrp
;
{
char
*
hdrend
,
hdrendchar
;
PARSED_ADDRESS
*
hdrlist
;
int
r
;
/* Find end of header */
hdrend
=
hdr
;
do
{
hdrend
=
strchr
(
hdrend
+
1
,
'\n'
);
}
while
(
hdrend
&&
(
hdrend
[
1
]
==
' '
||
hdrend
[
1
]
==
'\t'
));
/* Put a NUL character at the end of header */
if
(
hdrend
)
{
if
(
hdrend
>
hdr
&&
hdrend
[
-1
]
==
'\r'
)
hdrend
--
;
hdrendchar
=
*
hdrend
;
*
hdrend
=
'\0'
;
}
r
=
ParseAddressList
(
hdr
,
&
hdrlist
);
/* Put character at end of header back */
if
(
hdrend
)
*
hdrend
=
hdrendchar
;
if
(
r
)
return
;
*
addrp
=
AppendAddresses
(
*
addrp
,
hdrlist
);
}
/*
* Parse a Content-Transfer-Encoding from a header.
*/
static
message_parse_encoding
(
hdr
,
hdrp
)
char
*
hdr
;
char
**
hdrp
;
{
int
len
;
char
*
p
;
/* Ignore if we already saw one of these headers */
if
(
*
hdrp
)
return
;
/* Skip leading whitespace, ignore header if blank */
message_parse_rfc822space
(
&
hdr
);
if
(
!
hdr
)
return
;
/* Find end of encoding token */
for
(
p
=
hdr
;
*
p
&&
!
isspace
(
*
p
)
&&
*
p
!=
'('
;
p
++
)
{
if
(
*
p
<
' '
||
strchr
(
TSPECIALS
,
*
p
))
return
;
}
len
=
p
-
hdr
;
/* Skip trailing whitespace, ignore header if trailing garbage */
message_parse_rfc822space
(
&
p
);
if
(
p
)
return
;
/* Save encoding token */
*
hdrp
=
xmalloc
(
len
+
1
);
strncpy
(
*
hdrp
,
hdr
,
len
);
(
*
hdrp
)[
len
]
=
'\0'
;
for
(
p
=
*
hdrp
;
*
p
;
p
++
)
{
if
(
islower
(
*
p
))
*
p
=
toupper
(
*
p
);
}
}
/*
* Parse an uninterpreted header
*/
static
message_parse_string
(
hdr
,
hdrp
)
char
*
hdr
;
char
**
hdrp
;
{
int
len
;
char
*
hdrend
;
/* Ignore if we already saw one of these headers */
if
(
*
hdrp
)
return
;
/* Skip initial whitespace */
while
(
*
hdr
==
' '
||
*
hdr
==
'\t'
)
hdr
++
;
/* Find end of header */
hdrend
=
hdr
;
do
{
hdrend
=
strchr
(
hdrend
+
1
,
'\n'
);
}
while
(
hdrend
&&
(
hdrend
[
1
]
==
' '
||
hdrend
[
1
]
==
'\t'
));
if
(
hdrend
)
{
if
(
hdrend
>
hdr
&&
hdrend
[
-1
]
==
'\r'
)
hdrend
--
;
}
else
{
hdrend
=
hdr
+
strlen
(
hdr
);
}
/* Save header value */
len
=
hdrend
-
hdr
;
*
hdrp
=
xmalloc
(
len
+
1
);
strncpy
(
*
hdrp
,
hdr
,
len
);
(
*
hdrp
)[
len
]
=
'\0'
;
}
/*
* Parse a Content-Type from a header.
*/
static
message_parse_type
(
hdr
,
body
)
char
*
hdr
;
struct
body
*
body
;
{
char
*
type
;
int
typelen
;
char
*
subtype
;
int
subtypelen
;
char
*
p
;
/* Ignore if we already saw one of these headers */
if
(
body
->
type
)
return
;
/* Skip leading whitespace, ignore header if blank */
message_parse_rfc822space
(
&
hdr
);
if
(
!
hdr
)
return
;
/* Find end of type token */
type
=
hdr
;
for
(;
*
hdr
&&
!
isspace
(
*
hdr
)
&&
*
hdr
!=
'/'
&&
*
hdr
!=
'('
;
hdr
++
)
{
if
(
*
hdr
<
' '
||
strchr
(
TSPECIALS
,
*
hdr
))
return
;
}
typelen
=
hdr
-
type
;
/* Skip whitespace after type */
message_parse_rfc822space
(
&
hdr
);
if
(
!
hdr
)
return
;
/* Ignore header if no '/' character */
if
(
*
hdr
++
!=
'/'
)
return
;
/* Skip whitespace before subtype, ignore header if no subtype */
message_parse_rfc822space
(
&
hdr
);
if
(
!
hdr
)
return
;
/* Find end of subtype token */
subtype
=
hdr
;
for
(;
*
hdr
&&
!
isspace
(
*
hdr
)
&&
*
hdr
!=
';'
&&
*
hdr
!=
'('
;
hdr
++
)
{
if
(
*
hdr
<
' '
||
strchr
(
TSPECIALS
,
*
hdr
))
return
;
}
subtypelen
=
hdr
-
subtype
;
/* Skip whitespace after subtype */
message_parse_rfc822space
(
&
hdr
);
/* Ignore header if not at end of header or parameter delimiter */
if
(
hdr
&&
*
hdr
!=
';'
)
return
;
/* Save content type & subtype */
body
->
type
=
xmalloc
(
typelen
+
1
);
strncpy
(
body
->
type
,
type
,
typelen
);
body
->
type
[
typelen
]
=
'\0'
;
for
(
p
=
body
->
type
;
*
p
;
p
++
)
{
if
(
islower
(
*
p
))
*
p
=
toupper
(
*
p
);
}
body
->
subtype
=
xmalloc
(
subtypelen
+
1
);
strncpy
(
body
->
subtype
,
subtype
,
subtypelen
);
body
->
subtype
[
subtypelen
]
=
'\0'
;
for
(
p
=
body
->
subtype
;
*
p
;
p
++
)
{
if
(
islower
(
*
p
))
*
p
=
toupper
(
*
p
);
}
/* Parse parameter list */
if
(
hdr
)
{
message_parse_params
(
hdr
+
1
,
&
body
->
params
);
}
}
/*
* Parse a parameter list from a header
*/
static
message_parse_params
(
hdr
,
paramp
)
char
*
hdr
;
struct
param
**
paramp
;
{
struct
param
*
param
;
static
struct
param
zeroparam
;
char
*
attribute
;
int
attributelen
;
char
*
value
;
int
valuelen
;
char
*
p
;
for
(;;)
{
/* Skip over leading whitespace */
message_parse_rfc822space
(
&
hdr
);
if
(
!
hdr
)
return
;
/* Find end of attribute */
attribute
=
hdr
;
for
(;
*
hdr
&&
!
isspace
(
*
hdr
)
&&
*
hdr
!=
'='
&&
*
hdr
!=
'('
;
hdr
++
)
{
if
(
*
hdr
<
' '
||
strchr
(
TSPECIALS
,
*
hdr
))
return
;
}
attributelen
=
hdr
-
attribute
;
/* Skip whitespace after attribute */
message_parse_rfc822space
(
&
hdr
);
if
(
!
hdr
)
return
;
/* Ignore param if no '=' character */
if
(
*
hdr
++
!=
'='
)
return
;
/* Skip whitespace before value */
message_parse_rfc822space
(
&
hdr
);
if
(
!
hdr
)
return
;
/* Find end of value */
value
=
hdr
;
if
(
*
hdr
==
'\"'
)
{
hdr
++
;
while
(
*
hdr
&&
*
hdr
!=
'\"'
)
{
if
(
*
hdr
==
'\\'
)
{
hdr
++
;
if
(
!*
hdr
)
return
;
}
if
(
*
hdr
==
'\r'
)
{
return
;
}
hdr
++
;
}
if
(
!*
hdr
++
)
return
;
}
else
{
for
(;
*
hdr
&&
!
isspace
(
*
hdr
)
&&
*
hdr
!=
';'
&&
*
hdr
!=
'('
;
hdr
++
)
{
if
(
*
hdr
<
' '
||
strchr
(
TSPECIALS
,
*
hdr
))
return
;
}
}
valuelen
=
hdr
-
value
;
/* Skip whitespace after value */
message_parse_rfc822space
(
&
hdr
);
/* Ignore parameter if not at end of header or parameter delimiter */
if
(
hdr
&&
*
hdr
!=
';'
)
return
;
/* Save attribute/value pair */
*
paramp
=
param
=
(
struct
param
*
)
xmalloc
(
sizeof
(
struct
param
));
*
param
=
zeroparam
;
param
->
attribute
=
xmalloc
(
attributelen
+
1
);
strncpy
(
param
->
attribute
,
attribute
,
attributelen
);
param
->
attribute
[
attributelen
]
=
'\0'
;
for
(
p
=
param
->
attribute
;
*
p
;
p
++
)
{
if
(
islower
(
*
p
))
*
p
=
toupper
(
*
p
);
}
param
->
value
=
xmalloc
(
valuelen
+
1
);
if
(
*
value
==
'\"'
)
{
p
=
param
->
value
;
value
++
;
while
(
*
value
!=
'\"'
)
{
if
(
*
value
==
'\\'
)
value
++
;
*
p
++
=
*
value
++
;
}
*
p
=
'\0'
;
}
else
{
strncpy
(
param
->
value
,
value
,
valuelen
);
param
->
value
[
valuelen
]
=
'\0'
;
}
/* Get ready to parse the next parameter */
paramp
=
&
param
->
next
;
}
}
/*
* Skip over RFC-822 whitespace and comments
*/
static
message_parse_rfc822space
(
s
)
char
**
s
;
{
char
*
p
=
*
s
;
int
commentlevel
=
0
;
if
(
!
p
)
return
;
while
(
*
p
&&
(
isspace
(
*
p
)
||
*
p
==
'('
))
{
if
(
*
p
==
'\n'
)
{
p
++
;
if
(
*
p
!=
' '
&&
*
p
!=
'\t'
)
{
*
s
=
0
;
return
;
}
}
else
if
(
*
p
==
'('
)
{
p
++
;
commentlevel
++
;
while
(
commentlevel
)
{
switch
(
*
p
)
{
case
'\n'
:
p
++
;
if
(
*
p
==
' '
||
*
p
==
'\t'
)
break
;
/* FALL THROUGH */
case
'\0'
:
*
s
=
0
;
return
;
case
'\\'
:
p
++
;
break
;
case
'('
:
commentlevel
++
;
break
;
case
')'
:
commentlevel
--
;
break
;
}
p
++
;
}
}
else
p
++
;
}
if
(
*
p
==
0
)
{
*
s
=
0
;
}
else
{
*
s
=
p
;
}
}
/*
* Parse the content of a MIME multipart body-part
*/
static
message_parse_multipart
(
infile
,
format
,
body
,
boundaries
)
FILE
*
infile
;
int
format
;
struct
body
*
body
;
struct
boundary
*
boundaries
;
{
struct
body
preamble
,
epilogue
;
static
struct
body
zerobody
;
struct
param
*
boundary
;
char
*
defaultContentType
=
DEFAULT_CONTENT_TYPE
;
int
i
,
depth
;
preamble
=
epilogue
=
zerobody
;
if
(
strcmp
(
body
->
subtype
,
"DIGEST"
)
==
0
)
{
defaultContentType
=
"MESSAGE/RFC822"
;
}
/* Find boundary id */
boundary
=
body
->
params
;
while
(
boundary
&&
strcmp
(
boundary
->
attribute
,
"BOUNDARY"
)
!=
0
)
{
boundary
=
boundary
->
next
;
}
if
(
!
boundary
)
{
/* Invalid MIME--treat as zero-part multipart */
message_parse_content
(
infile
,
format
,
body
,
boundaries
);
return
;
}
/* Expand boundaries array if necessary */
if
(
boundaries
->
count
==
boundaries
->
alloc
)
{
boundaries
->
alloc
+=
20
;
boundaries
->
id
=
(
char
**
)
xrealloc
((
char
*
)
boundaries
->
id
,
boundaries
->
alloc
*
sizeof
(
char
*
));
}
/* Add the new boundary id */
boundaries
->
id
[
boundaries
->
count
++
]
=
boundary
->
value
;
depth
=
boundaries
->
count
;
/* Parse preamble */
message_parse_content
(
infile
,
format
,
&
preamble
,
boundaries
);
/* Parse the component body-parts */
while
(
boundaries
->
count
==
depth
)
{
body
->
subpart
=
(
struct
body
*
)
xrealloc
((
char
*
)
body
->
subpart
,
(
body
->
numparts
+
1
)
*
sizeof
(
struct
body
));
message_parse_body
(
infile
,
format
,
&
body
->
subpart
[
body
->
numparts
++
],
defaultContentType
,
boundaries
);
}
if
(
boundaries
->
count
==
depth
-1
)
{
/* Parse epilogue */
message_parse_content
(
infile
,
format
,
&
epilogue
,
boundaries
);
}
else
if
(
body
->
numparts
)
{
/*
* We hit the boundary of an enclosing multipart while parsing
* a component body-part. Move the enclosing boundary information
* up to our level.
*/
body
->
boundary_size
=
body
->
subpart
[
body
->
numparts
-1
].
boundary_size
;
body
->
boundary_lines
=
body
->
subpart
[
body
->
numparts
-1
].
boundary_lines
;
body
->
subpart
[
body
->
numparts
-1
].
boundary_size
=
0
;
body
->
subpart
[
body
->
numparts
-1
].
boundary_lines
=
0
;
}
else
{
/*
* We hit the boundary of an enclosing multipart while parsing
* the preamble. Move the enclosing boundary information
* up to our level.
*/
body
->
boundary_size
=
preamble
.
boundary_size
;
body
->
boundary_lines
=
preamble
.
boundary_lines
;
preamble
.
boundary_size
=
0
;
preamble
.
boundary_lines
=
0
;
}
/*
* Calculate our size/lines information
*/
body
->
content_size
=
preamble
.
content_size
+
preamble
.
boundary_size
;
body
->
content_lines
=
preamble
.
content_lines
+
preamble
.
boundary_lines
;
for
(
i
=
0
;
i
<
body
->
numparts
;
i
++
)
{
body
->
content_size
+=
body
->
subpart
[
i
].
header_size
+
body
->
subpart
[
i
].
content_size
+
body
->
subpart
[
i
].
boundary_size
;
body
->
content_lines
+=
body
->
subpart
[
i
].
header_lines
+
body
->
subpart
[
i
].
content_lines
+
body
->
subpart
[
i
].
boundary_lines
;
}
body
->
content_size
+=
epilogue
.
content_size
;
body
->
content_lines
+=
epilogue
.
content_lines
;
/*
* Move any enclosing boundary information up to our level.
*/
body
->
boundary_size
+=
epilogue
.
boundary_size
;
body
->
boundary_lines
+=
epilogue
.
boundary_lines
;
}
/*
* Parse the content of a generic body-part
*/
static
message_parse_content
(
infile
,
format
,
body
,
boundaries
)
FILE
*
infile
;
int
format
;
struct
body
*
body
;
struct
boundary
*
boundaries
;
{
char
buf
[
1024
];
int
len
,
line_boundary
=
1
;
while
(
fgets
(
buf
,
sizeof
(
buf
),
infile
))
{
if
(
line_boundary
&&
*
buf
==
'-'
&&
PendingBoundary
(
buf
,
boundaries
->
id
,
&
boundaries
->
count
))
{
body
->
boundary_size
=
strlen
(
buf
)
+
(
format
==
MAILBOX_FORMAT_NETNEWS
);
body
->
boundary_lines
++
;
if
(
body
->
content_lines
)
{
body
->
content_lines
--
;
body
->
boundary_lines
++
;
}
if
(
body
->
content_size
)
{
body
->
content_size
-=
2
;
body
->
boundary_size
+=
2
;
}
return
;
}
len
=
strlen
(
buf
);
body
->
content_size
+=
len
;
if
(
line_boundary
=
(
buf
[
len
-1
]
==
'\n'
))
{
body
->
content_lines
++
;
if
(
format
==
MAILBOX_FORMAT_NETNEWS
)
body
->
content_size
++
;
}
}
}
/*
* Return nonzero if s is an enclosing boundary delimiter.
* If we hit a terminating boundary, the integer pointed to by
* 'BoundaryCt' is modified appropriately.
*/
static
PendingBoundary
(
s
,
Boundaries
,
BoundaryCt
)
char
*
s
;
char
**
Boundaries
;
int
*
BoundaryCt
;
{
int
i
,
len
;
if
(
s
[
0
]
!=
'-'
||
s
[
1
]
!=
'-'
)
return
(
0
);
s
+=
2
;
for
(
i
=
0
;
i
<
*
BoundaryCt
;
++
i
)
{
len
=
strlen
(
Boundaries
[
i
]);
if
(
!
strncmp
(
s
,
Boundaries
[
i
],
len
))
{
if
(
s
[
len
]
==
'-'
&&
s
[
len
+
1
]
==
'-'
)
*
BoundaryCt
=
i
;
return
(
1
);
}
}
return
(
0
);
}
/*
* Write the cache information for the message parsed to 'body'
* to 'outfile'.
*/
static
int
message_write_cache
(
outfile
,
body
)
FILE
*
outfile
;
struct
body
*
body
;
{
struct
ibuf
section
,
envelope
,
bodystructure
,
oldbody
;
struct
ibuf
from
,
to
,
cc
,
bcc
;
struct
body
toplevel
;
toplevel
.
type
=
"MESSAGE"
;
toplevel
.
subtype
=
"RFC822"
;
toplevel
.
subpart
=
body
;
message_ibuf_init
(
&
envelope
);
message_write_envelope
(
&
envelope
,
body
);
message_ibuf_init
(
&
bodystructure
);
message_write_body
(
&
bodystructure
,
body
,
1
);
message_ibuf_init
(
&
oldbody
);
message_write_body
(
&
oldbody
,
body
,
0
);
message_ibuf_init
(
&
section
);
message_write_section
(
&
section
,
&
toplevel
);
message_ibuf_init
(
&
from
);
message_write_searchaddr
(
&
from
,
body
->
from
);
message_ibuf_init
(
&
to
);
message_write_searchaddr
(
&
to
,
body
->
to
);
message_ibuf_init
(
&
cc
);
message_write_searchaddr
(
&
cc
,
body
->
cc
);
message_ibuf_init
(
&
bcc
);
message_write_searchaddr
(
&
bcc
,
body
->
bcc
);
message_ibuf_write
(
outfile
,
&
envelope
);
message_ibuf_write
(
outfile
,
&
bodystructure
);
message_ibuf_write
(
outfile
,
&
oldbody
);
message_ibuf_write
(
outfile
,
&
section
);
message_ibuf_write
(
outfile
,
&
from
);
message_ibuf_write
(
outfile
,
&
to
);
message_ibuf_write
(
outfile
,
&
cc
);
message_ibuf_write
(
outfile
,
&
bcc
);
message_ibuf_free
(
&
envelope
);
message_ibuf_free
(
&
bodystructure
);
message_ibuf_free
(
&
oldbody
);
message_ibuf_free
(
&
section
);
message_ibuf_free
(
&
from
);
message_ibuf_free
(
&
to
);
message_ibuf_free
(
&
cc
);
message_ibuf_free
(
&
bcc
);
}
/* Append character 'c' to 'ibuf' */
#define PUTIBUF(ibuf,c) (((ibuf)->left || message_ibuf_ensure((ibuf),1)),(*((ibuf)->end)++ = (c)))
/*
* Write the IMAP envelope for 'body' to 'ibuf'
*/
static
message_write_envelope
(
ibuf
,
body
)
struct
ibuf
*
ibuf
;
struct
body
*
body
;
{
PUTIBUF
(
ibuf
,
'('
);
message_write_nstring
(
ibuf
,
body
->
date
);
PUTIBUF
(
ibuf
,
' '
);
message_write_nstring
(
ibuf
,
body
->
subject
);
PUTIBUF
(
ibuf
,
' '
);
message_write_address
(
ibuf
,
body
->
from
);
PUTIBUF
(
ibuf
,
' '
);
message_write_address
(
ibuf
,
body
->
sender
?
body
->
sender
:
body
->
from
);
PUTIBUF
(
ibuf
,
' '
);
message_write_address
(
ibuf
,
body
->
reply_to
?
body
->
reply_to
:
body
->
from
);
PUTIBUF
(
ibuf
,
' '
);
message_write_address
(
ibuf
,
body
->
to
);
PUTIBUF
(
ibuf
,
' '
);
message_write_address
(
ibuf
,
body
->
cc
);
PUTIBUF
(
ibuf
,
' '
);
message_write_address
(
ibuf
,
body
->
bcc
);
PUTIBUF
(
ibuf
,
' '
);
message_write_nstring
(
ibuf
,
body
->
in_reply_to
);
PUTIBUF
(
ibuf
,
' '
);
message_write_nstring
(
ibuf
,
body
->
message_id
);
PUTIBUF
(
ibuf
,
')'
);
}
/*
* Write the BODY (if 'newformat' is zero) or BODYSTRUCTURE
* (if 'newformat' is nonzero) for 'body' to 'ibuf'.
*/
static
message_write_body
(
ibuf
,
body
,
newformat
)
struct
ibuf
*
ibuf
;
struct
body
*
body
;
int
newformat
;
{
struct
param
*
param
;
if
(
strcmp
(
body
->
type
,
"MULTIPART"
)
==
0
)
{
int
i
;
/* 0-part multiparts are illegal--convert to 0-len text parts */
if
(
body
->
numparts
==
0
)
{
static
struct
body
zerotextbody
;
if
(
!
zerotextbody
.
type
)
{
message_parse_type
(
DEFAULT_CONTENT_TYPE
,
&
zerotextbody
);
}
message_write_body
(
ibuf
,
&
zerotextbody
,
newformat
);
return
;
}
/* Multipart types get a body_multipart */
PUTIBUF
(
ibuf
,
'('
);
for
(
i
=
0
;
i
<
body
->
numparts
;
i
++
)
{
message_write_body
(
ibuf
,
&
body
->
subpart
[
i
],
newformat
);
}
PUTIBUF
(
ibuf
,
' '
);
message_write_nstring
(
ibuf
,
body
->
subtype
);
if
(
newformat
)
{
PUTIBUF
(
ibuf
,
' '
);
if
(
param
=
body
->
params
)
{
PUTIBUF
(
ibuf
,
'('
);
while
(
param
)
{
message_write_nstring
(
ibuf
,
param
->
attribute
);
PUTIBUF
(
ibuf
,
' '
);
message_write_nstring
(
ibuf
,
param
->
value
);
if
(
param
=
param
->
next
)
{
PUTIBUF
(
ibuf
,
' '
);
}
}
PUTIBUF
(
ibuf
,
')'
);
}
else
message_write_nstring
(
ibuf
,
(
char
*
)
0
);
}
PUTIBUF
(
ibuf
,
')'
);
return
;
}
PUTIBUF
(
ibuf
,
'('
);
message_write_nstring
(
ibuf
,
body
->
type
);
PUTIBUF
(
ibuf
,
' '
);
message_write_nstring
(
ibuf
,
body
->
subtype
);
PUTIBUF
(
ibuf
,
' '
);
if
(
param
=
body
->
params
)
{
PUTIBUF
(
ibuf
,
'('
);
while
(
param
)
{
message_write_nstring
(
ibuf
,
param
->
attribute
);
PUTIBUF
(
ibuf
,
' '
);
message_write_nstring
(
ibuf
,
param
->
value
);
if
(
param
=
param
->
next
)
{
PUTIBUF
(
ibuf
,
' '
);
}
}
PUTIBUF
(
ibuf
,
')'
);
}
else
message_write_nstring
(
ibuf
,
(
char
*
)
0
);
PUTIBUF
(
ibuf
,
' '
);
message_write_nstring
(
ibuf
,
body
->
id
);
PUTIBUF
(
ibuf
,
' '
);
message_write_nstring
(
ibuf
,
body
->
description
);
PUTIBUF
(
ibuf
,
' '
);
message_write_nstring
(
ibuf
,
body
->
encoding
?
body
->
encoding
:
"7BIT"
);
PUTIBUF
(
ibuf
,
' '
);
message_write_number
(
ibuf
,
body
->
content_size
);
if
(
strcmp
(
body
->
type
,
"TEXT"
)
==
0
)
{
/* Text types get a line count */
PUTIBUF
(
ibuf
,
' '
);
message_write_number
(
ibuf
,
body
->
content_lines
);
}
else
if
(
strcmp
(
body
->
type
,
"MESSAGE"
)
==
0
&&
strcmp
(
body
->
subtype
,
"RFC822"
)
==
0
)
{
/* Message/rfc822 gets a body_msg */
PUTIBUF
(
ibuf
,
' '
);
message_write_envelope
(
ibuf
,
body
->
subpart
);
PUTIBUF
(
ibuf
,
' '
);
message_write_body
(
ibuf
,
body
->
subpart
,
newformat
);
PUTIBUF
(
ibuf
,
' '
);
message_write_number
(
ibuf
,
body
->
content_lines
);
}
if
(
newformat
)
{
/* Add additional fields for BODYSTRUCTURE */
PUTIBUF
(
ibuf
,
' '
);
message_write_nstring
(
ibuf
,
body
->
md5
);
}
PUTIBUF
(
ibuf
,
')'
);
}
/*
* Write the address list 'addrlist' to 'ibuf'
*/
static
message_write_address
(
ibuf
,
addrlist
)
struct
ibuf
*
ibuf
;
PARSED_ADDRESS
*
addrlist
;
{
int
len
=
0
;
/* If no addresses, write out NIL */
if
(
!
addrlist
)
{
message_write_nstring
(
ibuf
,
(
char
*
)
0
);
return
;
}
FOR_ALL_ADDRESSES
(
thisaddr
,
addrlist
,
len
++
;);
if
(
!
len
)
{
message_write_nstring
(
ibuf
,
(
char
*
)
0
);
return
;
}
PUTIBUF
(
ibuf
,
'('
);
FOR_ALL_ADDRESSES
(
thisaddr
,
addrlist
,
message_write_singleaddress
(
ibuf
,
thisaddr
););
PUTIBUF
(
ibuf
,
')'
);
}
/*
* Write the single address 'addr' to 'ibuf'.
*/
static
message_write_singleaddress
(
ibuf
,
addr
)
struct
ibuf
*
ibuf
;
PARSED_ADDRESS
*
addr
;
{
int
nhosts
=
0
,
adllen
=
0
;
char
*
name
=
0
,
*
adl
=
0
;
static
char
myhostname
[
128
];
/* Recursively handle RFC-822 group addresses */
if
(
addr
->
Kind
==
GROUP_ADDRESS
)
{
PUTIBUF
(
ibuf
,
'('
);
message_write_nstring
(
ibuf
,
(
char
*
)
0
);
PUTIBUF
(
ibuf
,
' '
);
message_write_nstring
(
ibuf
,
(
char
*
)
0
);
PUTIBUF
(
ibuf
,
' '
);
message_write_nstring
(
ibuf
,
addr
->
LocalPart
);
PUTIBUF
(
ibuf
,
' '
);
message_write_nstring
(
ibuf
,
(
char
*
)
0
);
PUTIBUF
(
ibuf
,
')'
);
FOR_ALL_GROUP_MEMBERS
(
thisaddr
,
addr
,
message_write_singleaddress
(
ibuf
,
thisaddr
););
PUTIBUF
(
ibuf
,
'('
);
message_write_nstring
(
ibuf
,
(
char
*
)
0
);
PUTIBUF
(
ibuf
,
' '
);
message_write_nstring
(
ibuf
,
(
char
*
)
0
);
PUTIBUF
(
ibuf
,
' '
);
message_write_nstring
(
ibuf
,
(
char
*
)
0
);
PUTIBUF
(
ibuf
,
' '
);
message_write_nstring
(
ibuf
,
(
char
*
)
0
);
PUTIBUF
(
ibuf
,
')'
);
return
;
}
/* If no route phrase, use first RFC-822 comment (without parens) */
name
=
addr
->
RoutePhrase
;
if
(
!
name
&&
addr
->
Comments
)
{
name
=
addr
->
Comments
->
Text
+
1
;
name
[
strlen
(
name
)
-1
]
=
'\0'
;
}
/* Fid out my hostname if necessary */
if
(
!
addr
->
Hosts
->
Next
->
Name
&&
!
myhostname
[
0
])
{
gethostname
(
myhostname
,
sizeof
(
myhostname
)
-1
);
}
/* Count number of hosts and build any necessary at-domain-list */
FOR_ALL_REVERSE_HOSTS
(
h
,
addr
,
{
nhosts
++
;
adllen
+=
2
+
strlen
(
h
->
Name
);});
if
(
nhosts
>
1
)
{
adl
=
xmalloc
(
adllen
);
*
adl
=
'\0'
;
FOR_ALL_REVERSE_HOSTS
(
h
,
addr
,
{
if
(
--
nhosts
)
{
if
(
*
adl
)
strcat
(
adl
,
","
);
strcat
(
adl
,
"@"
);
strcat
(
adl
,
h
->
Name
);
}});
nhosts
=
1
;
}
PUTIBUF
(
ibuf
,
'('
);
message_write_nstring
(
ibuf
,
name
);
PUTIBUF
(
ibuf
,
' '
);
message_write_nstring
(
ibuf
,
adl
);
PUTIBUF
(
ibuf
,
' '
);
message_write_nstring
(
ibuf
,
addr
->
LocalPart
);
PUTIBUF
(
ibuf
,
' '
);
message_write_nstring
(
ibuf
,
nhosts
?
addr
->
Hosts
->
Next
->
Name
:
myhostname
);
PUTIBUF
(
ibuf
,
')'
);
/* If we used a comment for a name, put back the close parenthesis */
if
(
!
addr
->
RoutePhrase
&&
addr
->
Comments
)
{
name
[
strlen
(
name
)]
=
')'
;
}
if
(
adl
)
free
(
adl
);
}
/*
* Write the nil-or-string 's' to 'ibuf'
*/
static
message_write_nstring
(
ibuf
,
s
)
struct
ibuf
*
ibuf
;
char
*
s
;
{
char
*
p
;
/* Write null pointer as NIL */
if
(
!
s
)
{
message_ibuf_ensure
(
ibuf
,
3
);
*
(
ibuf
->
end
)
++
=
'N'
;
*
(
ibuf
->
end
)
++
=
'I'
;
*
(
ibuf
->
end
)
++
=
'L'
;
return
;
}
/* Look for any non-QCHAR characters */
for
(
p
=
s
;
*
p
;
p
++
)
{
if
(
*
p
&
0x80
||
*
p
==
'\r'
||
*
p
==
'\n'
||
*
p
==
'\"'
||
*
p
==
'%'
||
*
p
==
'\\'
)
break
;
}
if
(
*
p
)
{
/* Write out as literal */
char
buf
[
100
];
sprintf
(
buf
,
"{%d}
\r\n
"
,
strlen
(
s
));
message_ibuf_ensure
(
ibuf
,
strlen
(
s
)
+
strlen
(
buf
));
for
(
p
=
buf
;
*
p
;
p
++
)
*
(
ibuf
->
end
)
++
=
*
p
;
for
(
p
=
s
;
*
p
;
p
++
)
*
(
ibuf
->
end
)
++
=
*
p
;
}
else
{
/* Write out as quoted string */
message_ibuf_ensure
(
ibuf
,
strlen
(
s
)
+
2
);
*
(
ibuf
->
end
)
++
=
'\"'
;
for
(
p
=
s
;
*
p
;
p
++
)
*
(
ibuf
->
end
)
++
=
*
p
;
*
(
ibuf
->
end
)
++
=
'\"'
;
}
}
/*
* Write the text 's' to 'ibuf'
*/
static
message_write_text
(
ibuf
,
s
)
struct
ibuf
*
ibuf
;
char
*
s
;
{
char
*
p
;
message_ibuf_ensure
(
ibuf
,
strlen
(
s
));
for
(
p
=
s
;
*
p
;
p
++
)
*
(
ibuf
->
end
)
++
=
*
p
;
}
/*
* Write out the IMAP number 'n' to 'ibuf'
*/
static
message_write_number
(
ibuf
,
n
)
struct
ibuf
*
ibuf
;
int
n
;
{
char
buf
[
100
],
*
p
;
sprintf
(
buf
,
"%d"
,
n
);
message_ibuf_ensure
(
ibuf
,
strlen
(
buf
));
for
(
p
=
buf
;
*
p
;
p
++
)
*
(
ibuf
->
end
)
++
=
*
p
;
}
/*
* Write out the FETCH BODY[section] location/size information to 'ibuf'.
*/
static
message_write_section
(
ibuf
,
body
)
struct
ibuf
*
ibuf
;
struct
body
*
body
;
{
int
part
;
if
(
strcmp
(
body
->
type
,
"MESSAGE"
)
==
0
&&
strcmp
(
body
->
subtype
,
"RFC822"
)
==
0
)
{
if
(
body
->
subpart
->
numparts
)
{
/*
* Part 0 of a message/rfc822 is the message header.
* Nested parts of a message/rfc822 containing a multipart
* are the sub-parts of the multipart.
*/
message_write_bit32
(
ibuf
,
body
->
subpart
->
numparts
+
1
);
message_write_bit32
(
ibuf
,
body
->
subpart
->
header_offset
);
message_write_bit32
(
ibuf
,
body
->
subpart
->
header_size
);
for
(
part
=
0
;
part
<
body
->
subpart
->
numparts
;
part
++
)
{
message_write_bit32
(
ibuf
,
body
->
subpart
->
subpart
[
part
].
content_offset
);
if
(
strcmp
(
body
->
subpart
->
subpart
[
part
].
type
,
"MULTIPART"
)
==
0
)
{
if
(
body
->
subpart
->
subpart
[
part
].
numparts
)
{
/* Cannot fetch a multipart itself */
message_write_bit32
(
ibuf
,
-1
);
}
else
{
/* Treat 0-part multipart as 0-length text */
message_write_bit32
(
ibuf
,
0
);
}
}
else
{
message_write_bit32
(
ibuf
,
body
->
subpart
->
subpart
[
part
].
content_size
);
}
}
for
(
part
=
0
;
part
<
body
->
subpart
->
numparts
;
part
++
)
{
message_write_section
(
ibuf
,
&
body
->
subpart
->
subpart
[
part
]);
}
}
else
{
/*
* Part 0 of a message/rfc822 is the message header.
* Part 1 of a message/rfc822 containing a non-multipart
* is the message body.
*/
message_write_bit32
(
ibuf
,
2
);
message_write_bit32
(
ibuf
,
body
->
subpart
->
header_offset
);
message_write_bit32
(
ibuf
,
body
->
subpart
->
header_size
);
message_write_bit32
(
ibuf
,
body
->
subpart
->
content_offset
);
if
(
strcmp
(
body
->
subpart
->
type
,
"MULTIPART"
)
==
0
)
{
/* Treat 0-part multipart as 0-length text */
message_write_bit32
(
ibuf
,
0
);
}
else
{
message_write_bit32
(
ibuf
,
body
->
subpart
->
content_size
);
}
message_write_section
(
ibuf
,
body
->
subpart
);
}
}
else
if
(
body
->
numparts
)
{
/*
* Cannot fetch part 0 of a multipart.
* Nested parts of a multipart are the sub-parts.
*/
message_write_bit32
(
ibuf
,
body
->
numparts
+
1
);
message_write_bit32
(
ibuf
,
0
);
message_write_bit32
(
ibuf
,
-1
);
for
(
part
=
0
;
part
<
body
->
numparts
;
part
++
)
{
message_write_bit32
(
ibuf
,
body
->
subpart
[
part
].
content_offset
);
if
(
body
->
subpart
[
part
].
numparts
)
{
/* Cannot fetch a multipart itself */
message_write_bit32
(
ibuf
,
-1
);
}
else
if
(
strcmp
(
body
->
subpart
[
part
].
type
,
"MULTIPART"
)
==
0
)
{
/* Treat 0-part multipart as 0-length text */
message_write_bit32
(
ibuf
,
0
);
}
else
{
message_write_bit32
(
ibuf
,
body
->
subpart
[
part
].
content_size
);
}
}
for
(
part
=
0
;
part
<
body
->
numparts
;
part
++
)
{
message_write_section
(
ibuf
,
&
body
->
subpart
[
part
]);
}
}
else
{
/*
* Leaf section--no part 0 or nested parts
*/
message_write_bit32
(
ibuf
,
0
);
}
}
/*
* Write the 32-bit integer quantitiy 'val' to 'ibuf'
*/
static
message_write_bit32
(
ibuf
,
val
)
struct
ibuf
*
ibuf
;
int
val
;
{
bit32
buf
;
int
i
;
char
*
p
=
(
char
*
)
&
buf
;
message_ibuf_ensure
(
ibuf
,
sizeof
(
bit32
));
buf
=
htonl
(
val
);
for
(
i
=
0
;
i
<
sizeof
(
bit32
);
i
++
)
{
*
(
ibuf
->
end
)
++
=
*
p
++
;
}
}
/*
* Unparse the address list 'addrlist' to 'ibuf'
*/
static
message_write_searchaddr
(
ibuf
,
addrlist
)
struct
ibuf
*
ibuf
;
PARSED_ADDRESS
*
addrlist
;
{
if
(
!
addrlist
)
return
;
FOR_ALL_ADDRESSES
(
thisaddr
,
addrlist
,
message_write_singlesearchaddr
(
ibuf
,
thisaddr
,
thisaddr
->
Next
->
Kind
==
DUMMY_ADDRESS
););
}
/*
* Unparse the single addres 'addr' to 'ibuf'.
*/
static
message_write_singlesearchaddr
(
ibuf
,
addr
,
last
)
struct
ibuf
*
ibuf
;
PARSED_ADDRESS
*
addr
;
int
last
;
{
int
nhosts
=
0
,
adllen
=
0
;
char
*
name
=
0
,
*
adl
=
0
;
static
char
myhostname
[
128
];
/* Recursively handle RFC-822 group addresses */
if
(
addr
->
Kind
==
GROUP_ADDRESS
)
{
message_write_text
(
ibuf
,
addr
->
LocalPart
);
PUTIBUF
(
ibuf
,
':'
);
FOR_ALL_GROUP_MEMBERS
(
thisaddr
,
addr
,
message_write_singlesearchaddr
(
ibuf
,
thisaddr
,
thisaddr
->
Next
->
Kind
==
DUMMY_ADDRESS
););
PUTIBUF
(
ibuf
,
';'
);
if
(
!
last
)
PUTIBUF
(
ibuf
,
','
);
return
;
}
/* If no route phrase, use first RFC-822 comment (without parens) */
name
=
addr
->
RoutePhrase
;
if
(
!
name
&&
addr
->
Comments
)
{
name
=
addr
->
Comments
->
Text
+
1
;
name
[
strlen
(
name
)
-1
]
=
'\0'
;
}
/* Fid out my hostname if necessary */
if
(
!
addr
->
Hosts
->
Next
->
Name
&&
!
myhostname
[
0
])
{
gethostname
(
myhostname
,
sizeof
(
myhostname
)
-1
);
}
/* Count number of hosts and build any necessary at-domain-list */
FOR_ALL_REVERSE_HOSTS
(
h
,
addr
,
{
nhosts
++
;
adllen
+=
2
+
strlen
(
h
->
Name
);});
if
(
nhosts
>
1
)
{
adl
=
xmalloc
(
adllen
);
*
adl
=
'\0'
;
FOR_ALL_REVERSE_HOSTS
(
h
,
addr
,
{
if
(
--
nhosts
)
{
if
(
*
adl
)
strcat
(
adl
,
","
);
strcat
(
adl
,
"@"
);
strcat
(
adl
,
h
->
Name
);
}});
nhosts
=
1
;
}
if
(
name
)
{
message_write_text
(
ibuf
,
name
);
PUTIBUF
(
ibuf
,
' '
);
}
PUTIBUF
(
ibuf
,
'<'
);
if
(
adl
)
{
message_write_text
(
ibuf
,
adl
);
PUTIBUF
(
ibuf
,
':'
);
}
message_write_text
(
ibuf
,
addr
->
LocalPart
);
PUTIBUF
(
ibuf
,
'@'
);
message_write_text
(
ibuf
,
nhosts
?
addr
->
Hosts
->
Next
->
Name
:
myhostname
);
PUTIBUF
(
ibuf
,
'>'
);
if
(
!
last
)
PUTIBUF
(
ibuf
,
','
);
/* If we used a comment for a name, put back the close parenthesis */
if
(
!
addr
->
RoutePhrase
&&
addr
->
Comments
)
{
name
[
strlen
(
name
)]
=
')'
;
}
if
(
adl
)
free
(
adl
);
}
/*
* Initialize 'ibuf'
*/
#define IBUFGROWSIZE 1000
static
message_ibuf_init
(
ibuf
)
struct
ibuf
*
ibuf
;
{
char
*
s
=
xmalloc
(
IBUFGROWSIZE
);
ibuf
->
start
=
ibuf
->
end
=
s
+
sizeof
(
bit32
);
ibuf
->
left
=
IBUFGROWSIZE
-
sizeof
(
bit32
);
}
/*
* Ensure 'ibuf' has enough free space to append 'len' bytes.
*/
static
message_ibuf_ensure
(
ibuf
,
len
)
struct
ibuf
*
ibuf
;
int
len
;
{
char
*
s
;
if
(
len
>=
ibuf
->
left
)
return
;
if
(
len
<
IBUFGROWSIZE
)
len
=
IBUFGROWSIZE
;
s
=
ibuf
->
start
-
sizeof
(
bit32
);
s
=
xrealloc
(
s
,
len
+
(
ibuf
->
end
-
ibuf
->
start
)
+
ibuf
->
left
+
sizeof
(
bit32
));
ibuf
->
left
+=
len
;
s
+=
sizeof
(
bit32
);
ibuf
->
end
=
(
ibuf
->
end
-
ibuf
->
start
)
+
s
;
ibuf
->
start
=
s
;
}
/*
* Write 'ibuf' to the cache file 'outfile'
*/
static
message_ibuf_write
(
outfile
,
ibuf
)
FILE
*
outfile
;
struct
ibuf
*
ibuf
;
{
char
*
s
;
int
len
;
len
=
(
ibuf
->
end
-
ibuf
->
start
);
s
=
ibuf
->
start
-
sizeof
(
bit32
);
*
((
bit32
*
)
s
)
=
htonl
(
len
);
fwrite
(
s
,
1
,
len
+
sizeof
(
bit32
),
outfile
);
if
(
len
&
3
)
{
fwrite
(
"
\0\0\0
"
,
1
,
4
-
(
len
&
3
),
outfile
);
}
}
/*
* Free the space used by 'ibuf'
*/
static
message_ibuf_free
(
ibuf
)
struct
ibuf
*
ibuf
;
{
free
(
ibuf
->
start
-
sizeof
(
bit32
));
}
/*
* Free the parsed body-part 'body'
*/
static
message_free_body
(
body
)
struct
body
*
body
;
{
struct
param
*
param
,
*
nextparam
;
int
part
;
if
(
body
->
type
)
{
free
(
body
->
type
);
free
(
body
->
subtype
);
for
(
param
=
body
->
params
;
param
;
param
=
nextparam
)
{
nextparam
=
param
->
next
;
free
(
param
->
attribute
);
free
(
param
->
value
);
free
(
param
);
}
}
if
(
body
->
id
)
free
(
body
->
id
);
if
(
body
->
description
)
free
(
body
->
description
);
if
(
body
->
encoding
)
free
(
body
->
encoding
);
if
(
body
->
md5
)
free
(
body
->
md5
);
if
(
body
->
date
)
free
(
body
->
date
);
if
(
body
->
subject
)
free
(
body
->
subject
);
if
(
body
->
from
)
FreeAddressList
(
body
->
from
);
if
(
body
->
sender
)
FreeAddressList
(
body
->
sender
);
if
(
body
->
reply_to
)
FreeAddressList
(
body
->
reply_to
);
if
(
body
->
to
)
FreeAddressList
(
body
->
to
);
if
(
body
->
cc
)
FreeAddressList
(
body
->
cc
);
if
(
body
->
bcc
)
FreeAddressList
(
body
->
bcc
);
if
(
body
->
in_reply_to
)
free
(
body
->
in_reply_to
);
if
(
body
->
message_id
)
free
(
body
->
message_id
);
if
(
body
->
subpart
)
{
if
(
body
->
numparts
)
{
for
(
part
=
0
;
part
<
body
->
numparts
;
part
++
)
{
message_free_body
(
&
body
->
subpart
[
part
]);
}
}
else
{
message_free_body
(
body
->
subpart
);
}
free
(
body
->
subpart
);
}
}
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Mon, Apr 6, 2:18 AM (1 w, 3 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
18831955
Default Alt Text
message.c (39 KB)
Attached To
Mode
R111 cyrus-imapd
Attached
Detach File
Event Timeline