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
9c5a3d47
...
9c5a3d47e072d74af7e4b2a82c09277245638e24
authored
2001-04-07 02:46:47 +0000
by
Alain Magloire
Browse Files
Options
Browse Files
Tag
Download
Email Patches
Plain Diff
New parser from Sam.
1 parent
c6d08dd1
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
879 additions
and
646 deletions
mailbox/include/address0.h
mailbox/parse822.c
mailbox/include/address0.h
View file @
9c5a3d4
...
...
@@ -38,7 +38,7 @@ extern "C" {
/*
* The data-structure representing an RFC822 MAILBOX. It may be
* one MAILBOX
in a list of them, as found in an ADDRESS list
or
* one MAILBOX
or a list of them, as found in an ADDRESS
or
* a MAILBOX list (as found in a GROUP).
*
* Capitalized names are from RFC 822, section 6.1 (Address Syntax).
...
...
@@ -62,7 +62,8 @@ struct _address
char
*
route
;
/* the optional ROUTE in the ROUTE-ADDR form of MAILBOX */
// size_t num; -- didn't appear to be used anywhere...
/* size_t num; this didn't appear to be used anywhere... so I commented
it out, is that ok? -sam */
struct
_address
*
next
;
};
...
...
mailbox/parse822.c
View file @
9c5a3d4
...
...
@@ -15,6 +15,41 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* vi:sw=4:ts=8 */
/*
Things to (maybe) do:
- groups used to return the number of addresses, now it returns
success... but doesn't create an _address for 'foo:;'. Should
it create one with just a personal?
x - C comments only.
x - no C++ reserved words.
x - fix is_digit() to be like the other is functions
- what should return codes be, possible errors are:
. no mem (ENOMEM)
. function wasn't called correctly, usually a missing argument (EINVAL)
. invalid syntax found during parsing (ENOENT)
All functions should return ==0 on success, and errno on failure.
x - const-correct the APIs
x - "new = (char*) realloc()", cast not needed
x - mailbox_t* nuked in favor of address_t
x - fix handful of memory leaks detected by Alain
- test for memory leaks, so I don't have to rely on Alains sharp eyes
- fix the realloc, try a struct _string { char* b, size_t sz };
x - where does parse822.h go?
- parse field names and bodies
- parse dates (pull from Mail++)
- parse Received: field
x - check RFC again, can groups be nested? No!
- should we do best effort parsing, so parsing "sam@locahost, foo@"
gets one address, or just say it is or it isn't in RFC format?
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
...
...
@@ -27,904 +62,1101 @@
#include "address0.h"
int
GetDigits
(
char
**
p
,
char
*
e
,
int
min
,
int
max
,
int
*
digits
);
int
GetSpecial
(
char
**
p
,
char
*
e
,
char
c
);
int
GetComment
(
char
**
p
,
char
*
e
,
char
**
comment
);
int
GetAtom
(
char
**
p
,
char
*
e
,
char
**
atom
);
int
GetQuotedPair
(
char
**
p
,
char
*
e
,
char
**
qpair
);
int
GetQuotedString
(
char
**
p
,
char
*
e
,
char
**
qstr
);
int
GetWord
(
char
**
p
,
char
*
e
,
char
**
word
);
int
GetPhrase
(
char
**
p
,
char
*
e
,
char
**
phrase
);
int
GetAddressList
(
address_t
*
a
,
char
*
s
);
int
GetMailBox
(
char
**
p
,
char
*
e
,
address_t
*
a
);
int
GetGroup
(
char
**
p
,
char
*
e
,
address_t
*
a
);
int
GetAddress
(
char
**
p
,
char
*
e
,
address_t
*
a
);
int
GetRouteAddr
(
char
**
p
,
char
*
e
,
address_t
*
a
);
int
GetRoute
(
char
**
p
,
char
*
e
,
char
**
route
);
int
GetAddrSpec
(
char
**
p
,
char
*
e
,
address_t
*
a
);
int
GetLocalPart
(
char
**
p
,
char
*
e
,
char
**
local_part
);
int
GetDomain
(
char
**
p
,
char
*
e
,
char
**
domain
);
int
GetSubDomain
(
char
**
p
,
char
*
e
,
char
**
sub_domain
);
int
GetDomainRef
(
char
**
p
,
char
*
e
,
char
**
domain_ref
);
int
GetDomainLiteral
(
char
**
p
,
char
*
e
,
char
**
domain_literal
);
// Some convenience functions for dealing with dynamically re-sized
// strings.
int
StrAppendN
(
char
**
to
,
char
*
from
,
size_t
n
)
{
size_t
l
=
0
;
/* if not to, then silently discard data */
if
(
!
to
)
{
return
1
;
}
#include <mailutils/parse822.h>
#ifdef EOK
# undef EOK
#endif
if
(
*
to
)
{
char
*
new
;
#define EOK 0
#define EPARSE ENOENT
l
=
strlen
(
*
to
);
/*
* Some convenience functions for dealing with dynamically re-sized
* strings.
*/
new
=
(
char
*
)
realloc
(
*
to
,
l
+
n
+
1
);
static
int
str_append_n
(
char
**
to
,
const
char
*
from
,
size_t
n
)
{
size_t
l
=
0
;
if
(
!
new
)
{
return
0
;
}
*
to
=
new
;
}
else
{
*
to
=
(
char
*
)
malloc
(
n
+
1
);
/* if not to, then silently discard data */
if
(
!
to
)
{
return
EOK
;
}
if
(
*
to
)
{
char
*
bigger
;
l
=
strlen
(
*
to
);
bigger
=
realloc
(
*
to
,
l
+
n
+
1
);
if
(
!
bigger
)
{
return
ENOMEM
;
}
*
to
=
bigger
;
}
else
{
*
to
=
malloc
(
n
+
1
);
}
strncpy
(
&
to
[
0
][
l
],
from
,
n
);
strncpy
(
&
to
[
0
][
l
],
from
,
n
);
/* strncpy is lame, nul terminate our buffer */
/* strncpy is lame, nul terminate our buffer */
to
[
0
][
l
+
n
]
=
0
;
to
[
0
][
l
+
n
]
=
0
;
return
1
;
return
EOK
;
}
int
StrAppend
(
char
**
to
,
char
*
from
)
static
int
str_append
(
char
**
to
,
const
char
*
from
)
{
return
StrAppendN
(
to
,
from
,
strlen
(
from
));
return
str_append_n
(
to
,
from
,
strlen
(
from
));
}
int
StrAppendChar
(
char
**
to
,
char
c
)
static
int
str_append_char
(
char
**
to
,
char
c
)
{
return
StrAppendN
(
to
,
&
c
,
1
);
return
str_append_n
(
to
,
&
c
,
1
);
}
int
StrAppendRange
(
char
**
to
,
char
*
b
,
char
*
e
)
static
int
str_append_range
(
char
**
to
,
const
char
*
b
,
const
char
*
e
)
{
return
StrAppendN
(
to
,
b
,
e
-
b
);
return
str_append_n
(
to
,
b
,
e
-
b
);
}
void
StrFree
(
char
**
s
)
static
void
str_free
(
char
**
s
)
{
if
(
s
&&
*
s
)
{
free
(
*
s
);
*
s
=
0
;
}
if
(
s
&&
*
s
)
{
free
(
*
s
);
*
s
=
0
;
}
}
//
// MRfc822Tokenizer
//
//
// Character Classification - could be rewritten in a C library
// independent way, my system's C library matches the RFC
// definitions, but I don't know if that's guaranteed.
//
int
IsCHAR
(
char
c
)
/*
* Character Classification - could be rewritten in a C library
* independent way, my system's C library matches the RFC
* definitions. I don't know if that's guaranteed.
*
* Note that all return values are:
* 1 -> TRUE
* 0 -> FALSE
* This may be appear different than the 0 == success return
* values of the other functions, but I was getting lost in
* boolean arithmetic.
*/
int
parse822_is_char
(
char
c
)
{
return
isascii
(
c
);
return
isascii
(
c
);
}
int
IsDIGIT
(
char
**
p
,
char
*
e
)
int
parse822_is_digit
(
char
c
)
{
// DIGIT = <any ASCII decimal digit>
/* digit = <any ASCII decimal digit> */
if
(
*
p
==
e
)
{
return
0
;
}
return
isdigit
(
**
p
);
return
isdigit
(
c
);
}
int
IsCTL
(
char
c
)
int
parse822_is_ctl
(
char
c
)
{
return
iscntrl
(
c
)
||
c
==
127
/* DEL */
;
return
iscntrl
(
c
)
||
c
==
127
/* DEL */
;
}
int
IsSPACE
(
char
c
)
int
parse822_is_space
(
char
c
)
{
return
c
==
' '
;
return
c
==
' '
;
}
int
IsHTAB
(
char
c
)
int
parse822_is_htab
(
char
c
)
{
return
c
==
'\t'
;
return
c
==
'\t'
;
}
int
IsLWSPC
har
(
char
c
)
int
parse822_is_lwsp_c
har
(
char
c
)
{
return
IsSPACE
(
c
)
||
IsHTAB
(
c
);
return
parse822_is_space
(
c
)
||
parse822_is_htab
(
c
);
}
int
IsS
pecial
(
char
c
)
int
parse822_is_s
pecial
(
char
c
)
{
return
strchr
(
"()<>@,;:
\\\"
.[]"
,
c
)
?
1
:
0
;
return
strchr
(
"()<>@,;:
\\\"
.[]"
,
c
)
?
1
:
0
;
}
int
IsAtomC
har
(
char
c
)
int
parse822_is_atom_c
har
(
char
c
)
{
return
IsCHAR
(
c
)
&&
!
IsSpecial
(
c
)
&&
!
IsSPACE
(
c
)
&&
!
IsCTL
(
c
);
return
parse822_is_char
(
c
)
&&
!
parse822_is_special
(
c
)
&&
!
parse822_is_space
(
c
)
&&
!
parse822_is_ctl
(
c
)
;
}
int
IsQT
ext
(
char
c
)
int
parse822_is_q_t
ext
(
char
c
)
{
return
IsCHAR
(
c
)
&&
c
!=
'"'
&&
c
!=
'\\'
&&
c
!=
'\r'
;
return
parse822_is_char
(
c
)
&&
c
!=
'"'
&&
c
!=
'\\'
&&
c
!=
'\r'
;
}
int
IsDT
ext
(
char
c
)
int
parse822_is_d_t
ext
(
char
c
)
{
return
IsCHAR
(
c
)
&&
c
!=
'['
&&
c
!=
']'
&&
c
!=
'\\'
&&
c
!=
'\r'
;
return
parse822_is_char
(
c
)
&&
c
!=
'['
&&
c
!=
']'
&&
c
!=
'\\'
&&
c
!=
'\r'
;
}
int
IsSmtpQ
(
char
c
)
/*
* SMTP's version of qtext, called <q> in the RFC 821 syntax,
* also excludes <LF>.
*/
int
parse822_is_smtp_q
(
char
c
)
{
return
IsQT
ext
(
c
)
&&
c
!=
'\n'
;
return
parse822_is_q_t
ext
(
c
)
&&
c
!=
'\n'
;
}
//
// Lexical Analysis - these tokens are all from RFC822,
// section 3.3, Lexical Tokens, though not all tokens are
// implemented.
//
/*
* Lexical Analysis - these tokens are all from RFC822,
* section 3.3, Lexical Tokens, though not all tokens are
* implemented. The names match those used int the extended
* BNF of the RFC where possible.
*/
int
SkipWs
(
char
**
p
,
char
*
e
)
int
parse822_skip_ws
(
const
char
**
p
,
const
char
*
e
)
{
int
ws
=
0
;
while
((
*
p
!=
e
)
&&
IsLWSPChar
(
**
p
))
{
++
ws
;
*
p
+=
1
;
}
return
ws
;
while
((
*
p
!=
e
)
&&
parse822_is_lwsp_char
(
**
p
))
{
*
p
+=
1
;
}
return
EOK
;
}
int
SkipComments
(
char
**
p
,
char
*
e
)
int
parse822_skip_comments
(
const
char
**
p
,
const
char
*
e
)
{
int
comment
s
;
int
statu
s
;
while
(
GetComment
(
p
,
e
,
0
)
)
comments
++
;
while
((
status
=
parse822_comment
(
p
,
e
,
0
))
==
EOK
)
;
return
comments
++
;
return
EOK
;
}
int
GetDigits
(
char
**
p
,
char
*
e
,
int
min
,
int
max
,
int
*
digits
)
int
parse822_digits
(
const
char
**
p
,
const
char
*
e
,
int
min
,
int
max
,
int
*
digits
)
{
char
*
save
=
*
p
;
const
char
*
save
=
*
p
;
int
i
=
0
;
int
i
=
0
;
assert
(
digits
);
assert
(
digits
);
*
digits
=
0
;
*
digits
=
0
;
while
(
IsDIGIT
(
p
,
e
))
{
*
digits
=
*
digits
*
10
+
**
p
-
'0'
;
*
p
+=
1
;
++
i
;
if
(
max
!=
0
&&
i
==
max
)
{
break
;
}
}
if
(
i
<
min
)
{
*
p
=
save
;
return
0
;
while
(
*
p
<
e
&&
parse822_is_digit
(
**
p
))
{
*
digits
=
*
digits
*
10
+
**
p
-
'0'
;
*
p
+=
1
;
++
i
;
if
(
max
!=
0
&&
i
==
max
)
{
break
;
}
}
if
(
i
<
min
)
{
*
p
=
save
;
return
EPARSE
;
}
return
1
;
return
EOK
;
}
int
GetSpecial
(
char
**
p
,
char
*
e
,
char
c
)
int
parse822_special
(
const
char
**
p
,
const
char
*
e
,
char
c
)
{
SkipWs
(
p
,
e
);
// not comments, they start with a special...
parse822_skip_ws
(
p
,
e
);
/* not comments, they start with a special... */
if
((
*
p
!=
e
)
&&
**
p
==
c
)
{
*
p
+=
1
;
return
1
;
}
return
0
;
if
((
*
p
!=
e
)
&&
**
p
==
c
)
{
*
p
+=
1
;
return
EOK
;
}
return
EPARSE
;
}
int
GetComment
(
char
**
p
,
char
*
e
,
char
**
comment
)
int
parse822_comment
(
const
char
**
p
,
const
char
*
e
,
char
**
comment
)
{
// comment = "(" *(ctext / quoted-pair / comment) ")"
// ctext = <any CHAR except "(", ")", "\", & CR, including LWSP>
if
(
!
GetSpecial
(
p
,
e
,
'('
))
{
return
0
;
}
while
(
*
p
!=
e
)
{
char
c
=
**
p
;
if
(
c
==
')'
)
{
*
p
+=
1
;
return
1
;
// found end-of-comment
}
else
if
(
c
==
'('
)
{
GetComment
(
p
,
e
,
comment
);
}
else
if
(
c
==
'\\'
)
{
GetQuotedPair
(
p
,
e
,
comment
);
}
else
if
(
c
==
'\r'
)
{
// invalid character...
*
p
+=
1
;
}
else
if
(
IsCHAR
(
c
))
{
StrAppendChar
(
comment
,
c
);
*
p
+=
1
;
}
else
{
// invalid character... should I append it?
*
p
+=
1
;
}
/* comment = "(" *(ctext / quoted-pair / comment) ")"
* ctext = <any char except "(", ")", "\", & CR, including lwsp>
*/
const
char
*
save
=
*
p
;
int
rc
;
if
((
rc
=
parse822_special
(
p
,
e
,
'('
)))
{
return
rc
;
}
while
(
*
p
!=
e
)
{
char
c
=
**
p
;
if
(
c
==
')'
)
{
*
p
+=
1
;
return
EOK
;
/* found end-of-comment */
}
else
if
(
c
==
'('
)
{
rc
=
parse822_comment
(
p
,
e
,
comment
);
}
else
if
(
c
==
'\\'
)
{
rc
=
parse822_quoted_pair
(
p
,
e
,
comment
);
}
else
if
(
c
==
'\r'
)
{
/* invalid character... */
*
p
+=
1
;
}
else
if
(
parse822_is_char
(
c
))
{
rc
=
str_append_char
(
comment
,
c
);
*
p
+=
1
;
}
else
{
/* invalid character... */
*
p
+=
1
;
}
return
0
;
// end-of-comment not found
if
(
rc
!=
EOK
)
break
;
}
if
(
*
p
==
e
)
{
rc
=
EPARSE
;
/* end-of-comment not found */
}
*
p
=
save
;
assert
(
rc
!=
EOK
);
return
rc
;
}
int
GetAtom
(
char
**
p
,
char
*
e
,
char
**
atom
)
int
parse822_atom
(
const
char
**
p
,
const
char
*
e
,
char
**
atom
)
{
// atom = 1*<an atom char>
/* atom = 1*<an atom char> */
int
ok
=
0
;
const
char
*
save
=
*
p
;
int
rc
=
EPARSE
;
SkipC
omments
(
p
,
e
);
parse822_skip_c
omments
(
p
,
e
);
while
((
*
p
!=
e
)
&&
IsAtomChar
(
**
p
))
{
++
ok
;
StrAppendChar
(
atom
,
**
p
);
*
p
+=
1
;
save
=
*
p
;
while
((
*
p
!=
e
)
&&
parse822_is_atom_char
(
**
p
))
{
rc
=
str_append_char
(
atom
,
**
p
);
*
p
+=
1
;
if
(
rc
!=
EOK
)
{
*
p
=
save
;
break
;
}
return
ok
;
}
return
rc
;
}
int
GetQuotedPair
(
char
**
p
,
char
*
e
,
char
**
qpair
)
int
parse822_quoted_pair
(
const
char
**
p
,
const
char
*
e
,
char
**
qpair
)
{
// quoted-pair = "\" CHAR
/* quoted-pair = "\" char */
/* need TWO characters to be available */
if
((
e
-
*
p
)
<
2
)
return
0
;
int
rc
;
if
(
**
p
!=
'\\'
)
return
0
;
/* need TWO characters to be available */
if
((
e
-
*
p
)
<
2
)
return
EPARSE
;
*
p
+=
1
;
if
(
*
p
==
e
)
return
0
;
if
(
**
p
!=
'\\'
)
return
EPARSE
;
StrAppendChar
(
qpair
,
**
p
);
if
((
rc
=
str_append_char
(
qpair
,
*
(
*
p
+
1
))))
return
rc
;
*
p
+=
1
;
*
p
+=
2
;
return
EOK
;
}
return
1
;
}
int
GetQuotedString
(
char
**
p
,
char
*
e
,
char
**
qstr
)
{
// quoted-string = <"> *(qtext/quoted-pair) <">
// qtext = CHAR except <">, "\", & CR, including LWSP-char
SkipComments
(
p
,
e
);
if
(
!
GetSpecial
(
p
,
e
,
'"'
))
return
0
;
while
(
*
p
!=
e
)
{
char
c
=
**
p
;
if
(
c
==
'"'
)
{
*
p
+=
1
;
return
1
;
// found end-of-qstr
}
else
if
(
c
==
'\\'
)
{
GetQuotedPair
(
p
,
e
,
qstr
);
}
else
if
(
c
==
'\r'
)
{
// invalid character...
*
p
+=
1
;
}
else
if
(
IsCHAR
(
c
))
{
StrAppendChar
(
qstr
,
c
);
*
p
+=
1
;
}
else
{
// invalid character...
*
p
+=
1
;
}
int
parse822_quoted_string
(
const
char
**
p
,
const
char
*
e
,
char
**
qstr
)
{
/* quoted-string = <"> *(qtext/quoted-pair) <">
* qtext = char except <">, "\", & CR, including lwsp-char
*/
const
char
*
save
=
*
p
;
int
rc
;
parse822_skip_comments
(
p
,
e
);
save
=
*
p
;
if
((
rc
=
parse822_special
(
p
,
e
,
'"'
)))
return
rc
;
while
(
*
p
!=
e
)
{
char
c
=
**
p
;
if
(
c
==
'"'
)
{
*
p
+=
1
;
return
EOK
;
/* found end-of-qstr */
}
else
if
(
c
==
'\\'
)
{
rc
=
parse822_quoted_pair
(
p
,
e
,
qstr
);
}
else
if
(
c
==
'\r'
)
{
/* invalid character... */
*
p
+=
1
;
}
else
if
(
parse822_is_char
(
c
))
{
rc
=
str_append_char
(
qstr
,
c
);
*
p
+=
1
;
}
else
{
/* invalid character... */
*
p
+=
1
;
}
if
(
rc
)
{
*
p
=
save
;
return
rc
;
}
return
0
;
// end-of-qstr not found
}
*
p
=
save
;
return
EPARSE
;
/* end-of-qstr not found */
}
int
GetWord
(
char
**
p
,
char
*
e
,
char
**
word
)
int
parse822_word
(
const
char
**
p
,
const
char
*
e
,
char
**
word
)
{
// word = atom / quoted-string
/* word = atom / quoted-string */
const
char
*
save
=
*
p
;
int
rc
=
EOK
;
char
*
save
=
*
p
;
parse822_skip_comments
(
p
,
e
)
;
SkipComments
(
p
,
e
)
;
save
=
*
p
;
{
char
*
qstr
=
0
;
if
(
GetQuotedString
(
p
,
e
,
&
qstr
)
)
{
StrA
ppend
(
word
,
qstr
);
{
char
*
qstr
=
0
;
if
((
rc
=
parse822_quoted_string
(
p
,
e
,
&
qstr
))
==
EOK
)
{
rc
=
str_a
ppend
(
word
,
qstr
);
StrF
ree
(
&
qstr
);
str_f
ree
(
&
qstr
);
return
1
;
}
if
(
rc
!=
EOK
)
*
p
=
save
;
return
rc
;
}
}
*
p
=
save
;
// Necessary because the quoted string could have found
// a partial string (invalid syntax). Thus reset, the atom
// will fail to if the syntax is invalid.
if
(
rc
!=
EPARSE
)
{
/* it's fatal */
return
rc
;
}
{
char
*
atom
=
0
;
if
(
GetAtom
(
p
,
e
,
&
atom
))
{
StrAppend
(
word
,
atom
);
/* Necessary because the quoted string could have found
* a partial string (invalid syntax). Thus reset, the atom
* will fail to if the syntax is invalid.
*/
StrFree
(
&
atom
);
{
char
*
atom
=
0
;
if
(
parse822_atom
(
p
,
e
,
&
atom
)
==
EOK
)
{
rc
=
str_append
(
word
,
atom
);
str_free
(
&
atom
);
if
(
rc
!=
EOK
)
*
p
=
save
;
return
1
;
}
return
rc
;
}
*
p
=
save
;
}
return
0
;
return
EPARSE
;
}
int
GetPhrase
(
char
**
p
,
char
*
e
,
char
**
phrase
)
int
parse822_phrase
(
const
char
**
p
,
const
char
*
e
,
char
**
phrase
)
{
// phrase = 1*word
/* phrase = 1*word */
if
(
!
GetWord
(
p
,
e
,
phrase
))
{
return
0
;
}
// ok, got the 1 word, now append all the others we can
{
char
*
word
=
0
;
while
(
GetWord
(
p
,
e
,
&
word
))
{
StrAppendChar
(
phrase
,
' '
);
StrAppend
(
phrase
,
word
);
*
word
=
0
;
}
}
return
1
;
}
const
char
*
save
=
*
p
;
int
rc
;
// this is all a bit of a hack....
typedef
struct
_address
mailbox_t
;
if
((
rc
=
parse822_word
(
p
,
e
,
phrase
)))
return
rc
;
mailbox_t
*
new_mb
(
void
)
{
return
(
mailbox_t
*
)
calloc
(
1
,
sizeof
(
mailbox_t
));
}
/* ok, got the 1 word, now append all the others we can */
{
char
*
word
=
0
;
mailbox_t
*
fill_mb
(
char
*
comments
,
char
*
personal
,
char
*
local
,
char
*
domain
)
{
mailbox_t
*
mb
=
new_mb
();
while
((
rc
=
parse822_word
(
p
,
e
,
&
word
))
==
EOK
)
{
rc
=
str_append_char
(
phrase
,
' '
);
if
(
!
mb
)
{
return
0
;
}
if
(
rc
==
EOK
)
rc
=
str_append
(
phrase
,
word
);
mb
->
comments
=
comments
;
mb
->
personal
=
personal
;
str_free
(
&
word
);
/* this is wrong, local must be quoted */
StrAppend
(
&
mb
->
email
,
local
);
StrAppend
(
&
mb
->
email
,
"@"
);
StrAppend
(
&
mb
->
email
,
domain
);
if
(
rc
!=
EOK
)
break
;
}
if
(
rc
==
EPARSE
)
rc
=
EOK
;
/* its not an error to find no more words */
}
if
(
rc
)
*
p
=
save
;
mb
->
local_part
=
local
;
mb
->
domain
=
domain
;
return
rc
;
}
return
mb
;
static
address_t
new_mb
(
void
)
{
return
calloc
(
1
,
sizeof
(
struct
_address
));
}
int
address_create0
(
address_t
*
a
,
const
char
*
s
)
static
int
fill_mb
(
address_t
*
a
,
char
*
comments
,
char
*
personal
,
char
*
local
,
char
*
domain
)
{
// a must exist, and can't already have been initialized
int
status
=
0
;
int
rc
=
EOK
;
*
a
=
new_mb
();
if
(
!*
a
)
{
return
ENOMEM
;
}
(
*
a
)
->
comments
=
comments
;
(
*
a
)
->
personal
=
personal
;
/* this is wrong, local must be quoted */
do
{
/* loop exists only to break out of */
if
((
rc
=
str_append
(
&
(
*
a
)
->
email
,
local
)))
break
;
if
((
rc
=
str_append
(
&
(
*
a
)
->
email
,
"@"
)))
break
;
if
((
rc
=
str_append
(
&
(
*
a
)
->
email
,
domain
)))
break
;
}
while
(
0
);
(
*
a
)
->
local_part
=
local
;
(
*
a
)
->
domain
=
domain
;
if
(
rc
!=
EOK
)
{
/* note that the arguments have NOT been freed, we only own
* them on success. */
free
(
*
a
);
}
return
rc
;
}
if
(
!
a
||
*
a
)
{
return
EINVAL
;
int
address_create0
(
address_t
*
a
,
const
char
*
s
)
{
/* 'a' must exist, and can't already have been initialized
*/
int
status
=
0
;
if
(
!
a
||
*
a
)
{
return
EINVAL
;
}
status
=
parse822_address_list
(
a
,
(
char
*
)
s
);
if
(
status
==
EOK
)
{
if
(
!*
a
)
{
/* there was a group that got parsed correctly, but had
* no addresses...
*/
return
EPARSE
;
}
status
=
GetAddressList
(
a
,
(
char
*
)
s
);
if
(
status
>
0
)
{
(
*
a
)
->
addr
=
strdup
(
s
);
if
(
!
(
*
a
)
->
addr
)
{
address_destroy
(
a
);
return
ENOMEM
;
}
(
*
a
)
->
addr
=
strdup
(
s
);
if
(
!
(
*
a
)
->
addr
)
{
address_destroy
(
a
);
return
ENOMEM
;
}
}
return
0
;
return
status
;
}
int
GetAddressList
(
mailbox_t
**
a
,
char
*
s
)
int
parse822_address_list
(
address_t
*
a
,
const
char
*
s
)
{
// address-list = #(address)
/* address-list = #(address) */
char
**
p
=
&
s
;
char
*
e
=
&
s
[
strlen
(
s
)];
/* need to make the parsing api const-correct */
int
ok
=
0
;
mailbox_t
**
an
=
a
;
/* the next address we'll be creating */
const
char
**
p
=
&
s
;
const
char
*
e
=
&
s
[
strlen
(
s
)];
int
rc
=
EOK
;
address_t
*
n
=
a
;
/* the next address we'll be creating */
if
(
!
GetAddress
(
p
,
e
,
an
))
return
0
;
if
((
rc
=
parse822_address
(
p
,
e
,
n
)
))
return
rc
;
parse822_skip_comments
(
p
,
e
);
while
(
*
p
<
e
)
{
/* An address can contain a group, so an entire
* list of addresses may have been appended, or no
* addresses at all. Walk to the end.
*/
while
(
*
an
)
{
++
ok
;
an
=
&
(
*
an
)
->
next
;
while
(
*
n
)
{
n
=
&
(
*
n
)
->
next
;
}
/* Remember that ',,a@b' is a valid list! So, we must find
* the <,>, but the address after it can be empty.
*/
if
((
rc
=
parse822_special
(
p
,
e
,
','
)))
{
break
;
}
parse822_skip_comments
(
p
,
e
);
rc
=
parse822_address
(
p
,
e
,
n
);
SkipComments
(
p
,
e
);
while
(
GetSpecial
(
p
,
e
,
','
))
{
// Remember that 'a,,b' is a valid list!
if
(
GetAddress
(
p
,
e
,
an
))
{
while
(
*
an
)
{
++
ok
;
an
=
&
(
*
an
)
->
next
;
}
}
if
(
rc
==
EOK
||
rc
==
EPARSE
)
{
/* that's cool, it may be a <,>, we'll find out if it isn't
* at the top of the loop
*/
rc
=
EOK
;
}
else
{
/* anything else is a fatal error, break out */
break
;
}
// A little problem here in that we return the number of
// addresses found, but if there was trailing garbage
// in the text, then we'll just be ignoring that.
parse822_skip_comments
(
p
,
e
);
}
return
ok
;
}
int
GetAddress
(
char
**
p
,
char
*
e
,
mailbox_t
**
a
)
{
// address = mailbox / group
if
(
rc
)
{
address_destroy
(
a
);
}
return
GetMailBox
(
p
,
e
,
a
)
||
GetGroup
(
p
,
e
,
a
);
return
rc
;
}
int
GetGroup
(
char
**
p
,
char
*
e
,
mailbox_t
**
a
)
int
parse822_address
(
const
char
**
p
,
const
char
*
e
,
address_t
*
a
)
{
// group = phrase ":" [#mailbox] ";"
/* address = mailbox / group */
char
*
save
=
*
p
;
int
rc
;
if
((
rc
=
parse822_mail_box
(
p
,
e
,
a
))
==
EPARSE
)
rc
=
parse822_group
(
p
,
e
,
a
);
SkipComments
(
p
,
e
);
return
rc
;
}
if
(
!
GetPhrase
(
p
,
e
,
0
))
{
return
0
;
}
int
parse822_group
(
const
char
**
p
,
const
char
*
e
,
address_t
*
a
)
{
/* group = phrase ":" [#mailbox] ";" */
SkipComments
(
p
,
e
);
const
char
*
save
=
*
p
;
address_t
*
asave
=
a
;
/* so we can destroy these if parsing fails */
int
rc
;
if
(
!
GetSpecial
(
p
,
e
,
':'
))
{
*
p
=
save
;
return
0
;
}
parse822_skip_comments
(
p
,
e
);
SkipComments
(
p
,
e
)
;
*
p
=
save
;
if
(
GetMailBox
(
p
,
e
,
a
))
{
a
=
&
(
*
a
)
->
next
;
if
((
rc
=
parse822_phrase
(
p
,
e
,
0
)))
{
return
rc
;
}
/* see if there are more */
SkipComments
(
p
,
e
);
while
(
GetSpecial
(
p
,
e
,
','
))
{
SkipComments
(
p
,
e
);
parse822_skip_comments
(
p
,
e
);
/* Rembmeber that a,,b is a valid list! */
if
(
GetMailBox
(
p
,
e
,
a
))
{
a
=
&
(
*
a
)
->
next
;
}
}
if
((
rc
=
parse822_special
(
p
,
e
,
':'
)))
{
*
p
=
save
;
return
rc
;
}
/* Basically, on each loop, we may find a mailbox, but we must find
* a comma after the mailbox, otherwise we've popped off the end
* of the list.
*/
for
(;;)
{
parse822_skip_comments
(
p
,
e
);
/* it's ok not be a mailbox, but other errors are fatal */
rc
=
parse822_mail_box
(
p
,
e
,
a
);
if
(
rc
==
EOK
)
{
a
=
&
(
*
a
)
->
next
;
parse822_skip_comments
(
p
,
e
);
}
else
if
(
rc
!=
EPARSE
)
{
break
;
}
if
(
!
GetSpecial
(
p
,
e
,
';'
))
{
*
p
=
save
;
return
0
;
if
(
(
rc
=
parse822_special
(
p
,
e
,
','
)
))
{
/* the commas aren't optional */
break
;
}
}
if
(
rc
==
EPARSE
)
{
rc
=
EOK
;
/* ok, as long as we find the ";" next */
}
return
1
;
}
int
GetMailBox
(
char
**
p
,
char
*
e
,
mailbox_t
**
a
)
{
// mailbox = addr-spec "(" comment ")" / [phrase] route-addr
//
// Note: we parse the ancient comment on the right since
// it's such "common practice". :-(
// Note: phrase is called display-name in drums.
// Note: phrase is optional in drums, though not in RFC 822.
// -> addr-spec
if
(
GetAddrSpec
(
p
,
e
,
a
))
{
char
*
comment
=
0
;
if
(
rc
||
(
rc
=
parse822_special
(
p
,
e
,
';'
)))
{
*
p
=
save
;
SkipWs
(
p
,
e
);
address_destroy
(
asave
);
}
if
(
GetComment
(
p
,
e
,
&
comment
))
{
// yuck.
(
*
a
)
->
personal
=
comment
;
}
return
rc
;
}
return
1
;
int
parse822_mail_box
(
const
char
**
p
,
const
char
*
e
,
address_t
*
a
)
{
/* mailbox = addr-spec [ "(" comment ")" ] / [phrase] route-addr
*
* Note: we parse the ancient comment on the right since
* it's such "common practice". :-(
* Note: phrase is called display-name in drums.
* Note: phrase is optional in drums, though not in RFC 822.
*/
const
char
*
save
=
*
p
;
int
rc
;
/* -> addr-spec */
if
((
rc
=
parse822_addr_spec
(
p
,
e
,
a
))
==
EOK
)
{
/*int rc = EOK; */
parse822_skip_ws
(
p
,
e
);
/* yuck. */
if
((
rc
=
parse822_comment
(
p
,
e
,
&
(
*
a
)
->
personal
))
==
EPARSE
)
{
rc
=
EOK
;
/* cool if there's no comment, */
}
/* but if something else is wrong, destroy the address */
if
(
rc
)
{
address_destroy
(
a
);
*
p
=
save
;
}
// -> phrase route-addr
{
char
*
save
=
*
p
;
char
*
phrase
=
0
;
return
rc
;
}
if
(
rc
!=
EPARSE
)
{
*
p
=
save
;
return
rc
;
}
/* -> phrase route-addr */
{
char
*
phrase
=
0
;
/*int rc; */
GetP
hrase
(
p
,
e
,
&
phrase
);
rc
=
parse822_p
hrase
(
p
,
e
,
&
phrase
);
if
(
!
GetRouteAddr
(
p
,
e
,
a
))
{
*
p
=
save
;
return
0
;
}
if
(
rc
!=
EPARSE
&&
rc
!=
EOK
)
{
return
rc
;
}
/* add the phrase */
(
*
a
)
->
personal
=
phrase
;
if
((
rc
=
parse822_route_addr
(
p
,
e
,
a
)))
{
*
p
=
save
;
str_free
(
&
phrase
);
return
rc
;
}
return
1
;
/* add the phrase */
(
*
a
)
->
personal
=
phrase
;
}
return
EOK
;
}
int
GetRouteAddr
(
char
**
p
,
char
*
e
,
mailbox_t
**
a
)
int
parse822_route_addr
(
const
char
**
p
,
const
char
*
e
,
address_t
*
a
)
{
// route-addr = "<" [route] addr-spec ">"
/* route-addr = "<" [route] addr-spec ">" */
char
*
save
=
*
p
;
char
*
route
=
0
;
const
char
*
save
=
*
p
;
char
*
route
=
0
;
int
rc
;
SkipC
omments
(
p
,
e
);
parse822_skip_c
omments
(
p
,
e
);
if
((
rc
=
parse822_special
(
p
,
e
,
'<'
)))
{
*
p
=
save
;
if
(
!
GetSpecial
(
p
,
e
,
'<'
))
{
*
p
=
save
;
return
rc
;
}
return
0
;
}
parse822_route
(
p
,
e
,
&
route
);
GetRoute
(
p
,
e
,
&
route
);
if
((
rc
=
parse822_addr_spec
(
p
,
e
,
a
)))
{
*
p
=
save
;
if
(
!
GetAddrSpec
(
p
,
e
,
a
))
{
*
p
=
save
;
str_free
(
&
route
);
StrFree
(
&
route
);
return
rc
;
}
return
0
;
}
(
*
a
)
->
route
=
route
;
/* now we don't have to free our local */
(
*
a
)
->
route
=
route
;
/* now we don't have to free our local */
parse822_skip_comments
(
p
,
e
);
SkipComments
(
p
,
e
);
if
(
!
GetSpecial
(
p
,
e
,
'>'
))
{
*
p
=
save
;
if
((
rc
=
parse822_special
(
p
,
e
,
'>'
)))
{
*
p
=
save
;
address_destroy
(
a
);
return
0
;
}
address_destroy
(
a
);
return
rc
;
}
return
1
;
return
EOK
;
}
int
GetRoute
(
char
**
p
,
char
*
e
,
char
**
route
)
int
parse822_route
(
const
char
**
p
,
const
char
*
e
,
char
**
route
)
{
// route = 1#("@" domain ) ":"
//
// Note: I don't hav a way of returning the route, so toss it for now.
/* route = 1#("@" domain ) ":" */
char
*
accumulator
=
0
;
const
char
*
save
=
*
p
;
char
*
accumulator
=
0
;
int
rc
=
EOK
;
for
(;;)
{
SkipC
omments
(
p
,
e
);
for
(;;)
{
parse822_skip_c
omments
(
p
,
e
);
if
(
!
GetSpecial
(
p
,
e
,
'@'
))
{
// it's not a route
return
0
;
}
if
((
rc
=
parse822_special
(
p
,
e
,
'@'
)))
{
break
;
}
StrAppend
(
&
accumulator
,
"@"
);
if
((
rc
=
str_append
(
&
accumulator
,
"@"
)))
{
break
;
}
SkipC
omments
(
p
,
e
);
parse822_skip_c
omments
(
p
,
e
);
if
(
!
GetDomain
(
p
,
e
,
&
accumulator
))
{
// it looked like a route, but there's no domain!
return
0
;
}
if
((
rc
=
parse822_domain
(
p
,
e
,
&
accumulator
)
))
{
/* it looked like a route, but there's no domain! */
break
;
}
SkipC
omments
(
p
,
e
);
parse822_skip_c
omments
(
p
,
e
);
if
(
!
GetSpecial
(
p
,
e
,
','
))
{
// there's no more routes
break
;
}
StrAppend
(
&
accumulator
,
", "
);
if
((
rc
=
parse822_special
(
p
,
e
,
','
))
==
EPARSE
)
{
/* no more routes, but we got one so its ok */
rc
=
EOK
;
break
;
}
if
((
rc
=
str_append
(
&
accumulator
,
", "
)))
{
break
;
}
}
SkipC
omments
(
p
,
e
);
parse822_skip_c
omments
(
p
,
e
);
if
(
!
GetSpecial
(
p
,
e
,
':'
)
)
{
return
0
;
}
if
(
!
rc
)
{
rc
=
parse822_special
(
p
,
e
,
':'
)
;
}
StrAppend
(
route
,
accumulator
);
StrFree
(
&
accumulator
);
if
(
!
rc
)
{
rc
=
str_append
(
route
,
accumulator
);
}
if
(
rc
)
{
str_free
(
&
accumulator
);
*
p
=
save
;
}
return
1
;
return
rc
;
}
int
GetAddrSpec
(
char
**
p
,
char
*
e
,
mailbox_t
**
a
)
int
parse822_addr_spec
(
const
char
**
p
,
const
char
*
e
,
address_t
*
a
)
{
// addr-spec = local-part "@" domain
/* addr-spec = local-part "@" domain */
char
*
save
=
*
p
;
char
*
local_part
=
0
;
char
*
domain
=
0
;
const
char
*
save
=
*
p
;
char
*
local_part
=
0
;
char
*
domain
=
0
;
int
rc
;
if
(
!
GetLocalPart
(
p
,
e
,
&
local_part
))
return
0
;
rc
=
parse822_local_part
(
p
,
e
,
&
local_part
);
SkipC
omments
(
p
,
e
);
parse822_skip_c
omments
(
p
,
e
);
if
(
!
GetSpecial
(
p
,
e
,
'@'
))
{
*
p
=
save
;
return
0
;
}
if
(
!
rc
)
{
rc
=
parse822_special
(
p
,
e
,
'@'
);
}
if
(
!
GetDomain
(
p
,
e
,
&
domain
))
{
*
p
=
save
;
return
0
;
}
if
(
!
rc
)
{
rc
=
parse822_domain
(
p
,
e
,
&
domain
);
}
*
a
=
fill_mb
(
0
,
0
,
local_part
,
domain
);
if
(
!
rc
)
{
rc
=
fill_mb
(
a
,
0
,
0
,
local_part
,
domain
);
}
return
1
;
if
(
rc
)
{
*
p
=
save
;
str_free
(
&
local_part
);
str_free
(
&
domain
);
}
return
rc
;
}
int
GetLocalPart
(
char
**
p
,
char
*
e
,
char
**
local_part
)
{
// local-part = word *("." word)
// Note: rewrite as -> word ["." local-part]
char
*
save
=
*
p
;
SkipComments
(
p
,
e
);
if
(
!
GetWord
(
p
,
e
,
local_part
))
{
*
p
=
save
;
return
0
;
}
// we've got a local-part, but keep looking for more
int
parse822_local_part
(
const
char
**
p
,
const
char
*
e
,
char
**
local_part
)
{
/* local-part = word *("." word)
*
* Note: rewrite as -> word ["." local-part]
*/
save
=
*
p
;
const
char
*
save
=
*
p
;
const
char
*
save2
=
*
p
;
int
rc
;
SkipC
omments
(
p
,
e
);
parse822_skip_c
omments
(
p
,
e
);
if
(
!
GetSpecial
(
p
,
e
,
'.'
))
{
*
p
=
save
;
return
1
;
}
{
char
*
more
=
0
;
if
(
!
GetLocalPart
(
p
,
e
,
&
more
))
{
*
p
=
save
;
return
1
;
}
// append more
StrAppend
(
local_part
,
"."
);
StrAppend
(
local_part
,
more
);
StrFree
(
&
more
);
if
((
rc
=
parse822_word
(
p
,
e
,
local_part
)))
{
*
p
=
save
;
return
rc
;
}
/* We've got a local-part, but keep looking for more. */
parse822_skip_comments
(
p
,
e
);
/* If we get a parse error, we roll back to save2, but if
* something else failed, we have to roll back to save.
*/
save2
=
*
p
;
rc
=
parse822_special
(
p
,
e
,
'.'
);
if
(
!
rc
)
{
char
*
more
=
0
;
if
((
rc
=
parse822_local_part
(
p
,
e
,
&
more
))
==
EOK
)
{
/* append more */
if
((
rc
=
str_append
(
local_part
,
"."
))
==
EOK
)
{
rc
=
str_append
(
local_part
,
more
);
}
str_free
(
&
more
);
}
return
1
;
}
if
(
rc
==
EPARSE
)
{
/* if we didn't get more ("." word) pairs, that's ok */
*
p
=
save2
;
rc
=
EOK
;
}
if
(
rc
)
{
/* if anything else failed, that's real */
*
p
=
save
;
str_free
(
local_part
);
}
return
rc
;
}
int
GetDomain
(
char
**
p
,
char
*
e
,
char
**
domain
)
int
parse822_domain
(
const
char
**
p
,
const
char
*
e
,
char
**
domain
)
{
// domain = sub-domain *("." sub-domain)
/* domain = sub-domain *("." sub-domain)
*
* Note: rewrite as -> sub-domain ("." domain)
*/
// Note: rewrite as -> sub-domain ("." domain)
const
char
*
save
=
*
p
;
const
char
*
save2
=
0
;
int
rc
;
char
*
save
=
0
;
parse822_skip_comments
(
p
,
e
)
;
if
(
!
GetSubDomain
(
p
,
e
,
domain
))
return
0
;
if
((
rc
=
parse822_sub_domain
(
p
,
e
,
domain
)))
{
*
p
=
save
;
return
rc
;
}
// we've got the 1, keep looking for more
save
=
*
p
;
/* We save before skipping comments to preserve the comment
* at the end of a domain, the addr-spec may want to abuse it
* for a personal name.
*/
save2
=
*
p
;
SkipComments
(
p
,
e
);
/* we've got the 1, keep looking for more */
if
(
!
GetSpecial
(
p
,
e
,
'.'
))
{
// we do this to preserve the comment at the end of a
// domain, the addr-spec may want to abuse it for a
// personal name.
*
p
=
save
;
return
1
;
}
{
char
*
more
=
0
;
if
(
!
GetDomain
(
p
,
e
,
&
more
))
{
*
p
=
save
;
return
1
;
}
StrAppend
(
domain
,
"."
);
StrAppend
(
domain
,
more
);
StrFree
(
&
more
);
}
parse822_skip_comments
(
p
,
e
);
return
1
;
}
int
GetSubDomain
(
char
**
p
,
char
*
e
,
char
**
sub_domain
)
{
// sub-domain = domain-ref / domain-literal
// Note: domain-literal isn't supported yet.
rc
=
parse822_special
(
p
,
e
,
'.'
);
return
GetDomainRef
(
p
,
e
,
sub_domain
)
||
GetDomainLiteral
(
p
,
e
,
sub_domain
);
if
(
!
rc
)
{
char
*
more
=
0
;
if
((
rc
=
parse822_domain
(
p
,
e
,
&
more
))
==
EOK
)
{
if
((
rc
=
str_append
(
domain
,
"."
))
==
EOK
)
{
rc
=
str_append
(
domain
,
more
);
}
str_free
(
&
more
);
}
}
if
(
rc
==
EPARSE
)
{
/* we didn't parse more ("." sub-domain) pairs, that's ok */
*
p
=
save2
;
rc
=
EOK
;
}
if
(
rc
)
{
/* something else failed, roll it all back */
*
p
=
save
;
str_free
(
domain
);
}
return
rc
;
}
int
GetDomainRef
(
char
**
p
,
char
*
e
,
char
**
domain_ref
)
{
// domain-ref = atom
return
GetAtom
(
p
,
e
,
domain_ref
);
}
int
GetDText
(
char
**
p
,
char
*
e
,
char
**
dtext
)
int
parse822_sub_domain
(
const
char
**
p
,
const
char
*
e
,
char
**
sub_domain
)
{
// dtext = 1*dtext
// Note: dtext is only defined as a character class in
// RFC822, but this definition is more useful for
// slurping domain literals.
/* sub-domain = domain-ref / domain-literal
*/
char
*
start
=
*
p
;
int
rc
;
if
((
rc
=
parse822_domain_ref
(
p
,
e
,
sub_domain
))
==
EPARSE
)
rc
=
parse822_domain_literal
(
p
,
e
,
sub_domain
);
while
(
*
p
<
e
&&
IsDText
(
**
p
))
{
*
p
+=
1
;
}
if
(
start
==
*
p
)
{
return
0
;
}
return
rc
;
}
StrAppendRange
(
dtext
,
start
,
*
p
);
int
parse822_domain_ref
(
const
char
**
p
,
const
char
*
e
,
char
**
domain_ref
)
{
/* domain-ref = atom */
return
1
;
return
parse822_atom
(
p
,
e
,
domain_ref
)
;
}
int
GetDomainLiteral
(
char
**
p
,
char
*
e
,
char
**
domain_literal
)
int
parse822_d_text
(
const
char
**
p
,
const
char
*
e
,
char
**
dtext
)
{
// domain-literal = "[" *(dtext / quoted-pair) "]"
/* d-text = 1*dtext
*
* Note: dtext is only defined as a character class in
* RFC822, but this definition is more useful for
* slurping domain literals.
*/
char
*
save
=
*
p
;
const
char
*
start
=
*
p
;
int
rc
=
EOK
;
char
*
literal
=
0
;
while
(
*
p
<
e
&&
parse822_is_d_text
(
**
p
))
{
*
p
+=
1
;
}
if
(
!
GetSpecial
(
p
,
e
,
'['
))
{
return
0
;
}
StrAppendChar
(
&
literal
,
'['
);
if
(
start
==
*
p
)
{
return
EPARSE
;
}
while
(
GetDText
(
p
,
e
,
&
literal
)
||
GetQuotedPair
(
p
,
e
,
&
literal
))
{
/* Eat all of this we can get! */
}
if
(
!
GetSpecial
(
p
,
e
,
']'
))
{
*
p
=
save
;
if
((
rc
=
str_append_range
(
dtext
,
start
,
*
p
)))
{
*
p
=
start
;
}
return
0
;
}
StrAppendChar
(
&
literal
,
']'
);
return
rc
;
}
StrAppend
(
domain_literal
,
literal
);
int
parse822_domain_literal
(
const
char
**
p
,
const
char
*
e
,
char
**
domain_literal
)
{
/* domain-literal = "[" *(dtext / quoted-pair) "]" */
StrFree
(
&
literal
);
const
char
*
save
=
*
p
;
char
*
literal
=
0
;
int
rc
;
return
1
;
if
((
rc
=
parse822_special
(
p
,
e
,
'['
)))
{
return
rc
;
}
if
((
rc
=
str_append_char
(
&
literal
,
'['
)))
{
*
p
=
save
;
return
rc
;
}
while
(
(
rc
=
parse822_d_text
(
p
,
e
,
&
literal
))
==
EOK
||
(
rc
=
parse822_quoted_pair
(
p
,
e
,
&
literal
))
==
EOK
)
{
/* Eat all of this we can get! */
}
if
(
rc
==
EPARSE
)
{
rc
=
EOK
;
}
if
(
!
rc
)
{
rc
=
parse822_special
(
p
,
e
,
']'
);
}
if
(
!
rc
)
{
rc
=
str_append_char
(
&
literal
,
']'
);
}
if
(
!
rc
)
{
rc
=
str_append
(
domain_literal
,
literal
);
}
str_free
(
&
literal
);
if
(
rc
)
{
*
p
=
save
;
}
return
rc
;
}
#if 0
int
GetFieldName(char** p,
char* e, char** fieldname)
int
parse822_field_name(const char** p, const
char* e, char** fieldname)
{
// field-name = 1*<any CHAR, excluding CTLS, SPACE, and ":"> ":"
/* field-name = 1*<any char, excluding ctlS, space, and ":"> ":" */
Ptr save = p;
Ptr save = p;
Rope fn;
Rope fn;
while(*p != e) {
char c = *p;
while(*p != e) {
char c = *p;
if(!IsCHAR
(c))
break;
if(!parse822_is_char
(c))
break;
if(IsCTL
(c))
break;
if(IsSPACE
(c))
break;
if(c == ':')
break;
if(parse822_is_ctl
(c))
break;
if(parse822_is_space
(c))
break;
if(c == ':')
break;
fn.append(c);
*p += 1;
}
// must be at least one char in the field name
if(fn.empty()) {
p = save;
return 0;
}
SkipC
omments(p, e);
fn.append(c);
*p += 1;
}
/* must be at least one char in the field name */
if(fn.empty()) {
p = save;
return 0;
}
parse822_skip_c
omments(p, e);
if(!GetS
pecial(p, e, ':')) {
p = save;
return 0;
}
if(!parse822_s
pecial(p, e, ':')) {
p = save;
return 0;
}
fieldname = fn;
fieldname = fn;
return 1;
return 1;
}
int GetFieldBody(char** p, char* e, Rope& fieldbody)
int parse822_field_body(const char** p, const char* e, Rope& fieldbody)
{
// field-body = *text [CRLF LWSP-char field-body]
/* field-body = *text [CRLF lwsp-char field-body] */
Ptr save = p;
Ptr save = p;
Rope fb;
Rope fb;
for(;;)
{
Ptr eol = p;
while(eol != e) {
char c = *eol;
if(eol[0] == '\r' && (eol+1) != e && eol[1] == '\n')
break;
++eol;
}
fb.append(p, eol);
p = eol;
if(eol == e)
break; // no more, so we're done
for(;;)
{
Ptr eol = p;
while(eol != e) {
char c = *eol;
if(eol[0] == '\r' && (eol+1) != e && eol[1] == '\n')
break;
++eol;
}
fb.append(p, eol);
p = eol;
if(eol == e)
break; /* no more, so we're done */
assert(p[0] == '\r');
assert(p[1] == '\n');
assert(p[0] == '\r');
assert(p[1] == '\n');
p += 2;
p += 2;
if(*p == e)
break; // no more, so we're done
if(*p == e)
break; /* no more, so we're done */
// check if next line is a continuation line
if(*p != ' ' && *p != '\t')
break;
}
/* check if next line is a continuation line */
if(*p != ' ' && *p != '\t')
break;
}
fieldbody = fb;
fieldbody = fb;
return 1;
return 1;
}
#endif
...
...
Please
register
or
sign in
to post a comment