From dcdac461e30941d03db7b8af4d641ae308bdda64 Mon Sep 17 00:00:00 2001 From: Stefan Sayer Date: Mon, 8 Dec 2008 17:11:12 +0000 Subject: [PATCH] UriParser -> AmUriParser as core utility git-svn-id: http://svn.berlios.de/svnroot/repos/sems/trunk@1171 8eb893ce-cfd4-0310-b710-fb5ebe64c474 --- core/AmUriParser.cpp | 384 +++++++++++++++++++++++++++++++++++++++++++ core/AmUriParser.h | 50 ++++++ 2 files changed, 434 insertions(+) create mode 100644 core/AmUriParser.cpp create mode 100644 core/AmUriParser.h diff --git a/core/AmUriParser.cpp b/core/AmUriParser.cpp new file mode 100644 index 00000000..08b1a043 --- /dev/null +++ b/core/AmUriParser.cpp @@ -0,0 +1,384 @@ +/* + * $Id$ + * + * Copyright (C) 2006 iptego GmbH + * + * This file is part of sems, a free SIP media server. + * + * sems is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * For a license to use the ser software under conditions + * other than those described here, or to purchase support for this + * software, please contact iptel.org by e-mail at the following addresses: + * info@iptel.org + * + * sems is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "AmUriParser.h" +#include "log.h" + +// Not on Solaris! +#if !defined (__SVR4) && !defined (__sun) +#include +#endif + +#include +using namespace std; + +bool AmUriParser::isEqual(const AmUriParser& c) const { + return (uri_user == c.uri_user) && + (!strcasecmp(uri_host.c_str(), + c.uri_host.c_str())) && + (uri_port == c.uri_port); +} + +/* + * Skip display name part + */ +static inline int skip_name(string& s, unsigned int pos) +{ + size_t i; + int last_wsp, quoted = 0; + + for(i = pos; i < s.length(); i++) { + char c = s[i]; + if (!quoted) { + if ((c == ' ') || (c == '\t')) { + last_wsp = i; + } else { + if (c == '<') { + return i; + } + + if (c == '\"') { + quoted = 1; + } + } + } else { + if ((c == '\"') && (s[i-1] != '\\')) quoted = 0; + } + } + + if (quoted) { + ERROR("skip_name(): Closing quote missing in name part of URI\n"); + return -1; + } + + return pos; // no name to skip +} + +#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(string& s, unsigned int pos) +{ + unsigned int len = s.length() - pos; + unsigned int p = pos; + + register int st = ST1; + + while(len) { + switch(s[p]) { + case ',': + case ';': + if (st == ST1) return p; + 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: + DBG("ERROR skip_uri(): Second < found\n"); + return -1; + case ST5: st = ST2; break; + case ST6: st = ST4; break; + } + break; + + case '>': + switch(st) { + case ST1: + DBG("ERROR 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; + + } + + p++; + len--; + } + + if (st != ST1) { + DBG("ERROR skip_uri(): < or \" not closed\n"); + return -3; + } + return p; +} + +#define uS0 0 // start +#define uS1 1 // protocol +#define uS2 2 // user / host +#define uS3 3 // host +#define uS3WSP 4 // wsp after host +#define uS4 5 // port +#define uS4WSP 6 // wsp after port +#define uS5 7 // params +#define uS5WSP 8 // wsp after params +#define uS6 9 // end +/** + * parse uri into user, host, port, param + * + */ +bool AmUriParser::parse_uri() { + // assuming user@host + size_t pos = 0; int st = uS0; + size_t p1 = 0; + int eq = 0; const char* sip_prot = "SIP:"; + uri_user = ""; uri_host = ""; uri_port = ""; uri_param = ""; + + if (uri.empty()) + return false; + + while (pos': { + uri_host = uri.substr(p1+1, pos-p1-1); + st = uS6; p1 = pos; + }; break; + } + } break; + case uS3: { + switch (c) { + case ':': { uri_host = uri.substr(p1+1, pos-p1-1); + st = uS4; p1 = pos; } + break; + case ';': { uri_host = uri.substr(p1+1, pos-p1-1); + st = uS5; p1 = pos; } + break; + case '>': { uri_host = uri.substr(p1+1, pos-p1-1); + st = uS6; p1 = pos; } + break; + case ' ': + case '\t': { uri_host = uri.substr(p1+1, pos-p1-1); + st = uS3WSP; p1 = pos; } + break; + }; + } break; + case uS3WSP: { + switch (c) { + case ':': { st = uS4; p1 = pos; } + break; + case ';': { st = uS5; p1 = pos; } + break; + case '>': { st = uS6; p1 = pos; } + } + case uS4: { + switch (c) { + case ';': { uri_port = uri.substr(p1+1, pos-p1-1); + st = uS5; p1 = pos; } + break; + case '>': { uri_port = uri.substr(p1+1, pos-p1-1); + st = uS6; p1 = pos; } + break; + }; + case ' ': + case '\t': + { uri_port = uri.substr(p1+1, pos-p1-1); + st = uS4WSP; p1 = pos; } + break; + }; + } break; + case uS4WSP: { + switch (c) { + case ';': { st = uS5; p1 = pos; } + break; + case '>': { st = uS6; p1 = pos; } + break; + }; + } break; + case uS5: { + switch (c) { + case '>': { uri_param = uri.substr(p1+1, pos-p1-1); + st = uS6; p1 = pos; } + break; + case ' ': { uri_param = uri.substr(p1+1, pos-p1-1); + st = uS5WSP; p1 = pos; } + break; }; + } break; + case uS5WSP: { + switch (c) { + case '>': { st = uS6; p1 = pos; } + break; + }; + } break; + }; + // DBG("(2) c = %c, st = %d\n", c, st); + pos++; + } + switch(st) { + case uS2: + case uS3: uri_host = uri.substr(p1+1, pos-p1-1); break; + case uS4: uri_port = uri.substr(p1+1, pos-p1-1); break; + case uS5: uri_param = uri.substr(p1+1, pos-p1-1); break; + case uS0: + case uS1: { DBG("ERROR while parsing uri\n"); return false; } break; + }; + return true; +} + +#define pS0 0 // start +#define pS1 1 // name +#define pS2 2 // val +/** + * parse params int param map + * + */ +bool AmUriParser::parse_params(string& line, int& pos) { + size_t p1=pos, p2=pos; + int st = 0; int quoted = false; + char last_c = ' '; + bool hit_comma = false; + params.clear(); + while((size_t)pos < line.length()) { + char c = line[pos]; + if (!quoted) { + if (c == ',') { + hit_comma = true; + break; + } + if (c == '\"') { + quoted = 1; + } else if (c == '=') { + p2 = pos; st = pS2; + } else if (c == ';') { + if ((st == pS2) ||(st == pS1)) { + params[line.substr(p1, p2-p1)] + = line.substr(p2+1, pos-p2-1); + st = pS0; + } + } else { + if (st == pS0) { + st = pS1; + p1 = pos; + } + } + + } else { + if ((c == '\"') && (last_c != '\\')) quoted = 0; + } + last_c = c; + pos++; + } + + if (st == pS2) { + if (hit_comma) + params[line.substr(p1, p2-p1)] = line.substr(p2+1, pos-p2 -1); + else + params[line.substr(p1, p2-p1)] = line.substr(p2+1, pos-p2); + } + return true; +} + + +bool AmUriParser::parse_contact(string& line, size_t pos, size_t& end) { + int p0 = skip_name(line, pos); + if (p0 < 0) { return false; } + int p1 = skip_uri(line, p0); + if (p1 < 0) { return false; } + // if (p1 < 0) return false; + uri = line.substr(p0, p1-p0); + if (!parse_uri()) { return false; } + parse_params(line, p1); + end = p1; + return true; +} + +void AmUriParser::dump() { + DBG("--- Uri Info --- \n"); + DBG(" uri '%s'\n", uri.c_str()); + DBG(" uri_user '%s'\n", uri_user.c_str()); + DBG(" uri_host '%s'\n", uri_host.c_str()); + DBG(" uri_port '%s'\n", uri_port.c_str()); + DBG(" uri_param '%s'\n", uri_param.c_str()); + for (map::iterator it = params.begin(); + it != params.end(); it++) + DBG(" param '%s'='%s'\n", it->first.c_str(), it->second.c_str()) ; + DBG("-------------------- \n"); +} diff --git a/core/AmUriParser.h b/core/AmUriParser.h new file mode 100644 index 00000000..7d0e33b0 --- /dev/null +++ b/core/AmUriParser.h @@ -0,0 +1,50 @@ +/* + * $Id$ + * + * Copyright (C) 2006 iptego GmbH + * + * This file is part of sems, a free SIP media server. + * + * sems is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * For a license to use the ser software under conditions + * other than those described here, or to purchase support for this + * software, please contact iptel.org by e-mail at the following addresses: + * info@iptel.org + * + * sems is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +using std::map; +using std::string; + +struct AmUriParser { + string display_name; + string uri; + + string uri_user; + string uri_host; + string uri_port; + string uri_param; + + map params; + + bool isEqual(const AmUriParser& c) const; + bool parse_contact(string& line, size_t pos, size_t& end); + bool parse_uri(); + bool parse_params(string& line, int& pos); + void dump(); + AmUriParser() { } +};