Commit 432c4569 authored by urbant's avatar urbant
Browse files

Tel scheme support

parent 31e21029
Loading
Loading
Loading
Loading
+71 −21
Original line number Diff line number Diff line
@@ -102,19 +102,28 @@ void remove_whitespace (Buffer & buffer) {
}

void read_sp (Buffer & buffer, Variable* v) {
	static Regex reg_ws ("[ \t]+");
	static Regex reg_ws ("^[ \t]+");
	reg_ws.AssertMatch (buffer, v);
	int nPos = buffer.GetPosition() + reg_ws.GetMatchedLength();
	buffer.SetPosition (nPos);
}

bool is_sip_scheme (const char * pszScheme) {
	return strcasecmp(pszScheme, "sip") == 0 || strcasecmp(pszScheme, "sips") == 0;
}

bool is_tel_scheme (const char * pszScheme) {
	return strcasecmp(pszScheme, "tel") == 0 || strcasecmp(pszScheme, "fax") == 0 ||
		strcasecmp(pszScheme, "modem") == 0;
}

//whitespace


#define SIPCHARS_MARK		"\\-_.!~*'()"
#define SIPCHARS_ALFA		"A-Za-z"
#define SIPCHARS_ALFANUM	"0-9" SIPCHARS_ALFA
#define SIPCHARS_HEXA	"0-9A-F"
#define SIPCHARS_HEXA	"0-9A-Fa-f"
#define SIPCHARS_UNRESERVED	SIPCHARS_ALFANUM SIPCHARS_MARK
#define SIPCHARS_RESERVED	";/?:@&=+$,"
#define SIPCHARS_USER_UNRESERVED "&=+$,;?/"
@@ -122,8 +131,6 @@ void read_sp (Buffer & buffer, Variable* v) {
#define SIPREG_ESCAPED	"(%[0-9A-Fa-f]{2})"
#define SIPREG_TOKEN "[" SIPCHARS_ALFANUM ".!%*_+`'~\\-]+"



// sip version
#define SIPREG_SIP_VERSION "SIP/[0-9]\\.[0-9]"

@@ -151,6 +158,9 @@ void read_sp (Buffer & buffer, Variable* v) {
#define SIPREG_HOST		"((" SIPREG_HOSTNAME ")|(" SIPREG_IP4 ")|(" SIPREG_IP6 "))"
#define SIPREG_ABSOLUTE_URI	"([" SIPCHARS_UNRESERVED "/;?:@&=+$,]|" SIPREG_ESCAPED ")+"

// phone number (global or local)
#define SIPREG_PHONE_NUMBER "(([+][\\-0-9.()]+)|[\\-0-9()*#A-Da-dPpWw]+)"

#define SIPCHARS_PPARAM_UNRESERVED "][/:&+$"
#define SIPREG_PPARAM		"([" SIPCHARS_PPARAM_UNRESERVED SIPCHARS_UNRESERVED "]|" SIPREG_ESCAPED ")"
#define SIPREG_PPARAM_ALLOWED	"[" SIPCHARS_PPARAM_UNRESERVED SIPCHARS_UNRESERVED ";=%]+"
@@ -159,15 +169,22 @@ void read_sp (Buffer & buffer, Variable* v) {
#define SIPREG_HPARAM		"([" SIPCHARS_HPARAM_UNRESERVED SIPCHARS_UNRESERVED "]|" SIPREG_ESCAPED ")"
#define SIPREG_HPARAM_ALLOWED	"[" SIPCHARS_HPARAM_UNRESERVED SIPCHARS_UNRESERVED ";=%]+"

#define SIPREG_TELPARAM_NAME	"[!#$%&'*+\\-.0-9A-Z^_`a-z|~]+"
#define SIPREG_TELPARAM_VALUE	"([\\x21\\x23-\\x3A\\x3C-\\x7E]+|(" SIPREG_QUOTED_STRING "))"
#define SIPREG_TELPARAMS		"([;]" SIPREG_TELPARAM_NAME "([=]" SIPREG_TELPARAM_VALUE ")?)+"

void SipUrl::PreDecodeField (int id, Buffer& buffer) throw (DecodeError)
{

	static Regex reg_scheme ("^[" SIPCHARS_ALFA "][" SIPCHARS_ALFANUM "+.\\-]*:");
	static Regex reg_scheme ("^[" SIPCHARS_ALFA "][" SIPCHARS_ALFANUM "+.\\-]*");
	static Regex reg_colon ("^[:]");
	static Regex reg_userinfo ("^([:" SIPCHARS_UNRESERVED SIPCHARS_USER_UNRESERVED "]|" SIPREG_ESCAPED "])+@");
	static Regex reg_phone ("^" SIPREG_PHONE_NUMBER);
	static Regex reg_hostport ("^[][" SIPCHARS_ALFANUM ":.\\-]+");
	static Regex reg_absolute_uri ("^" SIPREG_ABSOLUTE_URI);
	static Regex reg_urlParams ("^;" SIPREG_PPARAM_ALLOWED);	
	static Regex reg_headers ("^[?]" SIPREG_PPARAM_ALLOWED);
	static Regex reg_telParams ("^" SIPREG_TELPARAMS);

	const char * pszScheme;
	switch (id) {
@@ -177,23 +194,32 @@ void SipUrl::PreDecodeField (int id, Buffer& buffer) throw (DecodeError)
		break;

	case id_userInfo:
		reg_colon.AssertMatch(buffer, this);
		buffer.SetPosition(buffer.GetPosition() + 8);
		pszScheme = Get_scheme().GetValue();
		// user-info is not decoded in case of absoluteURI
		if ((strcasecmp(pszScheme, "sip:") == 0 || strcasecmp(pszScheme, "sips:") == 0) &&
			reg_userinfo.Match (buffer)) {
		if (is_sip_scheme(pszScheme) &&	reg_userinfo.Match (buffer)) {
			SetHypFieldIsPresent (id,  1);
			SetHypFieldLength (id, reg_userinfo.GetMatchedLength() - 8);
		} else {
		} 
		// telephone numbers are decoded to the userInfo field
		else if (is_tel_scheme(pszScheme)){
			reg_phone.AssertMatch(buffer, this);
			SetHypFieldIsPresent (id,  1);
			SetHypFieldLength (id, reg_phone.GetMatchedLength());
		}
		else {
			SetHypFieldIsPresent (id,  0);
		}
		break;

	case id_hostPort:
		pszScheme = Get_scheme().GetValue();
		if (is_sip_scheme(pszScheme)) {
			// remove '@'
			if (IsPresent (id_userInfo)) {
				buffer.SetPosition(buffer.GetPosition() + 8);
			}
		pszScheme = Get_scheme().GetValue();
		if ((strcasecmp(pszScheme, "sip:") == 0 || strcasecmp(pszScheme, "sips:") == 0)) {
			if (reg_hostport.Match (buffer)) {
				SetHypFieldIsPresent (id,  1);
				SetHypFieldLength(id, reg_hostport.GetMatchedLength());
@@ -202,6 +228,8 @@ void SipUrl::PreDecodeField (int id, Buffer& buffer) throw (DecodeError)
			} else {
				SetHypFieldIsPresent (id,  0);
			}
		} else if (is_tel_scheme(pszScheme)) {
			SetHypFieldIsPresent(id, 0);
		} else { // absoluteURI
			if (reg_absolute_uri.Match (buffer)) {
				SetHypFieldIsPresent (id,  1);
@@ -214,18 +242,25 @@ void SipUrl::PreDecodeField (int id, Buffer& buffer) throw (DecodeError)

	case id_urlParameters:
		pszScheme = Get_scheme().GetValue();
		if ((strcasecmp(pszScheme, "sip:") == 0 || strcasecmp(pszScheme, "sips:") == 0) &&
			reg_urlParams.Match (buffer)){
		if (is_sip_scheme(pszScheme) &&	reg_urlParams.Match (buffer)){
			SetHypFieldIsPresent (id,  1);
			SetHypFieldLength(id, reg_urlParams.GetMatchedLength());
		} else if (is_tel_scheme(pszScheme)) {
			// "tel" parameters have a different syntax (e.g. & is allowed within both id and values)
			if (reg_telParams.Match (buffer)) {
				SetHypFieldIsPresent (id,  1);
				SetHypFieldLength(id, reg_telParams.GetMatchedLength());
			} else {
				SetHypFieldIsPresent(id, 0);
			}
		}
		else {
			SetHypFieldIsPresent(id, 0);
		}
		break;
	case id_headers:
		pszScheme = Get_scheme().GetValue();
		if ((strcasecmp(pszScheme, "sip:") == 0 || strcasecmp(pszScheme, "sips:") == 0) && 
			reg_headers.Match (buffer)){
		if (is_sip_scheme(pszScheme) && reg_headers.Match (buffer)){
			SetHypFieldIsPresent (id,  1);
			SetHypFieldLength(id, reg_headers.GetMatchedLength());
		} else {
@@ -271,7 +306,7 @@ void HostPort::PreDecodeField (int id, Buffer& buffer) throw (DecodeError)
		if (strcmp(pszParName, "SipUrl") == 0) {
			SipUrl * pSipUrl = dynamic_cast<SipUrl*>(parent);
			const char * pszScheme = pSipUrl->Get_scheme().GetValue();
			bRequestUri = strcasecmp(pszScheme, "sip:") != 0 && strcasecmp(pszScheme, "sips:") != 0;
			bRequestUri = !is_sip_scheme(pszScheme);
		}
	}

@@ -335,6 +370,9 @@ void GenericParam::PreDecodeField (int id, Buffer& buffer) throw (DecodeError)
	static Regex reg_hparname ("^" SIPREG_HPARAM "+");
	static Regex reg_hparvalue ("^" SIPREG_HPARAM "*");

	static Regex reg_telparname ("^" SIPREG_TELPARAM_NAME);
	static Regex reg_telparvalue ("^" SIPREG_TELPARAM_VALUE);

	Regex * preg_name;
	Regex * preg_value;
	bool bMandatoryParam = false;
@@ -344,9 +382,21 @@ void GenericParam::PreDecodeField (int id, Buffer& buffer) throw (DecodeError)
		throw DecodeError (this, "Parent type cannot be null");
	const char * pszParName = parent->GetTypeName();
	if (strcmp(pszParName, "SemicolonParam_List") == 0){
		bool bTel = false;
		parent = parent->GetParent();
		if (parent != NULL && strcmp (parent->GetTypeName(), "SipUrl") == 0) {
			SipUrl * pSipUrl = dynamic_cast<SipUrl*>(parent);
			const char * pszScheme = pSipUrl->Get_scheme().GetValue();
			bTel = is_tel_scheme(pszScheme);
		}
		if (bTel) {
			preg_name = &reg_telparname;
			preg_value = &reg_telparvalue;
		} else {
			preg_name = &reg_pparname;
			preg_value = &reg_pparvalue;
		}
	}
	else if (strcmp(pszParName, "AmpersandParam_List") == 0){
		preg_name = &reg_hparname;
		preg_value = &reg_hparvalue;