浏览代码

Contact parser

Jan Janak 23 年之前
父节点
当前提交
0489d6a280
共有 6 个文件被更改,包括 789 次插入0 次删除
  1. 213 0
      parser/contact/contact.c
  2. 47 0
      parser/contact/contact.h
  3. 342 0
      parser/contact/cparam.c
  4. 52 0
      parser/contact/cparam.h
  5. 96 0
      parser/contact/parse_contact.c
  6. 39 0
      parser/contact/parse_contact.h

+ 213 - 0
parser/contact/contact.c

@@ -0,0 +1,213 @@
+/*
+ * $Id$
+ *
+ * Parses one Contact in Contact HF body
+ */
+
+#include "contact.h"
+#include "../../mem/mem.h" /* pkg_malloc, pkg_free */
+#include "../../dprint.h"
+#include <string.h>        /* memset */
+#include "../../trim.h"    /* trim_leading, trim_trailing */
+#include <stdio.h>         /* printf */
+
+
+#define ST1 1 /* Basic state */
+#define ST2 2 /* Quoted */
+#define ST3 3 /* Angle quoted */
+#define ST4 4 /* Angle quoted and quoted */
+#define ST5 5 /* Escape in quoted */
+#define ST6 6 /* Escape in angle quoted and quoted */
+
+
+/*
+ * Skip URI, stops when , (next contact)
+ * or ; (parameter) is found
+ */
+static inline int skip_uri(str* _s)
+{
+	register int st = ST1;
+
+	while(_s->len) {
+		switch(*(_s->s)) {
+		case ',':
+		case ';':
+			if (st == ST1) return 0;
+			break;
+
+		case '\"':
+			switch(st) {
+			case ST1: st = ST2; break;
+			case ST2: st = ST1; break;
+			case ST3: st = ST4; break;
+			case ST4: st = ST3; break;
+			case ST5: st = ST2; break;
+			case ST6: st = ST4; break;
+			}
+			break;
+
+		case '<':
+			switch(st) {
+			case ST1: st = ST3; break;
+			case ST3: 
+				LOG(L_ERR, "skip_uri(): Second < found\n");
+				return -1;
+			case ST5: st = ST2; break;
+			case ST6: st = ST4; break;
+			}
+			break;
+			
+		case '>':
+			switch(st) {
+			case ST1: 
+				LOG(L_ERR, "skip_uri(): > is first\n");
+				return -2;
+
+			case ST3: st = ST1; break;
+			case ST5: st = ST2; break;
+			case ST6: st = ST4; break;
+			}
+			break;
+
+		case '\\':
+			switch(st) {
+			case ST2: st = ST5; break;
+			case ST4: st = ST6; break;
+			case ST5: st = ST2; break;
+			case ST6: st = ST4; break;
+			}
+			break;
+
+		default: break;
+
+		}
+
+		_s->s++;
+		_s->len--;
+	}
+
+	if (st != ST1) {
+		LOG(L_ERR, "skip_uri(): < or \" not closed\n");
+		return -3;
+	}
+
+	return 0;
+}
+
+
+
+/*
+ * Parse contacts in a Contact HF
+ */
+int parse_contacts(str* _s, contact_t** _c)
+{
+	contact_t* c;
+
+	while(1) {
+		     /* Allocate and clear contact stucture */
+		c = (contact_t*)pkg_malloc(sizeof(contact_t));
+		if (c == 0) {
+			LOG(L_ERR, "parse_contacts(): No memory left\n");
+			goto error;
+		}
+		memset(c, 0, sizeof(contact_t));
+		
+		     /* Save beginning of URI */
+		c->uri.s = _s->s;
+		
+		     /* Find the end of the URI */
+		if (skip_uri(_s) < 0) {
+			LOG(L_ERR, "parse_contacts(): Error while skipping URI\n");
+			goto error;
+		}
+		
+		c->uri.len = _s->s - c->uri.s; /* Calculate URI length */
+		trim_trailing(&(c->uri));      /* Remove any trailing spaces from URI */
+
+		if (_s->len == 0) goto ok;
+		
+		if (_s->s[0] == ';') {         /* Contact parameter found */
+			_s->s++;
+			_s->len--;
+			trim_leading(_s);
+			
+			if (_s->len == 0) {
+				LOG(L_ERR, "parse_contacts(): Error while parsing params\n");
+				goto error;
+			}
+
+			if (parse_cparams(_s, &(c->params), &(c->q), &(c->expires), &(c->method)) < 0) {
+				LOG(L_ERR, "parse_contacts(): Error while parsing params\n");
+				goto error;
+			}
+
+			if (_s->len == 0) goto ok;
+		}
+
+		     /* Next character is comma */
+		_s->s++;
+		_s->len--;
+		trim_leading(_s);
+
+		if (_s->len == 0) {
+			LOG(L_ERR, "parse_contacts(): Text after comma missing\n");
+			goto error;
+		}
+
+		c->next = *_c;
+		*_c = c;
+	}
+
+ error:
+	if (c) pkg_free(c);
+	free_contacts(_c); /* Free any contacts created so far */
+	return -1;
+
+ ok:
+	c->next = *_c;
+	*_c = c;
+	return 0;
+}
+
+
+/*
+ * Free list of contacts
+ * _c is head of the list
+ */
+void free_contacts(contact_t** _c)
+{
+	contact_t* ptr;
+
+	while(*_c) {
+		ptr = *_c;
+		*_c = (*_c)->next;
+		if (ptr->params) {
+			free_cparams(&(ptr->params));
+		}
+		pkg_free(ptr);
+	}
+}
+
+
+/*
+ * Print list of contacts, just for debugging
+ */
+void print_contacts(contact_t* _c)
+{
+	contact_t* ptr;
+
+	ptr = _c;
+
+	while(ptr) {
+		printf("---Contact---\n");
+		printf("URI    : \'%.*s\'\n", ptr->uri.len, ptr->uri.s);
+		printf("q      : %p\n", ptr->q);
+		printf("expires: %p\n", ptr->expires);
+		printf("method : %p\n", ptr->method);
+		if (ptr->params) {
+			print_cparams(ptr->params);
+		}
+		printf("---/Contact---\n");
+		ptr = ptr->next;
+	}
+}

+ 47 - 0
parser/contact/contact.h

@@ -0,0 +1,47 @@
+/*
+ * $Id$
+ *
+ * Contact datatype
+ */
+
+#ifndef CONTACT_H
+#define CONTACT_H
+
+
+#include "cparam.h"    /* cparam_t */
+#include "../../str.h"
+
+
+/*
+ * Structure representing a Contac HF body
+ */
+typedef struct contact {
+	str uri;                /* contact uri */
+	cparam_t* q;            /* q parameter hook */
+	cparam_t* expires;      /* expires parameter hook */
+	cparam_t* method;       /* method parameter hook */
+	cparam_t* params;       /* List of all parameters */
+        struct contact* next; /* Next contact in the list */
+} contact_t;
+
+
+/*
+ * Parse contacts in a Contact HF
+ */
+int parse_contacts(str* _s, contact_t** _c);
+
+
+/*
+ * Free list of contacts
+ * _c is head of the list
+ */
+void free_contacts(contact_t** _c);
+
+
+/*
+ * Print list of contacts, just for debugging
+ */
+void print_contacts(contact_t* _c);
+
+
+#endif /* CONTACT_H */

+ 342 - 0
parser/contact/cparam.c

@@ -0,0 +1,342 @@
+#include "cparam.h"
+#include "../../mem/mem.h"
+#include <stdio.h>         /* printf */
+#include "../../ut.h"      /* q_memchr */
+#include <string.h>        /* memset */
+#include "../../trim.h"
+
+
+/*
+ * Parse quoted string in a parameter body
+ * return the string without quotes in _r
+ * parameter and update _s to point behind the
+ * closing quote
+ */
+static inline int parse_quoted(str* _s, str* _r)
+{
+	char* end_quote;
+
+	     /* The string must have at least
+	      * surrounding quotes
+	      */
+	if (_s->len < 2) {
+		return -1;
+	}
+
+	     /* Skip opening quote */
+	_s->s++;
+	_s->len--;
+
+
+	     /* Find closing quote */
+	end_quote = q_memchr(_s->s, '\"', _s->len);
+
+	     /* Not found, return error */
+	if (!end_quote) {
+		return -2;
+	}
+
+	     /* Let _r point to the string without
+	      * surrounding quotes
+	      */
+	_r->s = _s->s;
+	_r->len = end_quote - _s->s;
+
+	     /* Update _s parameter to point
+	      * behind the closing quote
+	      */
+	_s->len -= (end_quote - _s->s + 1);
+	_s->s = end_quote + 1;
+
+	     /* Everything went OK */
+	return 0;
+}
+
+
+/*
+ * Parse unquoted token in a parameter body
+ * let _r point to the token and update _s
+ * to point right behind the token
+ */
+static inline int parse_token(str* _s, str* _r)
+{
+	int i;
+
+	     /* There is nothing to parse,
+	      * return error
+	      */
+	if (_s->len == 0) {
+		return -1;
+	}
+
+	     /* Save the begining of the
+	      * token in _r->s
+	      */
+	_r->s = _s->s;
+
+	     /* Iterate throught the
+	      * token body
+	      */
+	for(i = 0; i < _s->len; i++) {
+
+		     /* All these characters
+		      * mark end of the token
+		      */
+		switch(_s->s[i]) {
+		case ' ':
+		case '\t':
+		case '\r':
+		case '\n':
+		case ',':
+		case ';':
+			     /* So if you find
+			      * any of them
+			      * stop iterating
+			      */
+			goto out;
+		}
+	}
+ out:
+	if (i == 0) {
+		return -1;
+        }
+
+	     /* Save length of the token */
+        _r->len = i;
+
+	     /* Update _s parameter so it points
+	      * right behind the end of the token
+	      */
+	_s->s = _s->s + i;
+	_s->len -= i;
+
+	     /* Everything went OK */
+	return 0;
+}
+
+
+/*
+ * Parse type of a parameter
+ */
+static inline int parse_param_type(cparam_t* _c)
+{
+	switch(_c->name.s[0]) {
+	case 'q':
+	case 'Q':
+		if (_c->name.len == 1) {
+			_c->type = CP_Q;
+		}
+		return 0;
+		
+	case 'e':
+	case 'E':
+		if ((_c->name.len == 7) &&
+		    (!strncasecmp(_c->name.s + 1, "xpires", 6))) {
+			_c->type = CP_EXPIRES;
+		}
+		return 0;
+		
+	case 'm':
+	case 'M':
+		if ((_c->name.len == 6) &&
+		    (!strncasecmp(_c->name.s + 1, "ethod", 5))) {
+			_c->type = CP_METHOD;
+		}
+		return 0;
+	}
+	return 0;
+}
+
+
+/*
+ * Parse body of a parameter. It can be quoted string or
+ * a single token.
+ */
+static inline int parse_body(str* _s, cparam_t* _c)
+{
+	if (_s->s[0] == '\"') {
+		if (parse_quoted(_s, &(_c->body)) < 0) {
+			LOG(L_ERR, "parse_body(): Error while parsing quoted string\n");
+			return -2;
+		}
+	} else {
+		if (parse_token(_s, &(_c->body)) < 0) {
+			LOG(L_ERR, "parse_body(): Error while parsing token\n");
+			return -3;
+		}
+	}
+
+	return 0;
+}
+
+
+/*
+ * Parse a parameter name
+ */
+static inline int parse_param_name(str* _s, cparam_t* _p)
+{
+	_p->name.s = _s->s;
+
+	while(_s->len) {
+		switch(_s->s[0]) {
+		case ' ':
+		case '\t':
+		case '\r':
+		case '\n':
+		case ';':
+		case ',':
+		case '=':
+			goto out;
+		}
+		_s->s++;
+		_s->len--;
+	}
+
+ out:
+	_p->name.len = _s->s - _p->name.s;
+	
+	if (parse_param_type(_p) < 0) {
+		LOG(L_ERR, "parse_param_name(): Error while parsing type\n");
+		return -2;
+	}
+	
+	return 0;
+}
+
+
+/*
+ * Parse contact parameters
+ */
+int parse_cparams(str* _s, cparam_t** _p, cparam_t** _q, cparam_t** _e, cparam_t** _m)
+{
+	cparam_t* c;
+
+	while(1) {
+		c = (cparam_t*)pkg_malloc(sizeof(cparam_t));
+		if (c == 0) {
+			LOG(L_ERR, "parse_cparams(): No memory left\n");
+			goto error;
+		}
+		memset(c, 0, sizeof(cparam_t));
+
+		if (parse_param_name(_s, c) < 0) {
+			LOG(L_ERR, "parse_cparams(): Error while parsing param name\n");
+			goto error;
+		}
+
+		trim_leading(_s);
+		
+		if (_s->len == 0) { /* The last parameter without body */
+			goto ok;
+		}
+		
+		if (_s->s[0] == '=') {
+			_s->s++;
+			_s->len--;
+			trim_leading(_s);
+
+			if (_s->len == 0) {
+				LOG(L_ERR, "parse_cparams(): Body missing\n");
+				goto error;
+			}
+
+			if (parse_body(_s, c) < 0) {
+				LOG(L_ERR, "parse_cparams(): Error while parsing param body\n");
+				goto error;
+			}
+
+			trim_leading(_s);
+			if (_s->len == 0) {
+				goto ok;
+			}
+		}
+
+		if (_s->s[0] == ',') goto ok;
+
+		if (_s->s[0] != ';') {
+			LOG(L_ERR, "parse_cparams(): Invalid character, ; expected\n");
+			goto error;
+		}
+
+		_s->s++;
+		_s->len--;
+		trim_leading(_s);
+		
+		if (_s->len == 0) {
+			LOG(L_ERR, "parse_cparams(): Param name missing after ;\n");
+			goto error;
+		}
+
+		c->next = *_p;
+		*_p = c;
+		switch(c->type) {    /* Update hook pointers */
+		case CP_Q:       *_q = c; break;
+		case CP_EXPIRES: *_e = c; break;
+		case CP_METHOD:  *_m = c; break;
+		case CP_OTHER:            break;
+		}		
+	}
+
+ error:
+	if (c) pkg_free(c);
+	free_cparams(_p);
+	return -1;
+
+ ok:
+	c->next = *_p;
+	*_p = c;
+	switch(c->type) {    /* Update hook pointers */
+	case CP_Q:       *_q = c; break;
+	case CP_EXPIRES: *_e = c; break;
+	case CP_METHOD:  *_m = c; break;
+	case CP_OTHER:          ; break;
+	}
+	return 0;
+}
+
+
+/*
+ * Free the whole contact parameter list
+ */
+void free_cparams(cparam_t** _p)
+{
+	cparam_t* ptr;
+
+	while(*_p) {
+		ptr = *_p;
+		pkg_free(ptr);
+		*_p = (*_p)->next;
+	}
+}
+
+
+/*
+ * Print contact parameter list
+ */
+void print_cparams(cparam_t* _p)
+{
+	cparam_t* ptr;
+	char* type;
+
+	ptr = _p;
+
+	while(ptr) {
+		printf("...cparam(%p)...\n", ptr);
+
+		switch(ptr->type) {
+		case CP_OTHER:   type = "CP_OTHER";   break;
+		case CP_Q:       type = "CP_Q";       break;
+		case CP_EXPIRES: type = "CP_EXPIRES"; break;
+		case CP_METHOD:  type = "CP_METHOD";  break;
+		default:         type = "UNKNOWN";    break;
+		}
+
+		printf("type: %s\n", type);
+		printf("name: \'%.*s\'\n", ptr->name.len, ptr->name.s);
+		printf("body: \'%.*s\'\n", ptr->body.len, ptr->body.s);
+
+		printf(".../cparam...\n");
+
+		ptr = ptr->next;
+	}
+}

+ 52 - 0
parser/contact/cparam.h

@@ -0,0 +1,52 @@
+/*
+ * $Id$
+ *
+ * Contact parameter datatype
+ */
+
+#ifndef CPARAM_H
+#define CPARAM_H
+
+#include "../../str.h"
+
+/*
+ * Supported types of contact parameters
+ */
+typedef enum cptype {
+	CP_OTHER = 0,  /* Unknown parameter */
+	CP_Q,          /* Q parameter */
+	CP_EXPIRES,    /* Expires parameter */
+	CP_METHOD      /* Method parameter */
+} cptype_t;
+
+
+/*
+ * Structure representing a contact
+ */
+typedef struct cparam {
+	cptype_t type;       /* Type of the parameter */
+	str name;            /* Parameter name */
+	str body;            /* Parameter body */
+	struct cparam* next; /* Next parameter in the list */
+} cparam_t;
+
+
+/*
+ * Parse contact parameters
+ */
+int parse_cparams(str* _s, cparam_t** _p, cparam_t** _q, cparam_t** _e, cparam_t** _m);
+
+
+/*
+ * Free the whole contact parameter list
+ */
+void free_cparams(cparam_t** _p);
+
+
+/*
+ * Print contact parameter list
+ */
+void print_cparams(cparam_t* _p);
+
+
+#endif /* CPARAM_H */

+ 96 - 0
parser/contact/parse_contact.c

@@ -0,0 +1,96 @@
+/*
+ * $Id$
+ *
+ * Contact header field body parser
+ */
+
+#include "parse_contact.h"
+#include "../hf.h"     
+#include "../../mem/mem.h"   /* pkg_malloc, pkg_free */
+#include "../../dprint.h"
+#include <stdio.h>           /* printf */
+#include "../../trim.h"      /* trim_leading */
+#include <string.h>          /* memset */
+
+
+static inline int contact_parser(char* _s, int _l, contact_body_t* _c)
+{
+	str tmp;
+
+	tmp.s = _s;
+	tmp.len = _l;
+
+	trim_leading(&tmp);
+
+	if (tmp.len == 0) {
+		LOG(L_ERR, "contact_parser(): Empty body\n");
+		return -1;
+	}
+
+	if (tmp.s[0] == '*') {
+		_c->star = 1;
+	} else {
+		if (parse_contacts(&tmp, &(_c->contacts)) < 0) {
+			LOG(L_ERR, "contact_parser(): Error while parsing contacts\n");
+			return -2;
+		}
+	}
+
+	return 0;
+}
+
+
+/*
+ * Parse contact header field body
+ */
+int parse_contact(struct hdr_field* _h)
+{
+	contact_body_t* b;
+
+	if (_h->parsed != 0) {
+		return 0;  /* Already parsed */
+	}
+
+	b = (contact_body_t*)pkg_malloc(sizeof(contact_body_t));
+	if (b == 0) {
+		LOG(L_ERR, "parse_contact(): No memory left\n");
+		return -1;
+	}
+
+	memset(b, 0, sizeof(contact_body_t));
+
+	if (contact_parser(_h->body.s, _h->body.len, b) < 0) {
+		LOG(L_ERR, "parse_contact(): Error while parsing\n");
+		pkg_free(b);
+		return -2;
+	}
+
+	_h->parsed = (void*)b;
+	return 0;
+}
+
+
+/*
+ * Free all memory
+ */
+void free_contact(contact_body_t** _c)
+{
+	if ((*_c)->contacts) {
+		free_contacts(&((*_c)->contacts));
+	}
+	
+	pkg_free(*_c);
+	*_c = 0;
+}
+
+
+/*
+ * Print structure, for debugging only
+ */
+void print_contact(contact_body_t* _c)
+{
+	printf("===Contact body===\n");
+	printf("star: %d\n", _c->star);
+	print_contacts(_c->contacts);
+	printf("===/Contact body===\n");
+}

+ 39 - 0
parser/contact/parse_contact.h

@@ -0,0 +1,39 @@
+/*
+ * $Id$
+ *
+ * Contact header field body parser
+ */
+
+#ifndef PARSE_CONTACT_H
+#define PARSE_CONTACT_H
+
+#include "../hf.h"
+#include "../../str.h"
+#include "contact.h"
+
+
+typedef struct contact_body {
+	unsigned char star;    /* Star contact */
+	contact_t* contacts;   /* List of contacts */
+} contact_body_t;
+
+
+/*
+ * Parse contact header field body
+ */
+int parse_contact(struct hdr_field* _h);
+
+
+/*
+ * Free all memory
+ */
+void free_contact(contact_body_t** _c);
+
+
+/*
+ * Print structure, for debugging only
+ */
+void print_contact(contact_body_t* _c);
+
+
+#endif /* PARSE_CONTACT_H */