Initial revision

This commit is contained in:
Peter Simons 2000-12-16 12:38:21 +00:00
parent 713e8e60dc
commit 0909ac418c
15 changed files with 4151 additions and 0 deletions

66
libmpools/Makefile Normal file
View File

@ -0,0 +1,66 @@
#
# libmpools Makefile
#
# $Header$
#
# Make Rules:
# ===========
#
.c.o:
$(CC) $(CFLAGS) $(CPPFLAGS) -c $<
# Compiler Flags:
# ===============
#
CFLAGS = -Wall
CPPFLAGS=
#
# Labels:
# =======
#
SRCS = mpools.c
OBJS = $(SRCS:.c=.o)
MANFILES= $(SRCS:.c=.3)
#
# Targets
#
.PHONY: all man clean realclean distclean depend
all: libmpools.a
man: mp_malloc.3
clean:
rm -f libmpools.a *.o *.3 *.core
realclean: clean
rm -rf man3
distclean: realclean
depend:
makedepend -Y /usr/include $(SRCS)
@rm -f Makefile.bak
mp_malloc.3: mpools.c
c2man -impools.h -g mpools.c;
#
# Actions
#
libmpools.a: $(OBJS)
rm -f $@
$(AR) cr $@ $(OBJS)
$(RANLIB) $@
#
# Dependencies
#

339
libmpools/mpools.c Normal file
View File

@ -0,0 +1,339 @@
/*
* $Source$
* $Revision$
* $Date$
*
* Copyright (C) 1997 by CyberSolutions GmbH.
* All rights reserved.
*/
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "../liblists/lists.h"
#include "mpools.h"
static List mpools_list = NULL;
/********** Internal routines **********/
static int
GetMemoryPool(const char * pool_name,
Node * node_ptr,
struct mp_list_entry ** mpool_entry_ptr)
{
Node node;
/* Sanity checks. */
assert(mpools_list != NULL);
assert(pool_name != NULL);
if (pool_name == NULL)
return -1;
/* Find the pool of the right name. */
node = FindNodeByKey(mpools_list, (const void *) pool_name);
if (node != NULL) {
if (node_ptr != NULL)
*node_ptr = node;
if (mpool_entry_ptr != NULL)
*mpool_entry_ptr = (struct mp_list_entry *) getNodeData(node);
return 0;
}
/* No entry available. So we create one. */
pool_name = strdup(pool_name);
if (pool_name == NULL)
return -1;
node = AppendNode(mpools_list, (const void *) pool_name, NULL);
if (node == NULL) {
free((char *) pool_name);
return -1;
}
/* Return result to caller. */
if (node_ptr != NULL)
*node_ptr = node;
if (mpool_entry_ptr != NULL)
*mpool_entry_ptr = (struct mp_list_entry *) getNodeData(node);
return 0;
}
/********** User interface **********/
/* mp_malloc() allocates a block of memory using malloc(3), adds the
pointer and the size of the block to the memory pool as identified
by the 'pool_name' argument and returns the address of the memory
block to the caller.
Memory pools are identified by a byte string, terminated with a
zero ('\\0') byte. The names are compared using strcmp(3), which is
case-sensitive.
RETURNS: If successfull, mp_malloc() returns a pointer to the newly
allocated memory block. In case of failure, NULL is returned
instead.
*/
void *
mp_malloc(const char * pool_name /* ID-String of the memory pool. */,
size_t block_size /* Size of the requested memory block. */
)
{
struct mp_list_entry * mpool;
Node node;
void * block;
/* Sanity checks. */
assert(pool_name != NULL);
if (pool_name == NULL || block_size <= 0)
return NULL;
/* Init the internal list structure, if it isn't already. */
if (mpools_list == NULL) {
mpools_list = InitList((int (*)(const void *, const void *)) strcmp);
if (mpools_list == NULL)
return NULL;
}
/* Get the pool structure. */
if (GetMemoryPool(pool_name, &node, NULL) != 0)
return NULL;
/* Allocate the memory. */
mpool = malloc(sizeof(struct mp_list_entry));
if (mpool == NULL)
return NULL;
block = malloc(block_size);
if (block == NULL) {
free(mpool);
return NULL;
}
/* Init the mpool structure. */
mpool->next = NULL;
mpool->block = block;
mpool->size = block_size;
/* Now append the structure to our list. */
if (getNodeData(node) != NULL)
mpool->next = (struct mp_list_entry *) getNodeData(node);
setNodeData(node, (const void *) mpool);
return block;
}
/* mp_free() will return the previously allocated memory block to the
system and remove the entry from the memory pool. The memory block
has to be previously allocated by mp_malloc(), or mp_free() won't
do anything.
It is safe to call mp_free() several times for the same memory
block, or for an invalid memory block, that hasn't been allocated
by mp_malloc(). mp_free will detect this and return without doing
anything.
*/
void
mp_free(const char * pool_name /* ID-String of the memory pool. */,
void * block /* Pointer to a memory block
previously allocated by mp_malloc(). */
)
{
struct mp_list_entry * mpool,
* prev_mpool;
Node node;
/* Sanity checks. */
assert(pool_name != NULL);
if (pool_name == NULL)
return;
/* Init the internal list structure, if it isn't already. */
if (mpools_list == NULL) {
mpools_list = InitList(NULL);
if (mpools_list == NULL)
return;
}
/* Get the pool structure. */
if (GetMemoryPool(pool_name, &node, &mpool) != 0)
return;
/* Find the block we should free. */
for (prev_mpool = NULL;
mpool != NULL && mpool->block != block;
prev_mpool = mpool, mpool = mpool->next)
;
if (mpool == NULL) { /* block not found */
printf("Warning\n");
return;
}
/* Remove the node from the linked list. */
if (prev_mpool == NULL)
setNodeData(node, mpool->next);
else
prev_mpool->next = mpool->next;
/* And free it plus our own structure stuff. */
free(mpool->block);
free(mpool);
}
/*
Remove the provided memory block from the memory pool, without
freeing the memory itself.
It is safe to call mp_remove_block_from_pool() with invalid data.
*/
void
mp_remove_block_from_pool(const char * pool_name /* ID-String of the memory pool. */,
void * block /* Pointer to a memory block
previously allocated by mp_malloc(). */
)
{
struct mp_list_entry * mpool,
* prev_mpool;
Node node;
/* Sanity checks. */
assert(pool_name != NULL);
assert(block != NULL);
if (!pool_name || !block)
return;
/* Init the internal list structure, if it isn't already. */
if (mpools_list == NULL) {
mpools_list = InitList(NULL);
return;
}
/* Get the pool structure. */
if (GetMemoryPool(pool_name, &node, &mpool) != 0)
return;
/* Find the block we should free. */
for (prev_mpool = NULL;
mpool != NULL && mpool->block != block;
prev_mpool = mpool, mpool = mpool->next)
;
if (mpool == NULL) /* block not found */
return;
/* Remove the node from the linked list. */
if (prev_mpool == NULL)
setNodeData(node, mpool->next);
else
prev_mpool->next = mpool->next;
/* Free the structure stuff. */
free(mpool);
}
/* This routine will return all allocated memory blocks contained in
pool 'pool_name' to the system.
*/
void
mp_free_memory_pool(const char * pool_name /* ID-String of the memory pool. */
)
{
struct mp_list_entry * mpool_entry,
* next_mpool_entry;
Node node;
/* Sanity checks. */
assert(pool_name != NULL);
if (pool_name == NULL)
return;
if (mpools_list == NULL)
return;
/* Find our memory pool. */
node = FindNodeByKey(mpools_list, pool_name);
if (node == NULL)
return;
mpool_entry = (struct mp_list_entry *) getNodeData(node);
/* And now we move the pool completely. */
RemoveNode(node);
free((void *) getNodeKey(node)); /* kill the pool name buffer */
FreeNode(node);
for ( ; mpool_entry != NULL; mpool_entry = next_mpool_entry) {
next_mpool_entry = mpool_entry->next;
free(mpool_entry->block);
free(mpool_entry);
}
}
/* This routine is experimental and for debugging purposes only. In
the current version, it will dump the contents of pool 'pool_name'
to the screen, using printf(3).
*/
void
mp_dump_memory_pool(const char * pool_name /* ID-String of the memory pool. */
)
{
struct mp_list_entry * mpool_entry;
unsigned int total;
/* Sanity checks. */
assert(pool_name != NULL);
if (pool_name == NULL)
return;
/* Dump the specified pool. */
if (GetMemoryPool(pool_name, NULL, &mpool_entry) != 0)
return;
if (mpool_entry == NULL) {
printf("mpool \"%s\" is empty.\n", pool_name);
return;
}
for (total = 0; mpool_entry != NULL; mpool_entry = mpool_entry->next) {
printf("\"%s\": %d byte block at $%08x.\n", pool_name, mpool_entry->size,
(unsigned int) mpool_entry->block);
total += mpool_entry->size;
}
printf("Total size of mpool \"%s\" is %u byte.\n", pool_name, total);
}

30
libmpools/mpools.h Normal file
View File

@ -0,0 +1,30 @@
/*
* $Source$
* $Revision$
* $Date$
*
* Copyright (C) 1996,97 by CyberSolutions GmbH.
* All rights reserved.
*/
#ifndef __LIB_MPOOLS_H__
#define __LIB_MPOOLS_H__ 1
#include <stdlib.h>
#ifdef DEBUG_DMALLOC
# include <dmalloc.h>
#endif
struct mp_list_entry {
struct mp_list_entry * next;
void * block;
size_t size;
};
void * mp_malloc(const char *, size_t);
void mp_free(const char * pool_name, void *);
void mp_free_memory_pool(const char *);
void mp_dump_memory_pool(const char *);
void mp_remove_block_from_pool(const char *, void *);
#endif /* !__LIB_MPOOLS_H__ */

97
librfc822/Makefile Normal file
View File

@ -0,0 +1,97 @@
#
# RFC Parse Library
#
# $Header$
#
# Make Rules:
# ===========
#
.c.o:
$(CC) $(CFLAGS) $(CPPFLAGS) -c $<
# Compiler flags:
# ===============
#
CFLAGS = -Wall
CPPFLAGS=
# Linker flags:
# =============
#
LDFLAGS =
LIBS = ../libmpools/libmpools.a ../liblists/liblists.a
#
# Labels:
# =======
#
SRCS = address.c address_scan.c decomment.c address_sep.c
OBJS = $(SRCS:.c=.o)
#
# Targets
#
.PHONY: all man clean realclean depend
all: librfc822.a
man: rfc822_decomment.3 rfc822_parse_address.3 rfc822_address_sep.3
test: test.o librfc822.a rfc822.h $(LIBS)
$(CC) test.o librfc822.a -o $@ $(LDFLAGS) $(LIBS)
clean:
rm -f librfc822.a test *.o *.3 *.core *.bak
realclean: clean
rm -f address.c address_scan.c address_scan.h
depend:
makedepend -Y /usr/include $(SRCS)
@rm -f Makefile.bak
#
# Actions:
#=========
#
librfc822.a: $(OBJS)
$(AR) cr $@ $(OBJS)
$(RANLIB) $@
address.c address_scan.h: address.y rfc822.h parse_address.c
$(YACC) -d -p "rfc822_" address.y
mv y.tab.c address.c
mv y.tab.h address_scan.h
address_scan.c: address_scan.l rfc822.h
$(LEX) -Prfc822_ address_scan.l
mv lex.rfc822_.c $@
rfc822_decomment.3: decomment.c
c2man -irfc822.h decomment.c
rfc822_parse_address.3: parse_address.c
c2man -irfc822.h parse_address.c
rfc822_address_sep.3: address_sep.c
c2man -irfc822.h address_sep.c
../libmpools/libmpools.a:
(cd ../libmpools;$(MAKE))
../liblists/liblists.a:
(cd ../liblists;$(MAKE))
#
# Dependencies
#
address.o: address.c address_scan.h address_scan.c parse_address.c
address_scan.c: address_scan.l
decomment.c: rfc822.h
address_sep.c: rfc822.h

1114
librfc822/address.c Normal file

File diff suppressed because it is too large Load Diff

180
librfc822/address.y Normal file
View File

@ -0,0 +1,180 @@
/*
* $Source$
* $Revision$
* $Date$
*
* Copyright (C) 1997 by CyberSolutions GmbH.
* All rights reserved.
*/
%{
/* Definitions we need in the parser. */
#include <errno.h>
#ifdef DEBUG_DMALLOC
# include <dmalloc.h>
#endif
#include "../libmpools/mpools.h"
#define yytext rfc822_text
#define yyley rfc822_lex
/* Variables in our lexer. */
extern char * rfc822_address_buffer;
extern int rfc822_address_buffer_pos;
extern char * yytext;
/* Our static/global variables. */
static int no_memory_flag;
static char * poolname,
* result_hostpart,
* result_localpart,
* result_address;
/* Prototypes for internal functions. */
static int yyparse(void);
static int yyerror(char *);
static char * pool_strdup(char *);
static char * pool_strjoin(char *, char *);
int yylex(void);
/* These macros call the routines we define later in a fail safe
way. */
#define str_dup(target,a) { \
target = (YYSTYPE) pool_strdup((char *) a); \
if (target == NULL) { \
no_memory_flag++; \
YYABORT; \
} \
}
#define str_join(target,a,b) { \
target = (YYSTYPE) pool_strjoin((char *) a, (char *) b); \
if (target == NULL) { \
no_memory_flag++; \
YYABORT; \
} \
}
%}
%token TOK_ATOM TOK_ILLEGAL
%left ':'
%left '@'
%%
address: local {
result_localpart = (char *)$1;
str_dup($$,$1);
result_address = (char *)$$;
}
| local at domain {
result_localpart = (char *)$1;
result_hostpart = (char *)$3;
str_join($$,$1,$2); str_join($$,$$,$3);
result_address = (char *)$$;
}
| at domain colon sourceroutings local {
result_hostpart = (char *)$2;
str_join($$,$4,$5);
result_localpart = (char *)$$;
str_join($$,$3,$$); str_join($$,$2,$$);
str_join($$,$1,$$);
result_address = (char *)$$;
}
| at domain colon sourceroutings local at domain {
result_hostpart = (char *)$2;
str_join($$,$4,$5); str_join($$,$$,$6);
str_join($$,$$,$7);
result_localpart = (char *)$$;
str_join($$,$3,$$); str_join($$,$2,$$);
str_join($$,$1,$$);
result_address = (char *)$$;
}
;
sourceroutings: /* empty */ { $$ = (YYSTYPE) NULL; }
| at domain colon sourceroutings {
str_join($$,$1,$2); str_join($$,$$,$3);
str_join($$,$$,$4);
}
local: atom { $$ = $1; }
| atom local { str_join($$,$1,$2); }
| dot { $$ = $1; }
| dot local { str_join($$,$1,$2); }
;
domain: atom { $$ = $1; }
| atom dot domain { str_join($$,$2,$3); str_join($$,$1,$$); }
;
atom: TOK_ATOM { str_dup($$,yytext); }
dot: '.' { $$ = (YYSTYPE) "."; }
at: '@' { $$ = (YYSTYPE) "@"; }
colon: ':' { $$ = (YYSTYPE) ":"; }
%%
/***** internal routines *****/
static int
yyerror(char * string)
{
return 0;
}
/* Do the same as strdup(3) but use the memory pool to allocate the
memory, so that we don't lose memory. */
static char *
pool_strdup(char * string)
{
char * p;
if (string == NULL)
return NULL;
p = mp_malloc(poolname, strlen(string) + 1);
if (p == NULL)
return NULL;
strcpy(p, string);
return p;
}
/* Allocate a new buffer (using the memory pool) and join the strings
'a' and 'b' into it. */
static char *
pool_strjoin(char * a, char * b)
{
char * p;
int length = 0;
if (a != NULL)
length += strlen(a);
if (b != NULL)
length += strlen(b);
if (length == 0)
return NULL;
p = mp_malloc(poolname, length + 2);
if (p == NULL)
return NULL;
else
*p = '\0';
if (a)
strcpy(p, a);
if (b)
strcpy(&(p[strlen(p)]), b);
return p;
}
/****** public routines ******/
#include "parse_address.c"

1660
librfc822/address_scan.c Normal file

File diff suppressed because it is too large Load Diff

8
librfc822/address_scan.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef YYSTYPE
#define YYSTYPE int
#endif
#define TOK_ATOM 257
#define TOK_ILLEGAL 258
extern YYSTYPE rfc822_lval;

56
librfc822/address_scan.l Normal file
View File

@ -0,0 +1,56 @@
/*
* $Source$
* $Revision$
* $Date$
*
* Copyright (C) 1997 by CyberSolutions GmbH.
* All rights reserved.
*/
%{
#ifdef DEBUG_DMALLOC
# include <dmalloc.h>
#endif
#include "rfc822.h"
#include "address_scan.h"
#define yylval rfc822_lval
extern int yylval;
char * rfc822_address_buffer;
int rfc822_address_buffer_pos;
#define YY_INPUT(buf,result,max_size) { \
buf[0] = rfc822_address_buffer[rfc822_address_buffer_pos++]; \
result = ((buf[0] != '\0') ? 1 : YY_NULL); \
}
%}
%x quoted escaped escaped2
%%
([^@\.\(\) \t<>\":,\\]*\\)/(.[@\.:]) { BEGIN(escaped2); yymore(); }
([^@\.\(\) \t<>\":,\\]*\\)/(.) { BEGIN(escaped2); yymore(); }
([^@\.\(\) \t<>\":,\\]*\\)/(.[^@\.:]) { BEGIN(escaped); yymore(); }
([^@\.\(\) \t<>\":,\\]*\\) { return TOK_ILLEGAL; }
[^@\.\(\) \t<>\":,\\]+ { return TOK_ATOM; }
[ \t]+ /* eat up whitespace */
[@\.:] { yylval = yytext[0]; return yylval; }
[<>\(\),:] { return TOK_ILLEGAL; }
<escaped>. { BEGIN(INITIAL); yymore(); }
<escaped2>. { BEGIN(INITIAL); return TOK_ATOM; }
\" { BEGIN(quoted); yymore(); }
<quoted>[^\"\\]+ { yymore(); }
<quoted>\\\" { yymore(); }
<quoted>\" { BEGIN(INITIAL); return TOK_ATOM; }
<quoted><<EOF>> { BEGIN(INITIAL); return TOK_ILLEGAL; }
%%
/* Internal routines. */
int
yywrap(void)
{
return 1;
}

152
librfc822/address_sep.c Normal file
View File

@ -0,0 +1,152 @@
/*
* $Source$
* $Revision$
* $Date$
*
* Copyright (C) 1997 by CyberSolutions GmbH.
* All rights reserved.
*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <assert.h>
#ifdef DEBUG_DMALLOC
# include <dmalloc.h>
#endif
#include "rfc822.h"
static char *
read_until_next_quote(char * p)
{
while (*p) {
if (*p == '"') {
p++;
break;
}
if (*p == '\\' && p[1] != '\0') {
p += 2;
continue;
}
p++;
}
return p;
}
static char *
read_until_close_bracket(char * p)
{
while (*p) {
if (*p == ')') {
p++;
break;
}
if (*p == '(') {
p = read_until_close_bracket(p+1);
continue;
}
else if (*p == '\\' && p[1] != '\0') {
p += 2;
continue;
}
else if (*p == '"') {
p = read_until_next_quote(p+1);
continue;
}
p++;
}
return p;
}
static int
is_source_routing(char * p)
{
while (*p) {
if (*p == '(')
p = read_until_close_bracket(p+1);
else if (*p == ' ' || *p == '\t')
p++;
else if (*p == '@' || *p == '<')
return 1;
else
return 0;
}
return 0;
}
/* Split an RFC822 address line.
This routine breaks an address line, as specified by RFC822, up
into separate addresses. The used delimiter is the comma (",").
The usage of the routine is very similar to strsep(3). More text to
come.
AUTHOR: Peter Simons <simons@rhein.de>
*/
char *
rfc822_address_sep(struct rfc822_address_sep_state * state)
{
char * p,
* old;
int allow_groups;
/* Sanity checks. */
assert(state != NULL);
if (!state) {
errno = EINVAL;
return NULL;
}
if (*(state->address_line) == '\0')
return NULL;
old = p = state->address_line;
allow_groups = !is_source_routing(p);
while(*p) {
if (*p == ',') {
*p = '\0';
state->address_line = p+1;
return old;
}
else if (*p == ':' && allow_groups) {
old = p+1;
state->group_nest++;
allow_groups = !is_source_routing(p+1);
}
else if (*p == ';') {
/* If we are inside an address group, the ';' character is
interpreted like a comma. */
if (state->group_nest > 0) {
state->group_nest--;
*p = ',';
continue;
}
else
/* do nothing */;
}
else if (*p == '(') {
p = read_until_close_bracket(p+1);
continue;
}
else if (*p == '\\' && p[1] != '\0')
p++;
else if (*p == '"') {
p = read_until_next_quote(p+1);
continue;
}
p++;
}
state->address_line = p;
return old;
}

217
librfc822/decomment.c Normal file
View File

@ -0,0 +1,217 @@
/*
* $Source$
* $Revision$
* $Date$
*
* Copyright (C) 1997 by CyberSolutions GmbH.
* All rights reserved.
*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <assert.h>
#ifdef DEBUG_DMALLOC
# include <dmalloc.h>
#endif
#include "rfc822.h"
static const char *
read_until_next_quote(const char * p)
{
while (*p) {
if (*p == '"') {
break;
}
if (*p == '\\' && p[1] != '\0') {
p += 2;
continue;
}
p++;
}
return p;
}
static const char *
read_until_close_bracket(const char * p)
{
while (*p) {
if (*p == ')') {
break;
}
if (*p == '(') {
p = read_until_close_bracket(p+1);
if (*p == '\0')
break;
else {
p++;
continue;
}
}
else if (*p == '\\' && p[1] != '\0') {
p += 2;
continue;
}
else if (*p == '"') {
p = read_until_next_quote(p+1);
if (*p == '\0')
break;
else {
p++;
continue;
}
}
p++;
}
return p;
}
/* remove all comments from an rfc822 address
This routine takes as argument an address string conforming to the
RFC822 syntax and removes all comments from it, returning the
result in the pointer specified as second argument.
This is very useful if you want to parse the address with a context
free grammer parser, like yacc, because recognizing the various
forms of commenting with a BNF grammar is very complicated.
RETURNS: The routine returns an integer describing whether the
decommenting process succeeded or not. In case of an error, the
return code described the reason for failure.
RFC822_OK: Success.
RFC822_FATAL_ERROR: A fatal system error occured, like malloc()
failed. The global errno variable will be set accordingly.
RFC822_UNCLOSED_COMMENT: A "(comment)"-like expression was not
closed properly.
RFC822_UNMATCHED_CLOSE_BRACKET: A close bracket (")") was
encountered outside the comment context.
RFC822_UNCLOSED_QUOTE: A quoted `"string"'-like expression was not
closed properly.
RFC822_UNCLOSED_ANGEL_BRACKET: An "<address>"-like expression was
not closed properly.
RFC822_NESTED_ANGEL_BRACKET: An open angel bracket ("<") was
encountered inside the "<address>" context.
RFC822_UNMATCHED_CLOSE_ANGEL_BRACKET: A close angel bracket (">") was
encountered outside the "<address>" context.
RFC822_SYNTAX_ERROR: The address does not follow the rfc822 syntax.
NOTE: The returned by rfc822_decomment() has been allocated with
malloc(3) and should be freed when not needed anymore.
AUTHOR: Peter Simons <simons@rhein.de>
*/
int
rfc822_decomment(const char * source /* String containing a formatted rfc822 address. */,
char ** destination /* Location where to store the parsed string. */)
{
char * buffer,
* address_start,
* p;
const char * s;
int in_quote,
angel_bracket_count;
/* Sanity checks. */
assert(source != NULL);
if (!source || *source == '\0') {
errno = EINVAL;
return NULL;
}
/* Allocate buffer. */
buffer = malloc(strlen(source)+1);
if (buffer == NULL) {
errno = ENOMEM;
return RFC822_FATAL_ERROR;
}
/* Let's parse it. */
address_start = p = buffer;
s = source;
in_quote = 0;
angel_bracket_count = 0;
while(*s) {
if (*s == '"') {
in_quote = !in_quote;
}
else if (!in_quote && *s == '(') {
s = read_until_close_bracket(s+1);
if (*s == '\0') {
free(buffer);
return RFC822_UNCLOSED_COMMENT;
}
s++;
*p++ = ' ';
continue;
}
else if (!in_quote && *s == ')') {
free(buffer);
return RFC822_UNMATCHED_CLOSE_BRACKET;
}
else if (!in_quote && *s == '<') {
if (angel_bracket_count > 0) {
free(buffer);
return RFC822_NESTED_ANGEL_BRACKET;
}
s++;
p = address_start;
*p = '\0';
angel_bracket_count++;
continue;
}
else if (!in_quote && *s == '>') {
if (angel_bracket_count == 0) {
free(buffer);
return RFC822_UNMATCHED_CLOSE_ANGEL_BRACKET;
}
*p = '\0';
angel_bracket_count--;
break;
}
else if (!in_quote && *s == '\\') {
if (s[1] != '\0') {
*p++ = *s++;
}
else {
free(buffer);
return RFC822_SYNTAX_ERROR;
}
}
*p++ = *s++;
}
*p = '\0';
if (in_quote) {
free(buffer);
return RFC822_UNCLOSED_QUOTE;
}
if (angel_bracket_count > 0) {
free(buffer);
return RFC822_UNCLOSED_ANGEL_BRACKET;
}
*destination = buffer;
return RFC822_OK;
}

127
librfc822/parse_address.c Normal file
View File

@ -0,0 +1,127 @@
/*
* $Source$
* $Revision$
* $Date$
*
* Copyright (C) 1997 by CyberSolutions GmbH.
* All rights reserved.
*/
#include <stdio.h>
#include <assert.h>
#ifdef DEBUG_DMALLOC
# include <dmalloc.h>
#endif
#include "rfc822.h"
/* parse an rfc822 address
This routine is absolutely magnificent. It understands the full
variety of Internet addresses as specified by RFC822 and parses
them. "Parsing" means that it will check the address to be
syntactically corrent and then returns the two parts an address
consists of: localpart@hostpart. This may not sound like being a
big thing, but you're invited to write a parser yourself to get an
idea. :-)
All kind of comments and delimeters are understood, due to
sophisticated memory pooling hopefully no memory is leaking and the
speed is absolutely untested.
RETURNS: If the parsing process was successful, the local- and
hostpart of the address will be stored in the location specified by
the parameters. It will also store the parsed, canonic address
(without any blanks, comments, etc...) in the provided location. If
the address is syntactically incorrect, or if parsing failed due to
an error, NULL will be stored in all these locations. The hostpart
may also be NULL, if the address is a local address, e.g.
"username".
If either the "address", "localpart" or "hostpart" parameters are
NULL, no result will be stored, what allows you to check an address
for syntax errors.
If the "string" parameter is NULL, the routine will return with a
RFC822_FATAL_ERROR and set the global errno variable to EINVAL.
RFC822_OK: Success.
RFC822_FATAL_ERROR: A fatal system error occured, like malloc()
failed. The global errno variable will be set accordingly.
RFC822_UNCLOSED_COMMENT: A "(comment)"-like expression was not
closed properly.
RFC822_UNMATCHED_CLOSE_BRACKET: A close bracket (")") was
encountered outside the comment context.
RFC822_UNCLOSED_QUOTE: A quoted `"string"'-like expression was not
closed properly.
RFC822_UNCLOSED_ANGEL_BRACKET: An "<address>"-like expression was
not closed properly.
RFC822_NESTED_ANGEL_BRACKET: An open angel bracket ("<") was
encountered inside the "<address>" context.
RFC822_UNMATCHED_CLOSE_ANGEL_BRACKET: A close angel bracket (">") was
encountered outside the "<address>" context.
RFC822_SYNTAX_ERROR: The address does not follow the rfc822 syntax.
NOTE: All buffers returned by the routine are allocated by
malloc(3) and should be freed by the user when they're not needed
anymore.
AUTHOR: Peter Simons <simons@rhein.de>
*/
int
rfc822_parse_address(const char * string /* String containing the address. */,
char ** address /* Where to store the canonic address. */,
char ** localpart /* Where to store the local part. */,
char ** hostpart /* Where to store the host part. */)
{
int rc;
assert(string != NULL);
if (!string) {
errno = EINVAL;
return RFC822_FATAL_ERROR;
}
rc = rfc822_decomment(string, &rfc822_address_buffer);
if (rc != RFC822_OK)
return rc;
else
rfc822_address_buffer_pos = 0;
poolname = rfc822_address_buffer;
no_memory_flag = 0;
result_address = NULL;
result_hostpart = NULL;
result_localpart = NULL;
rc = yyparse();
if (rc == RFC822_OK) {
if (address && (*address = result_address))
mp_remove_block_from_pool(poolname, *address);
if (localpart && (*localpart = result_localpart))
mp_remove_block_from_pool(poolname, *localpart);
if (hostpart && (*hostpart = result_hostpart))
mp_remove_block_from_pool(poolname, *hostpart);
}
else if (no_memory_flag != 0) {
errno = ENOMEM;
rc = RFC822_FATAL_ERROR;
}
else
rc = RFC822_SYNTAX_ERROR;
mp_free_memory_pool(poolname);
free(rfc822_address_buffer);
return rc;
}

35
librfc822/rfc822.h Normal file
View File

@ -0,0 +1,35 @@
/*
* $Source$
* $Revision$
* $Date$
*
* Copyright (C) 1997 by CyberSolutions GmbH.
* All rights reserved.
*/
#ifndef __LIB_RFC822_H__
#define __LIB_RFC822_H__ 1
struct rfc822_address_sep_state {
char * address_line;
unsigned int group_nest;
};
enum {
RFC822_FATAL_ERROR = -1,
RFC822_OK,
RFC822_UNCLOSED_COMMENT,
RFC822_UNMATCHED_CLOSE_BRACKET,
RFC822_UNCLOSED_QUOTE,
RFC822_UNCLOSED_ANGEL_BRACKET,
RFC822_NESTED_ANGEL_BRACKET,
RFC822_UNMATCHED_CLOSE_ANGEL_BRACKET,
RFC822_SYNTAX_ERROR
};
int rfc822_decomment(const char *, char **);
int rfc822_parse_address(const char *, char **, char **, char **);
char * rfc822_address_sep(struct rfc822_address_sep_state *);
#endif /* !__LIB_RFC822_H__ */

55
librfc822/test.c Normal file
View File

@ -0,0 +1,55 @@
/*
* $Source$
* $Revision$
* $Date$
*
* Copyright (C) 1997 by CyberSolutions GmbH.
* All rights reserved.
*/
#include <stdio.h>
#ifdef DEBUG_DMALLOC
# include <dmalloc.h>
#endif
#include "rfc822.h"
#define safe_free(x) if (x) free(x)
int
main(int argc, char ** argv)
{
struct rfc822_address_sep_state sep_state;
char buffer[4096];
char * p,
* address,
* local,
* host;
int rc;
while(gets(buffer)) {
printf("Read line: '%s'\n", buffer);
sep_state.address_line = buffer;
sep_state.group_nest = 0;
while((p = rfc822_address_sep(&sep_state))) {
if (*p == '\0')
continue;
else
printf("One part is: '%s'\n", p);
rc = rfc822_parse_address(p, &address, &local, &host);
if (rc == RFC822_OK) {
printf("Address: '%s'\nLocal: '%s'\nHost: '%s'\n", address, local, host);
safe_free(address);
safe_free(local);
safe_free(host);
}
else
printf("Syntax error: %d\n", rc);
}
printf("\n");
}
return 0;
}

View File

@ -0,0 +1,15 @@
simons
simons@rhein.de
peter.simons@rhein.de
simons (Peter Simons)
peter (peti) . simons
......
peter(simons)...(hallo)@rhein.de (,,,), cd@phoenix."rhein,,(,)".de
@im.net:@gmd.de:simons@rhein.de
group: @rhein.de:simons, group2: @im.net:@rhein.de:simons@petium, cd@phoenix; abcd;
group: @rhein.("hallo<bla>")de:simons, group2: @im.net:@rhein.de:simons@petium <bla>, cd@phoenix; abcd;