diff --git a/apps/dsm/mods/mod_uri/Makefile b/apps/dsm/mods/mod_uri/Makefile new file mode 100644 index 00000000..8b873b5a --- /dev/null +++ b/apps/dsm/mods/mod_uri/Makefile @@ -0,0 +1,18 @@ +plug_in_name = mod_uri + +DSMPATH ?= ../.. + +module_ldflags = +module_cflags = -DMOD_NAME=\"$(plug_in_name)\" -I$(DSMPATH) + +COREPATH ?=$(DSMPATH)/../../core +lib_full_name = $(DSMPATH)/mods/lib/$(lib_name) +include $(COREPATH)/plug-in/Makefile.app_module + +.PHONY: install +install: all $(extra_install) + mkdir -p $(DESTDIR)$(lib-prefix)/$(lib-dir)/dsm + if [ -f "$(lib_name)" ]; then \ + $(INSTALL-TOUCH) $(lib-prefix)/$(lib-dir)/dsm/; \ + $(INSTALL-MODULES) $(lib_name) $(lib-prefix)/$(lib-dir)/dsm/; \ + fi diff --git a/apps/dsm/mods/mod_uri/ModUri.cpp b/apps/dsm/mods/mod_uri/ModUri.cpp new file mode 100644 index 00000000..02860d25 --- /dev/null +++ b/apps/dsm/mods/mod_uri/ModUri.cpp @@ -0,0 +1,132 @@ +/* + * $Id$ + * + * Copyright (C) 2008 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 SEMS 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 "ModUri.h" +#include "log.h" +#include "AmUtils.h" + +#include "DSMSession.h" +#include "AmSession.h" +#include +#include +#include + +#include "DSMCoreModule.h" +#include "UriParser.h" + +SC_EXPORT(URIModule); + +URIModule::URIModule() { +} + +URIModule::~URIModule() { +} + +void splitCmd(const string& from_str, + string& cmd, string& params) { + size_t b_pos = from_str.find('('); + if (b_pos != string::npos) { + cmd = from_str.substr(0, b_pos); + params = from_str.substr(b_pos + 1, from_str.rfind(')') - b_pos -1); + } else + cmd = from_str; +} + +DSMAction* URIModule::getAction(const string& from_str) { + string cmd; + string params; + splitCmd(from_str, cmd, params); + +#define DEF_CMD(cmd_name, class_name) \ + \ + if (cmd == cmd_name) { \ + class_name * a = \ + new class_name(params); \ + a->name = from_str; \ + return a; \ + } + + DEF_CMD("uri.parse", URIParseAction); + DEF_CMD("uri.getHeader", URIGetHeaderAction); + + return NULL; +} + +DSMCondition* URIModule::getCondition(const string& from_str) { + return NULL; +} + +#define GET_SCSESSION() \ + DSMSession* sc_sess = dynamic_cast(sess); \ + if (!sc_sess) { \ + ERROR("wrong session type\n"); \ + return false; \ + } + +CONST_TwoParAction(URIParseAction, ",", true); + +bool URIParseAction::execute(AmSession* sess, + DSMCondition::EventType event, + map* event_params) { + GET_SCSESSION(); + + string uri = resolveVars(par1, sess, sc_sess, event_params); + string prefix = resolveVars(par2, sess, sc_sess, event_params); + + UriParser p; + p.uri = uri; + if (!p.parse_uri()) { + DBG("parsing URI '%s' failed\n", uri.c_str()); + return false; + } + + sc_sess->var[prefix+"display_name"] = p.display_name; + sc_sess->var[prefix+"user"] = p.uri_user; + sc_sess->var[prefix+"host"] = p.uri_host; + sc_sess->var[prefix+"param"] = p.uri_param; + + return false; +} + +void URIModule::onInvite(const AmSipRequest& req, DSMSession* sess) { + sess->var["hdrs"] = req.hdrs; +} + +CONST_TwoParAction(URIGetHeaderAction, ",", false); + +bool URIGetHeaderAction::execute(AmSession* sess, + DSMCondition::EventType event, + map* event_params) { + GET_SCSESSION(); + + string hname = resolveVars(par1, sess, sc_sess, event_params); + string dstname = resolveVars(par2, sess, sc_sess, event_params); + + sc_sess->var[dstname] = getHeader(sc_sess->var["hdrs"], hname); + DBG("got header '%s' value '%s' as $%s\n", + hname.c_str(), sc_sess->var[dstname].c_str(), dstname.c_str()); + return false; +} diff --git a/apps/dsm/mods/mod_uri/ModUri.h b/apps/dsm/mods/mod_uri/ModUri.h new file mode 100644 index 00000000..507ee43b --- /dev/null +++ b/apps/dsm/mods/mod_uri/ModUri.h @@ -0,0 +1,47 @@ +/* + * $Id$ + * + * Copyright (C) 2008 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 SEMS 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 + */ +#ifndef _MOD_SYS_H +#define _MOD_SYS_H +#include "DSMModule.h" + +class URIModule +: public DSMModule { + + public: + URIModule(); + ~URIModule(); + + DSMAction* getAction(const string& from_str); + DSMCondition* getCondition(const string& from_str); + + void onInvite(const AmSipRequest& req, DSMSession* sess); +}; + +DEF_TwoParAction(URIParseAction); +DEF_TwoParAction(URIGetHeaderAction); + +#endif diff --git a/apps/dsm/mods/mod_uri/Readme.mod_uri b/apps/dsm/mods/mod_uri/Readme.mod_uri new file mode 100644 index 00000000..632e702a --- /dev/null +++ b/apps/dsm/mods/mod_uri/Readme.mod_uri @@ -0,0 +1,18 @@ +uri.parse(, ) + splits in + display_name + user + host + param + + example: + uri.parse(@remote_uri, remote_); + uri.parse($PAI, pai_); + +uri.getHeader(
, ) + get header from initial INVITE into variable + + example: + uri.getHeader(P-Asserted-Identity, PAI); + + \ No newline at end of file diff --git a/apps/dsm/mods/mod_uri/UriParser.cpp b/apps/dsm/mods/mod_uri/UriParser.cpp new file mode 100644 index 00000000..7ee542c7 --- /dev/null +++ b/apps/dsm/mods/mod_uri/UriParser.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 "UriParser.h" +#include "log.h" + +// Not on Solaris! +#if !defined (__SVR4) && !defined (__sun) +#include +#endif + +#include +using namespace std; + +bool UriParser::isEqual(const UriParser& 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 Contact\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 UriParser::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 UriParser::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 UriParser::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 UriParser::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/apps/dsm/mods/mod_uri/UriParser.h b/apps/dsm/mods/mod_uri/UriParser.h new file mode 100644 index 00000000..409231fb --- /dev/null +++ b/apps/dsm/mods/mod_uri/UriParser.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 UriParser { + string display_name; + string uri; + + string uri_user; + string uri_host; + string uri_port; + string uri_param; + + map params; + + bool isEqual(const UriParser& 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(); + UriParser() { } +};