2004-12-24 18:15:34 +00:00
|
|
|
/**
|
|
|
|
* message.cpp
|
|
|
|
* Yet Another SIP Stack
|
|
|
|
* This file is part of the YATE Project http://YATE.null.ro
|
|
|
|
*
|
|
|
|
* Yet Another Telephony Engine - a fully featured software PBX and IVR
|
2006-05-27 15:08:43 +00:00
|
|
|
* Copyright (C) 2004-2006 Null Team
|
2004-12-24 18:15:34 +00:00
|
|
|
*
|
|
|
|
* This program 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.
|
|
|
|
*
|
|
|
|
* This program 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
|
2006-05-27 15:08:43 +00:00
|
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
2004-12-24 18:15:34 +00:00
|
|
|
*/
|
|
|
|
|
2005-04-28 22:46:59 +00:00
|
|
|
#include <yatesip.h>
|
|
|
|
#include "util.h"
|
2004-12-24 18:15:34 +00:00
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
|
|
|
|
|
|
using namespace TelEngine;
|
|
|
|
|
2005-06-03 12:23:12 +00:00
|
|
|
SIPHeaderLine::SIPHeaderLine(const char* name, const String& value, char sep)
|
2005-06-13 12:08:56 +00:00
|
|
|
: NamedString(name), m_separator(sep ? sep : ';')
|
2004-12-28 05:15:11 +00:00
|
|
|
{
|
|
|
|
if (value.null())
|
|
|
|
return;
|
2005-06-03 12:23:12 +00:00
|
|
|
XDebug(DebugAll,"SIPHeaderLine::SIPHeaderLine('%s','%s') [%p]",name,value.c_str(),this);
|
2006-07-25 22:23:54 +00:00
|
|
|
int sp = findSep(value,m_separator);
|
2004-12-28 05:15:11 +00:00
|
|
|
if (sp < 0) {
|
|
|
|
assign(value);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
assign(value,sp);
|
|
|
|
trimBlanks();
|
|
|
|
while (sp < (int)value.length()) {
|
2006-07-25 22:23:54 +00:00
|
|
|
int ep = findSep(value,m_separator,sp+1);
|
2004-12-28 05:15:11 +00:00
|
|
|
if (ep <= sp)
|
|
|
|
ep = value.length();
|
|
|
|
int eq = value.find('=',sp+1);
|
|
|
|
if ((eq > 0) && (eq < ep)) {
|
|
|
|
String pname(value.substr(sp+1,eq-sp-1));
|
|
|
|
String pvalue(value.substr(eq+1,ep-eq-1));
|
|
|
|
pname.trimBlanks();
|
|
|
|
pvalue.trimBlanks();
|
|
|
|
if (!pname.null()) {
|
2005-06-03 12:23:12 +00:00
|
|
|
XDebug(DebugAll,"hdr param name='%s' value='%s'",pname.c_str(),pvalue.c_str());
|
2004-12-28 05:15:11 +00:00
|
|
|
m_params.append(new NamedString(pname,pvalue));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
String pname(value.substr(sp+1,ep-sp-1));
|
|
|
|
pname.trimBlanks();
|
|
|
|
if (!pname.null()) {
|
2005-06-03 12:23:12 +00:00
|
|
|
XDebug(DebugAll,"hdr param name='%s' (no value)",pname.c_str());
|
2004-12-28 05:15:11 +00:00
|
|
|
m_params.append(new NamedString(pname));
|
|
|
|
}
|
|
|
|
}
|
2005-01-01 22:21:32 +00:00
|
|
|
sp = ep;
|
2004-12-28 05:15:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-06-28 12:06:12 +00:00
|
|
|
SIPHeaderLine::SIPHeaderLine(const SIPHeaderLine& original, const char* newName)
|
|
|
|
: NamedString(newName ? newName : original.name().c_str(),original),
|
2005-06-13 15:01:15 +00:00
|
|
|
m_separator(original.separator())
|
2004-12-28 05:15:11 +00:00
|
|
|
{
|
2005-05-07 23:47:37 +00:00
|
|
|
XDebug(DebugAll,"SIPHeaderLine::SIPHeaderLine(%p '%s') [%p]",&original,name().c_str(),this);
|
2004-12-28 05:15:11 +00:00
|
|
|
const ObjList* l = &original.params();
|
|
|
|
for (; l; l = l->next()) {
|
|
|
|
const NamedString* t = static_cast<const NamedString*>(l->get());
|
|
|
|
if (t)
|
|
|
|
m_params.append(new NamedString(t->name(),*t));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-05-02 18:31:05 +00:00
|
|
|
SIPHeaderLine::~SIPHeaderLine()
|
2004-12-28 05:15:11 +00:00
|
|
|
{
|
2005-05-07 23:47:37 +00:00
|
|
|
XDebug(DebugAll,"SIPHeaderLine::~SIPHeaderLine() [%p]",this);
|
2004-12-28 05:15:11 +00:00
|
|
|
}
|
|
|
|
|
2005-06-03 12:23:12 +00:00
|
|
|
void* SIPHeaderLine::getObject(const String& name) const
|
|
|
|
{
|
|
|
|
if (name == "SIPHeaderLine")
|
|
|
|
return const_cast<SIPHeaderLine*>(this);
|
|
|
|
return NamedString::getObject(name);
|
|
|
|
}
|
|
|
|
|
2005-06-28 12:06:12 +00:00
|
|
|
SIPHeaderLine* SIPHeaderLine::clone(const char* newName) const
|
2005-06-03 12:23:12 +00:00
|
|
|
{
|
2005-06-28 12:06:12 +00:00
|
|
|
return new SIPHeaderLine(*this,newName);
|
2005-06-03 12:23:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void SIPHeaderLine::buildLine(String& line) const
|
|
|
|
{
|
|
|
|
line << name() << ": " << *this;
|
|
|
|
const ObjList* p = &m_params;
|
|
|
|
for (; p; p = p->next()) {
|
|
|
|
NamedString* s = static_cast<NamedString*>(p->get());
|
|
|
|
if (s) {
|
|
|
|
line << separator() << s->name();
|
|
|
|
if (!s->null())
|
|
|
|
line << "=" << *s;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-05-31 22:18:38 +00:00
|
|
|
const NamedString* SIPHeaderLine::getParam(const char* name) const
|
2004-12-28 05:15:11 +00:00
|
|
|
{
|
|
|
|
if (!(name && *name))
|
|
|
|
return 0;
|
|
|
|
const ObjList* l = &m_params;
|
|
|
|
for (; l; l = l->next()) {
|
|
|
|
const NamedString* t = static_cast<const NamedString*>(l->get());
|
|
|
|
if (t && (t->name() &= name))
|
|
|
|
return t;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-05-31 22:18:38 +00:00
|
|
|
void SIPHeaderLine::setParam(const char* name, const char* value)
|
2005-01-01 22:21:32 +00:00
|
|
|
{
|
|
|
|
ObjList* p = m_params.find(name);
|
|
|
|
if (p)
|
|
|
|
*static_cast<NamedString*>(p->get()) = value;
|
|
|
|
else
|
|
|
|
m_params.append(new NamedString(name,value));
|
|
|
|
}
|
|
|
|
|
2005-05-31 22:18:38 +00:00
|
|
|
void SIPHeaderLine::delParam(const char* name)
|
2005-01-01 22:21:32 +00:00
|
|
|
{
|
|
|
|
ObjList* p = m_params.find(name);
|
|
|
|
if (p)
|
|
|
|
p->remove();
|
|
|
|
}
|
|
|
|
|
2005-06-03 12:23:12 +00:00
|
|
|
SIPAuthLine::SIPAuthLine(const char* name, const String& value)
|
|
|
|
: SIPHeaderLine(name,String::empty(),',')
|
|
|
|
{
|
|
|
|
XDebug(DebugAll,"SIPAuthLine::SIPAuthLine('%s','%s') [%p]",name,value.c_str(),this);
|
|
|
|
if (value.null())
|
|
|
|
return;
|
|
|
|
int sp = value.find(' ');
|
|
|
|
if (sp < 0) {
|
|
|
|
assign(value);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
assign(value,sp);
|
|
|
|
trimBlanks();
|
|
|
|
while (sp < (int)value.length()) {
|
|
|
|
int ep = value.find(m_separator,sp+1);
|
|
|
|
int quot = value.find('"',sp+1);
|
|
|
|
if ((quot > sp) && (quot < ep)) {
|
|
|
|
quot = value.find('"',quot+1);
|
|
|
|
if (quot > sp)
|
|
|
|
ep = value.find(m_separator,quot+1);
|
|
|
|
}
|
|
|
|
if (ep <= sp)
|
|
|
|
ep = value.length();
|
|
|
|
int eq = value.find('=',sp+1);
|
|
|
|
if ((eq > 0) && (eq < ep)) {
|
|
|
|
String pname(value.substr(sp+1,eq-sp-1));
|
|
|
|
String pvalue(value.substr(eq+1,ep-eq-1));
|
|
|
|
pname.trimBlanks();
|
|
|
|
pvalue.trimBlanks();
|
|
|
|
if (!pname.null()) {
|
|
|
|
XDebug(DebugAll,"auth param name='%s' value='%s'",pname.c_str(),pvalue.c_str());
|
|
|
|
m_params.append(new NamedString(pname,pvalue));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
String pname(value.substr(sp+1,ep-sp-1));
|
|
|
|
pname.trimBlanks();
|
|
|
|
if (!pname.null()) {
|
|
|
|
XDebug(DebugAll,"auth param name='%s' (no value)",pname.c_str());
|
|
|
|
m_params.append(new NamedString(pname));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
sp = ep;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-06-28 12:06:12 +00:00
|
|
|
SIPAuthLine::SIPAuthLine(const SIPAuthLine& original, const char* newName)
|
|
|
|
: SIPHeaderLine(original,newName)
|
2005-06-03 12:23:12 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void* SIPAuthLine::getObject(const String& name) const
|
|
|
|
{
|
|
|
|
if (name == "SIPAuthLine")
|
|
|
|
return const_cast<SIPAuthLine*>(this);
|
|
|
|
return SIPHeaderLine::getObject(name);
|
|
|
|
}
|
|
|
|
|
2005-06-28 12:06:12 +00:00
|
|
|
SIPHeaderLine* SIPAuthLine::clone(const char* newName) const
|
2005-06-03 12:23:12 +00:00
|
|
|
{
|
2005-06-28 12:06:12 +00:00
|
|
|
return new SIPAuthLine(*this,newName);
|
2005-06-03 12:23:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void SIPAuthLine::buildLine(String& line) const
|
|
|
|
{
|
|
|
|
line << name() << ": " << *this;
|
|
|
|
const ObjList* p = &m_params;
|
|
|
|
for (bool first = true; p; p = p->next()) {
|
|
|
|
NamedString* s = static_cast<NamedString*>(p->get());
|
|
|
|
if (s) {
|
|
|
|
if (first)
|
|
|
|
first = false;
|
|
|
|
else
|
|
|
|
line << separator();
|
|
|
|
line << " " << s->name();
|
|
|
|
if (!s->null())
|
|
|
|
line << "=" << *s;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-06-12 18:58:17 +00:00
|
|
|
SIPMessage::SIPMessage(const SIPMessage& original)
|
|
|
|
: version(original.version), method(original.method), uri(original.uri),
|
|
|
|
code(original.code), reason(original.reason),
|
|
|
|
body(0), m_ep(0),
|
|
|
|
m_valid(original.isValid()), m_answer(original.isAnswer()),
|
|
|
|
m_outgoing(original.isOutgoing()), m_ack(original.isACK()),
|
|
|
|
m_cseq(-1)
|
|
|
|
{
|
|
|
|
DDebug(DebugAll,"SIPMessage::SIPMessage(&%p) [%p]",
|
|
|
|
&original,this);
|
|
|
|
if (original.body)
|
|
|
|
setBody(original.body->clone());
|
|
|
|
setParty(original.getParty());
|
|
|
|
bool via1 = true;
|
|
|
|
const ObjList* l = &original.header;
|
|
|
|
for (; l; l = l->next()) {
|
|
|
|
const SIPHeaderLine* hl = static_cast<SIPHeaderLine*>(l->get());
|
|
|
|
if (!hl)
|
|
|
|
continue;
|
|
|
|
// CSeq must not be copied, a new one will be built by complete()
|
|
|
|
if (hl->name() &= "CSeq")
|
|
|
|
continue;
|
|
|
|
SIPHeaderLine* nl = hl->clone();
|
2005-10-28 03:10:32 +00:00
|
|
|
// this is a new transaction so let complete() add randomness
|
2005-06-12 18:58:17 +00:00
|
|
|
if (via1 && (nl->name() &= "Via")) {
|
|
|
|
via1 = false;
|
|
|
|
nl->delParam("branch");
|
|
|
|
}
|
|
|
|
addHeader(nl);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-12-28 05:15:11 +00:00
|
|
|
SIPMessage::SIPMessage(const char* _method, const char* _uri, const char* _version)
|
2006-12-21 23:26:04 +00:00
|
|
|
: version(_version), method(_method), uri(_uri), code(0),
|
2004-12-29 17:01:39 +00:00
|
|
|
body(0), m_ep(0), m_valid(true),
|
|
|
|
m_answer(false), m_outgoing(true), m_ack(false), m_cseq(-1)
|
2004-12-24 18:15:34 +00:00
|
|
|
{
|
2005-05-06 18:13:33 +00:00
|
|
|
DDebug(DebugAll,"SIPMessage::SIPMessage('%s','%s','%s') [%p]",
|
2005-01-02 04:52:02 +00:00
|
|
|
_method,_uri,_version,this);
|
2004-12-24 18:15:34 +00:00
|
|
|
}
|
|
|
|
|
2005-05-31 22:18:38 +00:00
|
|
|
SIPMessage::SIPMessage(SIPParty* ep, const char* buf, int len)
|
2006-12-21 23:26:04 +00:00
|
|
|
: code(0), body(0), m_ep(ep), m_valid(false),
|
|
|
|
m_answer(false), m_outgoing(false), m_ack(false), m_cseq(-1)
|
2004-12-24 18:15:34 +00:00
|
|
|
{
|
2005-09-06 02:51:09 +00:00
|
|
|
DDebug(DebugInfo,"SIPMessage::SIPMessage(%p,%d) [%p]\n------\n%s------",
|
2004-12-24 18:15:34 +00:00
|
|
|
buf,len,this,buf);
|
|
|
|
if (m_ep)
|
|
|
|
m_ep->ref();
|
|
|
|
if (!(buf && *buf)) {
|
|
|
|
Debug(DebugWarn,"Empty message text in [%p]",this);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (len < 0)
|
|
|
|
len = ::strlen(buf);
|
|
|
|
m_valid = parse(buf,len);
|
|
|
|
}
|
|
|
|
|
|
|
|
SIPMessage::SIPMessage(const SIPMessage* message, int _code, const char* _reason)
|
2005-04-29 21:07:41 +00:00
|
|
|
: code(_code), body(0),
|
2004-12-29 17:01:39 +00:00
|
|
|
m_ep(0), m_valid(false),
|
2004-12-31 01:09:21 +00:00
|
|
|
m_answer(true), m_outgoing(true), m_ack(false), m_cseq(-1)
|
2004-12-24 18:15:34 +00:00
|
|
|
{
|
2005-05-06 18:13:33 +00:00
|
|
|
DDebug(DebugAll,"SIPMessage::SIPMessage(%p,%d,'%s') [%p]",
|
2004-12-24 18:15:34 +00:00
|
|
|
message,_code,_reason,this);
|
2005-04-29 21:07:41 +00:00
|
|
|
if (!_reason)
|
|
|
|
_reason = lookup(code,SIPResponses,"Unknown Reason Code");
|
|
|
|
reason = _reason;
|
2004-12-24 18:15:34 +00:00
|
|
|
if (!(message && message->isValid()))
|
|
|
|
return;
|
|
|
|
m_ep = message->getParty();
|
|
|
|
if (m_ep)
|
|
|
|
m_ep->ref();
|
|
|
|
version = message->version;
|
|
|
|
uri = message->uri;
|
|
|
|
method = message->method;
|
2004-12-28 14:50:10 +00:00
|
|
|
copyAllHeaders(message,"Via");
|
2005-06-13 15:01:15 +00:00
|
|
|
copyAllHeaders(message,"Record-Route");
|
2004-12-28 14:50:10 +00:00
|
|
|
copyHeader(message,"From");
|
2004-12-31 04:18:13 +00:00
|
|
|
copyHeader(message,"To");
|
2004-12-28 14:50:10 +00:00
|
|
|
copyHeader(message,"Call-ID");
|
|
|
|
copyHeader(message,"CSeq");
|
2004-12-24 18:15:34 +00:00
|
|
|
m_valid = true;
|
|
|
|
}
|
|
|
|
|
2005-07-01 20:31:43 +00:00
|
|
|
SIPMessage::SIPMessage(const SIPMessage* original, const SIPMessage* answer)
|
2006-12-21 23:26:04 +00:00
|
|
|
: method("ACK"), code(0),
|
2005-05-20 05:37:58 +00:00
|
|
|
body(0), m_ep(0), m_valid(false),
|
2004-12-29 17:01:39 +00:00
|
|
|
m_answer(false), m_outgoing(true), m_ack(true), m_cseq(-1)
|
2004-12-28 14:50:10 +00:00
|
|
|
{
|
2005-07-01 20:31:43 +00:00
|
|
|
DDebug(DebugAll,"SIPMessage::SIPMessage(%p,%p) [%p]",original,answer,this);
|
|
|
|
if (!(original && original->isValid()))
|
2004-12-28 14:50:10 +00:00
|
|
|
return;
|
2005-07-01 20:31:43 +00:00
|
|
|
m_ep = original->getParty();
|
2004-12-28 14:50:10 +00:00
|
|
|
if (m_ep)
|
|
|
|
m_ep->ref();
|
2005-07-01 20:31:43 +00:00
|
|
|
version = original->version;
|
|
|
|
uri = original->uri;
|
|
|
|
copyAllHeaders(original,"Via");
|
2005-05-02 18:31:05 +00:00
|
|
|
SIPHeaderLine* hl = const_cast<SIPHeaderLine*>(getHeader("Via"));
|
2005-01-03 03:02:11 +00:00
|
|
|
if (!hl) {
|
|
|
|
String tmp;
|
|
|
|
tmp << version << "/" << getParty()->getProtoName();
|
|
|
|
tmp << " " << getParty()->getLocalAddr() << ":" << getParty()->getLocalPort();
|
2005-05-02 18:31:05 +00:00
|
|
|
hl = new SIPHeaderLine("Via",tmp);
|
2005-01-03 03:02:11 +00:00
|
|
|
header.append(hl);
|
|
|
|
}
|
2005-07-01 20:31:43 +00:00
|
|
|
if (answer && (answer->code == 200) && (original->method &= "INVITE")) {
|
2005-01-03 03:02:11 +00:00
|
|
|
String tmp("z9hG4bK");
|
|
|
|
tmp << (int)::random();
|
|
|
|
hl->setParam("branch",tmp);
|
2005-07-01 20:31:43 +00:00
|
|
|
const SIPHeaderLine* co = answer->getHeader("Contact");
|
|
|
|
if (co) {
|
|
|
|
uri = *co;
|
|
|
|
Regexp r("^[^<]*<\\([^>]*\\)>.*$");
|
|
|
|
if (uri.matches(r))
|
|
|
|
uri = uri.matchString(1);
|
|
|
|
}
|
2007-02-05 19:19:29 +00:00
|
|
|
// new transaction - get/apply routeset unless INVITE already knew it
|
|
|
|
if (!original->getHeader("Route")) {
|
|
|
|
ObjList* routeset = answer->getRoutes();
|
|
|
|
addRoutes(routeset);
|
2007-05-15 15:40:50 +00:00
|
|
|
TelEngine::destruct(routeset);
|
2007-02-05 19:19:29 +00:00
|
|
|
}
|
2005-01-03 03:02:11 +00:00
|
|
|
}
|
2005-07-01 20:31:43 +00:00
|
|
|
copyAllHeaders(original,"Route");
|
|
|
|
copyHeader(original,"From");
|
|
|
|
copyHeader(original,"To");
|
|
|
|
copyHeader(original,"Call-ID");
|
2004-12-28 14:50:10 +00:00
|
|
|
String tmp;
|
2005-07-01 20:31:43 +00:00
|
|
|
tmp << original->getCSeq() << " " << method;
|
2004-12-28 14:50:10 +00:00
|
|
|
addHeader("CSeq",tmp);
|
2005-07-01 20:31:43 +00:00
|
|
|
copyHeader(original,"Max-Forwards");
|
|
|
|
copyAllHeaders(original,"Contact");
|
|
|
|
copyAllHeaders(original,"Authorization");
|
|
|
|
copyAllHeaders(original,"Proxy-Authorization");
|
|
|
|
copyHeader(original,"User-Agent");
|
2004-12-28 14:50:10 +00:00
|
|
|
m_valid = true;
|
|
|
|
}
|
|
|
|
|
2004-12-24 18:15:34 +00:00
|
|
|
SIPMessage::~SIPMessage()
|
|
|
|
{
|
2005-05-06 18:13:33 +00:00
|
|
|
DDebug(DebugAll,"SIPMessage::~SIPMessage() [%p]",this);
|
2004-12-24 18:15:34 +00:00
|
|
|
m_valid = false;
|
2004-12-29 04:02:55 +00:00
|
|
|
setParty();
|
|
|
|
setBody();
|
2004-12-24 18:15:34 +00:00
|
|
|
}
|
|
|
|
|
2004-12-31 01:09:21 +00:00
|
|
|
void SIPMessage::complete(SIPEngine* engine, const char* user, const char* domain, const char* dlgTag)
|
2004-12-28 05:47:43 +00:00
|
|
|
{
|
2005-12-15 20:52:36 +00:00
|
|
|
DDebug(engine,DebugAll,"SIPMessage::complete(%p,'%s','%s','%s')%s%s%s [%p]",
|
2004-12-31 01:09:21 +00:00
|
|
|
engine,user,domain,dlgTag,
|
|
|
|
isACK() ? " ACK" : "",
|
|
|
|
isOutgoing() ? " OUT" : "",
|
|
|
|
isAnswer() ? " ANS" : "",
|
|
|
|
this);
|
2004-12-28 05:47:43 +00:00
|
|
|
if (!engine)
|
|
|
|
return;
|
2004-12-28 14:50:10 +00:00
|
|
|
|
2005-01-10 04:33:15 +00:00
|
|
|
// don't complete incoming messages
|
|
|
|
if (!isOutgoing())
|
2004-12-29 17:01:39 +00:00
|
|
|
return;
|
|
|
|
|
2005-07-01 21:12:16 +00:00
|
|
|
if (!getParty()) {
|
|
|
|
engine->buildParty(this);
|
|
|
|
if (!getParty()) {
|
2005-12-15 20:52:36 +00:00
|
|
|
Debug(engine,DebugGoOn,"Could not complete party-less SIP message [%p]",this);
|
2005-07-01 21:12:16 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-01-10 04:33:15 +00:00
|
|
|
// only set the dialog tag on ACK
|
|
|
|
if (isACK()) {
|
2005-05-02 18:31:05 +00:00
|
|
|
SIPHeaderLine* hl = const_cast<SIPHeaderLine*>(getHeader("To"));
|
2005-01-10 04:33:15 +00:00
|
|
|
if (dlgTag && hl && !hl->getParam("tag"))
|
|
|
|
hl->setParam("tag",dlgTag);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2005-07-01 20:31:43 +00:00
|
|
|
const char* luser = user ? user : "anonymous";
|
2004-12-29 04:02:55 +00:00
|
|
|
if (!domain)
|
2005-01-02 04:52:02 +00:00
|
|
|
domain = getParty()->getLocalAddr();
|
2004-12-29 04:02:55 +00:00
|
|
|
|
2005-05-02 18:31:05 +00:00
|
|
|
SIPHeaderLine* hl = const_cast<SIPHeaderLine*>(getHeader("Via"));
|
2004-12-29 04:02:55 +00:00
|
|
|
if (!hl) {
|
|
|
|
String tmp;
|
|
|
|
tmp << version << "/" << getParty()->getProtoName();
|
|
|
|
tmp << " " << getParty()->getLocalAddr() << ":" << getParty()->getLocalPort();
|
2005-05-02 18:31:05 +00:00
|
|
|
hl = new SIPHeaderLine("Via",tmp);
|
2005-11-08 14:02:38 +00:00
|
|
|
if (!(isAnswer() || isACK()))
|
|
|
|
hl->setParam("rport");
|
2004-12-29 04:02:55 +00:00
|
|
|
header.append(hl);
|
|
|
|
}
|
2005-01-02 04:52:02 +00:00
|
|
|
if (!(isAnswer() || hl->getParam("branch"))) {
|
2004-12-29 04:02:55 +00:00
|
|
|
String tmp("z9hG4bK");
|
|
|
|
tmp << (int)::random();
|
2005-01-01 22:21:32 +00:00
|
|
|
hl->setParam("branch",tmp);
|
2004-12-29 04:02:55 +00:00
|
|
|
}
|
2004-12-31 01:09:21 +00:00
|
|
|
if (isAnswer()) {
|
2005-01-01 22:21:32 +00:00
|
|
|
hl->setParam("received",getParty()->getPartyAddr());
|
|
|
|
hl->setParam("rport",String(getParty()->getPartyPort()));
|
2004-12-31 01:09:21 +00:00
|
|
|
}
|
2004-12-29 04:02:55 +00:00
|
|
|
|
2006-05-23 17:47:24 +00:00
|
|
|
if (!isAnswer()) {
|
|
|
|
hl = const_cast<SIPHeaderLine*>(getHeader("From"));
|
|
|
|
if (!hl) {
|
|
|
|
String tmp;
|
|
|
|
tmp << "<sip:" << luser << "@" << domain << ">";
|
|
|
|
hl = new SIPHeaderLine("From",tmp);
|
|
|
|
header.append(hl);
|
|
|
|
}
|
|
|
|
if (!hl->getParam("tag"))
|
|
|
|
hl->setParam("tag",String((int)::random()));
|
2004-12-29 04:02:55 +00:00
|
|
|
}
|
|
|
|
|
2005-05-02 18:31:05 +00:00
|
|
|
hl = const_cast<SIPHeaderLine*>(getHeader("To"));
|
2006-05-23 17:47:24 +00:00
|
|
|
if (!(isAnswer() || hl)) {
|
2004-12-29 04:02:55 +00:00
|
|
|
String tmp;
|
|
|
|
tmp << "<" << uri << ">";
|
2005-05-02 18:31:05 +00:00
|
|
|
hl = new SIPHeaderLine("To",tmp);
|
2004-12-31 01:09:21 +00:00
|
|
|
header.append(hl);
|
2004-12-29 04:02:55 +00:00
|
|
|
}
|
2006-05-23 17:47:24 +00:00
|
|
|
if (hl && dlgTag && !hl->getParam("tag"))
|
2005-01-01 22:21:32 +00:00
|
|
|
hl->setParam("tag",dlgTag);
|
2004-12-29 04:02:55 +00:00
|
|
|
|
2006-05-23 17:47:24 +00:00
|
|
|
if (!(isAnswer() || getHeader("Call-ID"))) {
|
2004-12-29 04:02:55 +00:00
|
|
|
String tmp;
|
|
|
|
tmp << (int)::random() << "@" << domain;
|
|
|
|
addHeader("Call-ID",tmp);
|
|
|
|
}
|
|
|
|
|
2006-05-23 17:47:24 +00:00
|
|
|
if (!(isAnswer() || getHeader("CSeq"))) {
|
2004-12-28 14:50:10 +00:00
|
|
|
String tmp;
|
|
|
|
m_cseq = engine->getNextCSeq();
|
|
|
|
tmp << m_cseq << " " << method;
|
|
|
|
addHeader("CSeq",tmp);
|
|
|
|
}
|
|
|
|
|
2006-02-21 15:09:25 +00:00
|
|
|
const char* info = isAnswer() ? "Server" : "User-Agent";
|
|
|
|
if (!(getHeader(info) || engine->getUserAgent().null()))
|
|
|
|
addHeader(info,engine->getUserAgent());
|
|
|
|
|
|
|
|
// keep 100 answers short - they are hop to hop anyway
|
|
|
|
if (isAnswer() && (code == 100))
|
|
|
|
return;
|
|
|
|
|
2004-12-29 17:01:39 +00:00
|
|
|
if (!(isAnswer() || getHeader("Max-Forwards"))) {
|
2004-12-28 14:50:10 +00:00
|
|
|
String tmp(engine->getMaxForwards());
|
|
|
|
addHeader("Max-Forwards",tmp);
|
2004-12-28 05:47:43 +00:00
|
|
|
}
|
2004-12-28 14:50:10 +00:00
|
|
|
|
2006-06-28 07:54:59 +00:00
|
|
|
if ((method == "INVITE") && !getHeader("Contact")) {
|
|
|
|
// automatically add a contact field to (re)INVITE and its answers
|
2005-07-01 20:31:43 +00:00
|
|
|
String tmp(user);
|
|
|
|
if (!tmp) {
|
|
|
|
tmp = uri;
|
|
|
|
Regexp r(":\\([^:@]*\\)@");
|
|
|
|
tmp.matches(r);
|
|
|
|
tmp = tmp.matchString(1);
|
|
|
|
}
|
|
|
|
if (tmp) {
|
|
|
|
tmp = "<sip:" + tmp;
|
|
|
|
tmp << "@" << getParty()->getLocalAddr() ;
|
|
|
|
tmp << ":" << getParty()->getLocalPort() << ">";
|
|
|
|
addHeader("Contact",tmp);
|
2005-01-01 22:21:32 +00:00
|
|
|
}
|
2004-12-31 01:09:21 +00:00
|
|
|
}
|
|
|
|
|
2004-12-29 17:01:39 +00:00
|
|
|
if (!getHeader("Allow"))
|
|
|
|
addHeader("Allow",engine->getAllowed());
|
2004-12-28 05:47:43 +00:00
|
|
|
}
|
|
|
|
|
2005-06-28 12:06:12 +00:00
|
|
|
bool SIPMessage::copyHeader(const SIPMessage* message, const char* name, const char* newName)
|
2004-12-28 05:15:11 +00:00
|
|
|
{
|
2005-05-02 18:31:05 +00:00
|
|
|
const SIPHeaderLine* hl = message ? message->getHeader(name) : 0;
|
2004-12-28 05:15:11 +00:00
|
|
|
if (hl) {
|
2005-06-28 12:06:12 +00:00
|
|
|
header.append(hl->clone(newName));
|
2004-12-28 05:15:11 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2005-06-28 12:06:12 +00:00
|
|
|
int SIPMessage::copyAllHeaders(const SIPMessage* message, const char* name, const char* newName)
|
2004-12-28 05:15:11 +00:00
|
|
|
{
|
|
|
|
if (!(message && name && *name))
|
|
|
|
return 0;
|
|
|
|
int c = 0;
|
|
|
|
const ObjList* l = &message->header;
|
|
|
|
for (; l; l = l->next()) {
|
2005-05-02 18:31:05 +00:00
|
|
|
const SIPHeaderLine* hl = static_cast<const SIPHeaderLine*>(l->get());
|
2004-12-28 05:15:11 +00:00
|
|
|
if (hl && (hl->name() &= name)) {
|
|
|
|
++c;
|
2005-06-28 12:06:12 +00:00
|
|
|
header.append(hl->clone(newName));
|
2004-12-28 05:15:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
|
2004-12-24 18:15:34 +00:00
|
|
|
bool SIPMessage::parseFirst(String& line)
|
|
|
|
{
|
2005-05-07 23:47:37 +00:00
|
|
|
XDebug(DebugAll,"SIPMessage::parse firstline= '%s'",line.c_str());
|
2004-12-24 18:15:34 +00:00
|
|
|
if (line.null())
|
|
|
|
return false;
|
|
|
|
Regexp r("^\\([Ss][Ii][Pp]/[0-9]\\.[0-9]\\+\\)[[:space:]]\\+\\([0-9][0-9][0-9]\\)[[:space:]]\\+\\(.*\\)$");
|
|
|
|
if (line.matches(r)) {
|
|
|
|
// Answer: <version> <code> <reason-phrase>
|
|
|
|
m_answer = true;
|
|
|
|
version = line.matchString(1).toUpper();
|
|
|
|
code = line.matchString(2).toInteger();
|
|
|
|
reason = line.matchString(3);
|
2005-05-06 18:13:33 +00:00
|
|
|
DDebug(DebugAll,"got answer version='%s' code=%d reason='%s'",
|
2004-12-24 18:15:34 +00:00
|
|
|
version.c_str(),code,reason.c_str());
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
r = "^\\([[:alpha:]]\\+\\)[[:space:]]\\+\\([^[:space:]]\\+\\)[[:space:]]\\+\\([Ss][Ii][Pp]/[0-9]\\.[0-9]\\+\\)$";
|
|
|
|
if (line.matches(r)) {
|
|
|
|
// Request: <method> <uri> <version>
|
|
|
|
m_answer = false;
|
|
|
|
method = line.matchString(1).toUpper();
|
|
|
|
uri = line.matchString(2);
|
|
|
|
version = line.matchString(3).toUpper();
|
2005-05-06 18:13:33 +00:00
|
|
|
DDebug(DebugAll,"got request method='%s' uri='%s' version='%s'",
|
2004-12-24 18:15:34 +00:00
|
|
|
method.c_str(),uri.c_str(),version.c_str());
|
2004-12-29 17:01:39 +00:00
|
|
|
if (method == "ACK")
|
|
|
|
m_ack = true;
|
2004-12-24 18:15:34 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
Debug(DebugAll,"Invalid SIP line '%s'",line.c_str());
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2004-12-28 05:15:11 +00:00
|
|
|
bool SIPMessage::parse(const char* buf, int len)
|
2004-12-24 18:15:34 +00:00
|
|
|
{
|
2005-05-06 18:13:33 +00:00
|
|
|
DDebug(DebugAll,"SIPMessage::parse(%p,%d) [%p]",buf,len,this);
|
2004-12-24 18:15:34 +00:00
|
|
|
String* line = 0;
|
|
|
|
while (len > 0) {
|
2007-07-26 23:47:29 +00:00
|
|
|
line = MimeBody::getUnfoldedLine(buf,len);
|
2004-12-24 18:15:34 +00:00
|
|
|
if (!line->null())
|
|
|
|
break;
|
|
|
|
// Skip any initial empty lines
|
2007-05-15 15:40:50 +00:00
|
|
|
TelEngine::destruct(line);
|
2004-12-24 18:15:34 +00:00
|
|
|
}
|
|
|
|
if (!line)
|
|
|
|
return false;
|
|
|
|
if (!parseFirst(*line)) {
|
|
|
|
line->destruct();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
line->destruct();
|
|
|
|
String content;
|
2006-05-23 17:47:24 +00:00
|
|
|
int clen = -1;
|
2004-12-24 18:15:34 +00:00
|
|
|
while (len > 0) {
|
2007-07-26 23:47:29 +00:00
|
|
|
line = MimeBody::getUnfoldedLine(buf,len);
|
2004-12-24 18:15:34 +00:00
|
|
|
if (line->null()) {
|
2004-12-27 15:08:12 +00:00
|
|
|
// Found end of headers
|
2004-12-24 18:15:34 +00:00
|
|
|
line->destruct();
|
|
|
|
break;
|
|
|
|
}
|
2004-12-27 15:08:12 +00:00
|
|
|
int col = line->find(':');
|
|
|
|
if (col <= 0) {
|
|
|
|
line->destruct();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
String name = line->substr(0,col);
|
|
|
|
name.trimBlanks();
|
|
|
|
if (name.null()) {
|
|
|
|
line->destruct();
|
|
|
|
return false;
|
|
|
|
}
|
2005-06-03 12:23:12 +00:00
|
|
|
name = uncompactForm(name);
|
2004-12-27 15:08:12 +00:00
|
|
|
*line >> ":";
|
|
|
|
line->trimBlanks();
|
2005-05-07 23:47:37 +00:00
|
|
|
XDebug(DebugAll,"SIPMessage::parse header='%s' value='%s'",name.c_str(),line->c_str());
|
2005-06-03 12:23:12 +00:00
|
|
|
|
|
|
|
if ((name &= "WWW-Authenticate") ||
|
|
|
|
(name &= "Proxy-Authenticate") ||
|
|
|
|
(name &= "Authorization") ||
|
|
|
|
(name &= "Proxy-Authorization"))
|
|
|
|
header.append(new SIPAuthLine(name,*line));
|
|
|
|
else
|
|
|
|
header.append(new SIPHeaderLine(name,*line));
|
|
|
|
|
2004-12-28 14:50:10 +00:00
|
|
|
if (content.null() && (name &= "Content-Type")) {
|
2004-12-24 18:15:34 +00:00
|
|
|
content = *line;
|
|
|
|
content.toLower();
|
|
|
|
}
|
2006-05-23 17:47:24 +00:00
|
|
|
else if ((clen < 0) && (name &= "Content-Length"))
|
|
|
|
clen = line->toInteger(-1,10);
|
|
|
|
else if ((m_cseq < 0) && (name &= "CSeq")) {
|
2004-12-28 14:50:10 +00:00
|
|
|
String seq = *line;
|
|
|
|
seq >> m_cseq;
|
2004-12-31 01:09:21 +00:00
|
|
|
if (m_answer) {
|
|
|
|
seq.trimBlanks().toUpper();
|
|
|
|
method = seq;
|
|
|
|
}
|
2004-12-28 14:50:10 +00:00
|
|
|
}
|
2004-12-27 15:08:12 +00:00
|
|
|
line->destruct();
|
2004-12-24 18:15:34 +00:00
|
|
|
}
|
2006-05-23 17:47:24 +00:00
|
|
|
if (clen >= 0) {
|
|
|
|
if (clen > len)
|
|
|
|
Debug("SIPMessage",DebugMild,"Content length is %d but only %d in buffer",clen,len);
|
|
|
|
else if (clen < len) {
|
|
|
|
DDebug("SIPMessage",DebugInfo,"Got %d garbage bytes after content",len - clen);
|
|
|
|
len = clen;
|
|
|
|
}
|
|
|
|
}
|
2007-07-26 23:47:29 +00:00
|
|
|
body = MimeBody::build(buf,len,content);
|
2005-05-07 23:47:37 +00:00
|
|
|
DDebug(DebugAll,"SIPMessage::parse %d header lines, body %p",
|
2004-12-24 18:15:34 +00:00
|
|
|
header.count(),body);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2005-05-31 22:18:38 +00:00
|
|
|
SIPMessage* SIPMessage::fromParsing(SIPParty* ep, const char* buf, int len)
|
2004-12-24 18:15:34 +00:00
|
|
|
{
|
|
|
|
SIPMessage* msg = new SIPMessage(ep,buf,len);
|
|
|
|
if (msg->isValid())
|
|
|
|
return msg;
|
2005-05-06 18:13:33 +00:00
|
|
|
DDebug("SIPMessage",DebugInfo,"Invalid message");
|
2004-12-24 18:15:34 +00:00
|
|
|
msg->destruct();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-05-02 18:31:05 +00:00
|
|
|
const SIPHeaderLine* SIPMessage::getHeader(const char* name) const
|
2004-12-28 05:15:11 +00:00
|
|
|
{
|
|
|
|
if (!(name && *name))
|
|
|
|
return 0;
|
|
|
|
const ObjList* l = &header;
|
|
|
|
for (; l; l = l->next()) {
|
2005-05-02 18:31:05 +00:00
|
|
|
const SIPHeaderLine* t = static_cast<const SIPHeaderLine*>(l->get());
|
2004-12-28 05:15:11 +00:00
|
|
|
if (t && (t->name() &= name))
|
|
|
|
return t;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-05-02 18:31:05 +00:00
|
|
|
const SIPHeaderLine* SIPMessage::getLastHeader(const char* name) const
|
2004-12-29 04:02:55 +00:00
|
|
|
{
|
|
|
|
if (!(name && *name))
|
|
|
|
return 0;
|
2005-05-02 18:31:05 +00:00
|
|
|
const SIPHeaderLine* res = 0;
|
2004-12-29 04:02:55 +00:00
|
|
|
const ObjList* l = &header;
|
|
|
|
for (; l; l = l->next()) {
|
2005-05-02 18:31:05 +00:00
|
|
|
const SIPHeaderLine* t = static_cast<const SIPHeaderLine*>(l->get());
|
2004-12-29 04:02:55 +00:00
|
|
|
if (t && (t->name() &= name))
|
|
|
|
res = t;
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2005-05-14 20:03:38 +00:00
|
|
|
void SIPMessage::clearHeaders(const char* name)
|
|
|
|
{
|
|
|
|
if (!(name && *name))
|
|
|
|
return;
|
|
|
|
ObjList* l = &header;
|
|
|
|
while (l) {
|
|
|
|
const SIPHeaderLine* t = static_cast<const SIPHeaderLine*>(l->get());
|
|
|
|
if (t && (t->name() &= name))
|
|
|
|
l->remove();
|
|
|
|
else
|
|
|
|
l = l->next();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-12-29 04:02:55 +00:00
|
|
|
int SIPMessage::countHeaders(const char* name) const
|
|
|
|
{
|
|
|
|
if (!(name && *name))
|
|
|
|
return 0;
|
|
|
|
int res = 0;
|
|
|
|
const ObjList* l = &header;
|
|
|
|
for (; l; l = l->next()) {
|
2005-05-02 18:31:05 +00:00
|
|
|
const SIPHeaderLine* t = static_cast<const SIPHeaderLine*>(l->get());
|
2004-12-29 04:02:55 +00:00
|
|
|
if (t && (t->name() &= name))
|
|
|
|
++res;
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2004-12-28 05:15:11 +00:00
|
|
|
const NamedString* SIPMessage::getParam(const char* name, const char* param) const
|
|
|
|
{
|
2005-05-02 18:31:05 +00:00
|
|
|
const SIPHeaderLine* hl = getHeader(name);
|
2004-12-28 05:15:11 +00:00
|
|
|
return hl ? hl->getParam(param) : 0;
|
|
|
|
}
|
|
|
|
|
2005-01-01 22:21:32 +00:00
|
|
|
const String& SIPMessage::getHeaderValue(const char* name) const
|
|
|
|
{
|
2005-05-02 18:31:05 +00:00
|
|
|
const SIPHeaderLine* hl = getHeader(name);
|
2005-05-11 20:37:14 +00:00
|
|
|
return hl ? *static_cast<const String*>(hl) : String::empty();
|
2005-01-01 22:21:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const String& SIPMessage::getParamValue(const char* name, const char* param) const
|
|
|
|
{
|
|
|
|
const NamedString* ns = getParam(name,param);
|
2005-05-11 20:37:14 +00:00
|
|
|
return ns ? *static_cast<const String*>(ns) : String::empty();
|
2005-01-01 22:21:32 +00:00
|
|
|
}
|
|
|
|
|
2004-12-24 18:15:34 +00:00
|
|
|
const String& SIPMessage::getHeaders() const
|
|
|
|
{
|
|
|
|
if (isValid() && m_string.null()) {
|
|
|
|
if (isAnswer())
|
|
|
|
m_string << version << " " << code << " " << reason << "\r\n";
|
|
|
|
else
|
|
|
|
m_string << method << " " << uri << " " << version << "\r\n";
|
|
|
|
|
|
|
|
const ObjList* l = &header;
|
|
|
|
for (; l; l = l->next()) {
|
2005-05-02 18:31:05 +00:00
|
|
|
SIPHeaderLine* t = static_cast<SIPHeaderLine*>(l->get());
|
2004-12-28 05:15:11 +00:00
|
|
|
if (t) {
|
2005-06-03 12:23:12 +00:00
|
|
|
t->buildLine(m_string);
|
2004-12-28 05:15:11 +00:00
|
|
|
m_string << "\r\n";
|
|
|
|
}
|
2004-12-24 18:15:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return m_string;
|
|
|
|
}
|
|
|
|
|
|
|
|
const DataBlock& SIPMessage::getBuffer() const
|
|
|
|
{
|
|
|
|
if (isValid() && m_data.null()) {
|
|
|
|
m_data.assign((void*)(getHeaders().c_str()),getHeaders().length());
|
2004-12-28 05:15:11 +00:00
|
|
|
if (body) {
|
|
|
|
String s;
|
|
|
|
s << "Content-Type: " << body->getType() << "\r\n";
|
|
|
|
s << "Content-Length: " << body->getBody().length() << "\r\n\r\n";
|
|
|
|
m_data += s;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
m_data += "Content-Length: 0\r\n\r\n";
|
2004-12-24 18:15:34 +00:00
|
|
|
if (body)
|
|
|
|
m_data += body->getBody();
|
2005-09-06 02:51:09 +00:00
|
|
|
#ifdef DEBUG
|
|
|
|
if (debugAt(DebugInfo)) {
|
|
|
|
String buf((char*)m_data.data(),m_data.length());
|
|
|
|
Debug(DebugInfo,"SIPMessage::getBuffer() [%p]\n------\n%s------",
|
|
|
|
this,buf.c_str());
|
|
|
|
}
|
|
|
|
#endif
|
2004-12-24 18:15:34 +00:00
|
|
|
}
|
|
|
|
return m_data;
|
|
|
|
}
|
|
|
|
|
2007-07-26 23:47:29 +00:00
|
|
|
void SIPMessage::setBody(MimeBody* newbody)
|
2004-12-28 05:47:43 +00:00
|
|
|
{
|
|
|
|
if (newbody == body)
|
|
|
|
return;
|
2007-05-15 15:40:50 +00:00
|
|
|
TelEngine::destruct(body);
|
2004-12-28 05:47:43 +00:00
|
|
|
body = newbody;
|
|
|
|
}
|
|
|
|
|
2004-12-29 04:02:55 +00:00
|
|
|
void SIPMessage::setParty(SIPParty* ep)
|
|
|
|
{
|
|
|
|
if (ep == m_ep)
|
|
|
|
return;
|
|
|
|
if (m_ep)
|
|
|
|
m_ep->deref();
|
|
|
|
m_ep = ep;
|
|
|
|
if (m_ep)
|
|
|
|
m_ep->ref();
|
|
|
|
}
|
|
|
|
|
2005-06-12 18:58:17 +00:00
|
|
|
SIPAuthLine* SIPMessage::buildAuth(const String& username, const String& password,
|
|
|
|
const String& meth, const String& uri, bool proxy) const
|
|
|
|
{
|
|
|
|
const char* hdr = proxy ? "Proxy-Authenticate" : "WWW-Authenticate";
|
|
|
|
const ObjList* l = &header;
|
|
|
|
for (; l; l = l->next()) {
|
|
|
|
const SIPAuthLine* t = YOBJECT(SIPAuthLine,l->get());
|
|
|
|
if (t && (t->name() &= hdr) && (*t &= "Digest")) {
|
|
|
|
String nonce(t->getParam("nonce"));
|
|
|
|
delQuotes(nonce);
|
|
|
|
if (nonce.null())
|
|
|
|
continue;
|
|
|
|
String realm(t->getParam("realm"));
|
|
|
|
delQuotes(realm);
|
|
|
|
int par = uri.find(';');
|
|
|
|
String msguri = uri.substr(0,par);
|
|
|
|
String response;
|
|
|
|
SIPEngine::buildAuth(username,realm,password,nonce,meth,msguri,response);
|
|
|
|
SIPAuthLine* auth = new SIPAuthLine(proxy ? "Proxy-Authorization" : "Authorization","Digest");
|
|
|
|
auth->setParam("username",quote(username));
|
|
|
|
auth->setParam("realm",quote(realm));
|
|
|
|
auth->setParam("nonce",quote(nonce));
|
|
|
|
auth->setParam("uri",quote(msguri));
|
|
|
|
auth->setParam("response",quote(response));
|
|
|
|
auth->setParam("algorithm","MD5");
|
2006-10-13 11:30:13 +00:00
|
|
|
// copy opaque data as-is, only if present
|
|
|
|
const NamedString* opaque = t->getParam("opaque");
|
|
|
|
if (opaque)
|
|
|
|
auth->setParam(opaque->name(),*opaque);
|
2005-06-12 18:58:17 +00:00
|
|
|
return auth;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-10-28 03:10:32 +00:00
|
|
|
SIPAuthLine* SIPMessage::buildAuth(const SIPMessage& original) const
|
|
|
|
{
|
|
|
|
if (original.getAuthUsername().null())
|
|
|
|
return 0;
|
|
|
|
return buildAuth(original.getAuthUsername(),original.getAuthPassword(),
|
|
|
|
original.method,original.uri,(code == 407));
|
|
|
|
}
|
|
|
|
|
2005-06-13 15:01:15 +00:00
|
|
|
ObjList* SIPMessage::getRoutes() const
|
|
|
|
{
|
|
|
|
ObjList* list = 0;
|
|
|
|
const ObjList* l = &header;
|
|
|
|
for (; l; l = l->next()) {
|
|
|
|
const SIPHeaderLine* h = YOBJECT(SIPHeaderLine,l->get());
|
|
|
|
if (h && (h->name() &= "Record-Route")) {
|
2006-07-25 22:23:54 +00:00
|
|
|
int p = 0;
|
|
|
|
while (p >= 0) {
|
|
|
|
SIPHeaderLine* line = 0;
|
|
|
|
int s = findSep(*h,',',p);
|
|
|
|
String tmp;
|
|
|
|
if (s < 0) {
|
|
|
|
if (p)
|
|
|
|
tmp = h->substr(p);
|
|
|
|
else
|
|
|
|
line = new SIPHeaderLine(*h,"Route");
|
|
|
|
p = -1;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (s > p)
|
|
|
|
tmp = h->substr(p,s-p);
|
|
|
|
p = s + 1;
|
|
|
|
}
|
|
|
|
tmp.trimBlanks();
|
|
|
|
if (tmp)
|
|
|
|
line = new SIPHeaderLine("Route",tmp);
|
|
|
|
if (!line)
|
|
|
|
continue;
|
|
|
|
if (!list)
|
|
|
|
list = new ObjList;
|
|
|
|
if (isAnswer())
|
2007-02-05 19:19:29 +00:00
|
|
|
// route set learned from an answer, reverse order
|
2006-07-25 22:23:54 +00:00
|
|
|
list->insert(line);
|
2007-02-05 19:19:29 +00:00
|
|
|
else
|
|
|
|
// route set learned from a request, preserve order
|
|
|
|
list->append(line);
|
2006-07-25 22:23:54 +00:00
|
|
|
}
|
2005-06-13 15:01:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return list;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SIPMessage::addRoutes(const ObjList* routes)
|
|
|
|
{
|
2006-07-25 22:23:54 +00:00
|
|
|
if (isAnswer() || !routes)
|
|
|
|
return;
|
|
|
|
SIPHeaderLine* hl = YOBJECT(SIPHeaderLine,routes->get());
|
|
|
|
if (hl) {
|
|
|
|
// check if first route is to a RFC 2543 proxy
|
|
|
|
String tmp = *hl;
|
|
|
|
Regexp r("<\\([^>]\\+\\)>");
|
|
|
|
if (tmp.matches(r))
|
|
|
|
tmp = tmp.matchString(1);
|
|
|
|
if (tmp.find(";lr") < 0) {
|
|
|
|
// prepare a new final route
|
|
|
|
hl = new SIPHeaderLine("Route","<" + uri + ">");
|
|
|
|
// set the first route as Request-URI and then skip it
|
|
|
|
uri = tmp;
|
|
|
|
routes = routes->next();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
hl = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// add (remaining) routes
|
2005-06-13 15:01:15 +00:00
|
|
|
for (; routes; routes = routes->next()) {
|
|
|
|
const SIPHeaderLine* h = YOBJECT(SIPHeaderLine,routes->get());
|
|
|
|
if (h)
|
|
|
|
addHeader(h->clone());
|
|
|
|
}
|
2006-07-25 22:23:54 +00:00
|
|
|
|
|
|
|
// if first route was to a RFC 2543 proxy add the old Request-URI
|
|
|
|
if (hl)
|
|
|
|
addHeader(hl);
|
2005-06-13 15:01:15 +00:00
|
|
|
}
|
|
|
|
|
2005-01-04 02:22:43 +00:00
|
|
|
SIPDialog::SIPDialog()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
SIPDialog::SIPDialog(const SIPDialog& original)
|
|
|
|
: String(original),
|
|
|
|
localURI(original.localURI), localTag(original.localTag),
|
|
|
|
remoteURI(original.remoteURI), remoteTag(original.remoteTag)
|
|
|
|
{
|
2005-05-06 18:13:33 +00:00
|
|
|
DDebug("SIPDialog",DebugAll,"callid '%s' local '%s;tag=%s' remote '%s;tag=%s' [%p]",
|
2005-01-04 02:22:43 +00:00
|
|
|
c_str(),localURI.c_str(),localTag.c_str(),remoteURI.c_str(),remoteTag.c_str(),this);
|
|
|
|
}
|
|
|
|
|
|
|
|
SIPDialog& SIPDialog::operator=(const SIPDialog& original)
|
|
|
|
{
|
|
|
|
String::operator=(original);
|
|
|
|
localURI = original.localURI;
|
|
|
|
localTag = original.localTag;
|
|
|
|
remoteURI = original.remoteURI;
|
|
|
|
remoteTag = original.remoteTag;
|
2005-05-06 18:13:33 +00:00
|
|
|
DDebug("SIPDialog",DebugAll,"callid '%s' local '%s;tag=%s' remote '%s;tag=%s' [%p]",
|
2005-01-04 02:22:43 +00:00
|
|
|
c_str(),localURI.c_str(),localTag.c_str(),remoteURI.c_str(),remoteTag.c_str(),this);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
SIPDialog& SIPDialog::operator=(const String& callid)
|
|
|
|
{
|
|
|
|
String::operator=(callid);
|
|
|
|
localURI.clear();
|
|
|
|
localTag.clear();
|
|
|
|
remoteURI.clear();
|
|
|
|
remoteTag.clear();
|
2005-05-06 18:13:33 +00:00
|
|
|
DDebug("SIPDialog",DebugAll,"callid '%s' local '%s;tag=%s' remote '%s;tag=%s' [%p]",
|
2005-01-04 02:22:43 +00:00
|
|
|
c_str(),localURI.c_str(),localTag.c_str(),remoteURI.c_str(),remoteTag.c_str(),this);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
SIPDialog::SIPDialog(const SIPMessage& message)
|
|
|
|
: String(message.getHeaderValue("Call-ID"))
|
|
|
|
{
|
|
|
|
Regexp r("<\\([^>]\\+\\)>");
|
|
|
|
bool local = message.isOutgoing() ^ message.isAnswer();
|
2005-05-02 18:31:05 +00:00
|
|
|
const SIPHeaderLine* hl = message.getHeader(local ? "From" : "To");
|
2005-01-04 02:22:43 +00:00
|
|
|
localURI = hl;
|
|
|
|
if (localURI.matches(r))
|
|
|
|
localURI = localURI.matchString(1);
|
|
|
|
if (hl)
|
|
|
|
localTag = hl->getParam("tag");
|
|
|
|
hl = message.getHeader(local ? "To" : "From");
|
|
|
|
remoteURI = hl;
|
|
|
|
if (remoteURI.matches(r))
|
|
|
|
remoteURI = remoteURI.matchString(1);
|
|
|
|
if (hl)
|
|
|
|
remoteTag = hl->getParam("tag");
|
2005-05-06 18:13:33 +00:00
|
|
|
DDebug("SIPDialog",DebugAll,"callid '%s' local '%s;tag=%s' remote '%s;tag=%s' [%p]",
|
2005-01-04 02:22:43 +00:00
|
|
|
c_str(),localURI.c_str(),localTag.c_str(),remoteURI.c_str(),remoteTag.c_str(),this);
|
|
|
|
}
|
|
|
|
|
|
|
|
SIPDialog& SIPDialog::operator=(const SIPMessage& message)
|
|
|
|
{
|
2005-05-11 20:37:14 +00:00
|
|
|
const char* cid = message.getHeaderValue("Call-ID");
|
|
|
|
if (cid)
|
|
|
|
String::operator=(cid);
|
2005-01-04 02:22:43 +00:00
|
|
|
Regexp r("<\\([^>]\\+\\)>");
|
|
|
|
bool local = message.isOutgoing() ^ message.isAnswer();
|
2005-05-02 18:31:05 +00:00
|
|
|
const SIPHeaderLine* hl = message.getHeader(local ? "From" : "To");
|
2005-01-04 02:22:43 +00:00
|
|
|
localURI = hl;
|
|
|
|
if (localURI.matches(r))
|
|
|
|
localURI = localURI.matchString(1);
|
|
|
|
if (hl)
|
|
|
|
localTag = hl->getParam("tag");
|
|
|
|
hl = message.getHeader(local ? "To" : "From");
|
|
|
|
remoteURI = hl;
|
|
|
|
if (remoteURI.matches(r))
|
|
|
|
remoteURI = remoteURI.matchString(1);
|
|
|
|
if (hl)
|
|
|
|
remoteTag = hl->getParam("tag");
|
2005-05-06 18:13:33 +00:00
|
|
|
DDebug("SIPDialog",DebugAll,"callid '%s' local '%s;tag=%s' remote '%s;tag=%s' [%p]",
|
2005-01-04 02:22:43 +00:00
|
|
|
c_str(),localURI.c_str(),localTag.c_str(),remoteURI.c_str(),remoteTag.c_str(),this);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SIPDialog::operator==(const SIPDialog& other) const
|
|
|
|
{
|
|
|
|
return
|
|
|
|
String::operator==(other) &&
|
|
|
|
localURI == other.localURI &&
|
|
|
|
localTag == other.localTag &&
|
|
|
|
remoteURI == other.remoteURI &&
|
|
|
|
remoteTag == other.remoteTag;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SIPDialog::operator!=(const SIPDialog& other) const
|
|
|
|
{
|
|
|
|
return !operator==(other);
|
|
|
|
}
|
|
|
|
|
2004-12-24 18:15:34 +00:00
|
|
|
/* vi: set ts=8 sw=4 sts=4 noet: */
|