From 648b9c82b156d35213566fbc821bc714048888c8 Mon Sep 17 00:00:00 2001 From: marian Date: Tue, 8 Jan 2008 12:29:12 +0000 Subject: [PATCH] Moved header classes and some utilities from SIP to MIME. Updated SIP module and library to reflect the changes. git-svn-id: http://voip.null.ro/svn/yate@1599 acf43c95-373e-0410-b603-e72c3f656dc1 --- engine/Mime.cpp | 269 ++++++++++++++++++++++++++++++++++- libs/ysip/engine.cpp | 14 +- libs/ysip/message.cpp | 292 +++++++------------------------------- libs/ysip/transaction.cpp | 6 +- libs/ysip/util.cpp | 62 -------- libs/ysip/util.h | 12 -- libs/ysip/yatesip.h | 49 ++----- modules/ysipchan.cpp | 56 ++++---- yatemime.h | 189 ++++++++++++++++++++++-- 9 files changed, 543 insertions(+), 406 deletions(-) diff --git a/engine/Mime.cpp b/engine/Mime.cpp index bd1c3fc0..5f58e2b0 100644 --- a/engine/Mime.cpp +++ b/engine/Mime.cpp @@ -30,10 +30,277 @@ static bool isContinuationBlank(char c) return ((c == ' ') || (c == '\t')); } +/** + * MimeHeaderLine + */ +MimeHeaderLine::MimeHeaderLine(const char* name, const String& value, char sep) + : NamedString(name), m_separator(sep ? sep : ';') +{ + if (value.null()) + return; + XDebug(DebugAll,"MimeHeaderLine::MimeHeaderLine('%s','%s') [%p]",name,value.c_str(),this); + int sp = findSep(value,m_separator); + if (sp < 0) { + assign(value); + return; + } + assign(value,sp); + trimBlanks(); + while (sp < (int)value.length()) { + int ep = findSep(value,m_separator,sp+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,"hdr 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,"hdr param name='%s' (no value)",pname.c_str()); + m_params.append(new NamedString(pname)); + } + } + sp = ep; + } +} + +MimeHeaderLine::MimeHeaderLine(const MimeHeaderLine& original, const char* newName) + : NamedString(newName ? newName : original.name().c_str(),original), + m_separator(original.separator()) +{ + XDebug(DebugAll,"MimeHeaderLine::MimeHeaderLine(%p '%s') [%p]",&original,name().c_str(),this); + const ObjList* l = &original.params(); + for (; l; l = l->next()) { + const NamedString* t = static_cast(l->get()); + if (t) + m_params.append(new NamedString(t->name(),*t)); + } +} + +MimeHeaderLine::~MimeHeaderLine() +{ + XDebug(DebugAll,"MimeHeaderLine::~MimeHeaderLine() [%p]",this); +} + +void* MimeHeaderLine::getObject(const String& name) const +{ + if (name == "MimeHeaderLine") + return const_cast(this); + return NamedString::getObject(name); +} + +MimeHeaderLine* MimeHeaderLine::clone(const char* newName) const +{ + return new MimeHeaderLine(*this,newName); +} + +void MimeHeaderLine::buildLine(String& line) const +{ + line << name() << ": " << *this; + const ObjList* p = &m_params; + for (; p; p = p->next()) { + NamedString* s = static_cast(p->get()); + if (s) { + line << separator() << s->name(); + if (!s->null()) + line << "=" << *s; + } + } +} + +const NamedString* MimeHeaderLine::getParam(const char* name) const +{ + if (!(name && *name)) + return 0; + const ObjList* l = &m_params; + for (; l; l = l->next()) { + const NamedString* t = static_cast(l->get()); + if (t && (t->name() &= name)) + return t; + } + return 0; +} + +void MimeHeaderLine::setParam(const char* name, const char* value) +{ + ObjList* p = m_params.find(name); + if (p) + *static_cast(p->get()) = value; + else + m_params.append(new NamedString(name,value)); +} + +void MimeHeaderLine::delParam(const char* name) +{ + ObjList* p = m_params.find(name); + if (p) + p->remove(); +} + +// Utility function, puts quotes around a string +void MimeHeaderLine::addQuotes(String& str) +{ + str.trimBlanks(); + int l = str.length(); + if ((l < 2) || (str[0] != '"') || (str[l-1] != '"')) + str = "\"" + str + "\""; +} + +// Utility function, removes quotes around a string +void MimeHeaderLine::delQuotes(String& str) +{ + str.trimBlanks(); + int l = str.length(); + if ((l >= 2) && (str[0] == '"') && (str[l-1] == '"')) { + str = str.substr(1,l-2); + str.trimBlanks(); + } +} + +// Utility function, puts quotes around a string +String MimeHeaderLine::quote(const String& str) +{ + String tmp(str); + addQuotes(tmp); + return tmp; +} + +// Utility function to find a separator not in "quotes" or inside +int MimeHeaderLine::findSep(const char* str, char sep, int offs) +{ + if (!(str && sep)) + return -1; + str += offs; + bool inQ = false; + bool inU = false; + char c; + for (; (c = *str++) ; offs++) { + if (inQ) { + if (c == '"') + inQ = false; + continue; + } + if (inU) { + if (c == '>') + inU = false; + continue; + } + if (c == sep) + return offs; + switch (c) { + case '"': + inQ = true; + break; + case '<': + inU = true; + break; + } + } + return -1; +} + + +/** + * MimeAuthLine + */ +MimeAuthLine::MimeAuthLine(const char* name, const String& value) + : MimeHeaderLine(name,String::empty(),',') +{ + XDebug(DebugAll,"MimeAuthLine::MimeAuthLine('%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; + } +} + +MimeAuthLine::MimeAuthLine(const MimeAuthLine& original, const char* newName) + : MimeHeaderLine(original,newName) +{ +} + +void* MimeAuthLine::getObject(const String& name) const +{ + if (name == "MimeAuthLine") + return const_cast(this); + return MimeHeaderLine::getObject(name); +} + +MimeHeaderLine* MimeAuthLine::clone(const char* newName) const +{ + return new MimeAuthLine(*this,newName); +} + +void MimeAuthLine::buildLine(String& line) const +{ + line << name() << ": " << *this; + const ObjList* p = &m_params; + for (bool first = true; p; p = p->next()) { + NamedString* s = static_cast(p->get()); + if (s) { + if (first) + first = false; + else + line << separator(); + line << " " << s->name(); + if (!s->null()) + line << "=" << *s; + } + } +} + + +/** + * MimeBody + */ YCLASSIMP(MimeBody,GenObject) MimeBody::MimeBody(const String& type) - : m_type(type) + : m_type("Content-Type",type) { DDebug(DebugAll,"MimeBody::MimeBody('%s') [%p]",m_type.c_str(),this); } diff --git a/libs/ysip/engine.cpp b/libs/ysip/engine.cpp index fbe43905..4e60110a 100644 --- a/libs/ysip/engine.cpp +++ b/libs/ysip/engine.cpp @@ -192,7 +192,7 @@ SIPTransaction* SIPEngine::addMessage(SIPMessage* message) if (message->isOutgoing()) message->complete(this); // locate the branch parameter of last Via header - added by the UA - const SIPHeaderLine* hl = message->getLastHeader("Via"); + const MimeHeaderLine* hl = message->getLastHeader("Via"); if (!hl) #ifdef SIP_STRICT return 0; @@ -465,10 +465,10 @@ int SIPEngine::authUser(const SIPMessage* message, String& user, bool proxy, Gen const ObjList* l = &message->header; for (; l; l = l->next()) { const GenObject* o = l->get(); - const SIPHeaderLine* t = o ? static_cast(o->getObject("SIPHeaderLine")) : 0; + const MimeHeaderLine* t = o ? static_cast(o->getObject("MimeHeaderLine")) : 0; if (t && (t->name() &= hdr) && (*t &= "Digest")) { String usr(t->getParam("username")); - delQuotes(usr); + MimeHeaderLine::delQuotes(usr); if (usr.null()) continue; XDebug(this,DebugAll,"authUser found user '%s'",usr.c_str()); @@ -476,7 +476,7 @@ int SIPEngine::authUser(const SIPMessage* message, String& user, bool proxy, Gen if (user && (usr != user)) continue; String nonce(t->getParam("nonce")); - delQuotes(nonce); + MimeHeaderLine::delQuotes(nonce); // TODO: implement a nonce cache for the stupid clients that don't send it back if (nonce.null()) continue; @@ -487,15 +487,15 @@ int SIPEngine::authUser(const SIPMessage* message, String& user, bool proxy, Gen noUser = false; XDebug(this,DebugAll,"authUser nonce age is %ld",age); String res(t->getParam("response")); - delQuotes(res); + MimeHeaderLine::delQuotes(res); if (res.null()) continue; String uri(t->getParam("uri")); - delQuotes(uri); + MimeHeaderLine::delQuotes(uri); if (uri.null()) uri = message->uri; String realm(t->getParam("realm")); - delQuotes(realm); + MimeHeaderLine::delQuotes(realm); if (!checkUser(usr,realm,nonce,message->method,uri,res,message,userData)) continue; diff --git a/libs/ysip/message.cpp b/libs/ysip/message.cpp index a0eef978..35c81e9a 100644 --- a/libs/ysip/message.cpp +++ b/libs/ysip/message.cpp @@ -30,200 +30,6 @@ using namespace TelEngine; -SIPHeaderLine::SIPHeaderLine(const char* name, const String& value, char sep) - : NamedString(name), m_separator(sep ? sep : ';') -{ - if (value.null()) - return; - XDebug(DebugAll,"SIPHeaderLine::SIPHeaderLine('%s','%s') [%p]",name,value.c_str(),this); - int sp = findSep(value,m_separator); - if (sp < 0) { - assign(value); - return; - } - assign(value,sp); - trimBlanks(); - while (sp < (int)value.length()) { - int ep = findSep(value,m_separator,sp+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,"hdr 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,"hdr param name='%s' (no value)",pname.c_str()); - m_params.append(new NamedString(pname)); - } - } - sp = ep; - } -} - -SIPHeaderLine::SIPHeaderLine(const SIPHeaderLine& original, const char* newName) - : NamedString(newName ? newName : original.name().c_str(),original), - m_separator(original.separator()) -{ - XDebug(DebugAll,"SIPHeaderLine::SIPHeaderLine(%p '%s') [%p]",&original,name().c_str(),this); - const ObjList* l = &original.params(); - for (; l; l = l->next()) { - const NamedString* t = static_cast(l->get()); - if (t) - m_params.append(new NamedString(t->name(),*t)); - } -} - -SIPHeaderLine::~SIPHeaderLine() -{ - XDebug(DebugAll,"SIPHeaderLine::~SIPHeaderLine() [%p]",this); -} - -void* SIPHeaderLine::getObject(const String& name) const -{ - if (name == "SIPHeaderLine") - return const_cast(this); - return NamedString::getObject(name); -} - -SIPHeaderLine* SIPHeaderLine::clone(const char* newName) const -{ - return new SIPHeaderLine(*this,newName); -} - -void SIPHeaderLine::buildLine(String& line) const -{ - line << name() << ": " << *this; - const ObjList* p = &m_params; - for (; p; p = p->next()) { - NamedString* s = static_cast(p->get()); - if (s) { - line << separator() << s->name(); - if (!s->null()) - line << "=" << *s; - } - } -} - -const NamedString* SIPHeaderLine::getParam(const char* name) const -{ - if (!(name && *name)) - return 0; - const ObjList* l = &m_params; - for (; l; l = l->next()) { - const NamedString* t = static_cast(l->get()); - if (t && (t->name() &= name)) - return t; - } - return 0; -} - -void SIPHeaderLine::setParam(const char* name, const char* value) -{ - ObjList* p = m_params.find(name); - if (p) - *static_cast(p->get()) = value; - else - m_params.append(new NamedString(name,value)); -} - -void SIPHeaderLine::delParam(const char* name) -{ - ObjList* p = m_params.find(name); - if (p) - p->remove(); -} - -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; - } -} - -SIPAuthLine::SIPAuthLine(const SIPAuthLine& original, const char* newName) - : SIPHeaderLine(original,newName) -{ -} - -void* SIPAuthLine::getObject(const String& name) const -{ - if (name == "SIPAuthLine") - return const_cast(this); - return SIPHeaderLine::getObject(name); -} - -SIPHeaderLine* SIPAuthLine::clone(const char* newName) const -{ - return new SIPAuthLine(*this,newName); -} - -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(p->get()); - if (s) { - if (first) - first = false; - else - line << separator(); - line << " " << s->name(); - if (!s->null()) - line << "=" << *s; - } - } -} - SIPMessage::SIPMessage(const SIPMessage& original) : version(original.version), method(original.method), uri(original.uri), code(original.code), reason(original.reason), @@ -240,13 +46,13 @@ SIPMessage::SIPMessage(const SIPMessage& original) bool via1 = true; const ObjList* l = &original.header; for (; l; l = l->next()) { - const SIPHeaderLine* hl = static_cast(l->get()); + const MimeHeaderLine* hl = static_cast(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(); + MimeHeaderLine* nl = hl->clone(); // this is a new transaction so let complete() add randomness if (via1 && (nl->name() &= "Via")) { via1 = false; @@ -323,19 +129,19 @@ SIPMessage::SIPMessage(const SIPMessage* original, const SIPMessage* answer) version = original->version; uri = original->uri; copyAllHeaders(original,"Via"); - SIPHeaderLine* hl = const_cast(getHeader("Via")); + MimeHeaderLine* hl = const_cast(getHeader("Via")); if (!hl) { String tmp; tmp << version << "/" << getParty()->getProtoName(); tmp << " " << getParty()->getLocalAddr() << ":" << getParty()->getLocalPort(); - hl = new SIPHeaderLine("Via",tmp); + hl = new MimeHeaderLine("Via",tmp); header.append(hl); } if (answer && (answer->code == 200) && (original->method &= "INVITE")) { String tmp("z9hG4bK"); tmp << (int)::random(); hl->setParam("branch",tmp); - const SIPHeaderLine* co = answer->getHeader("Contact"); + const MimeHeaderLine* co = answer->getHeader("Contact"); if (co) { uri = *co; Regexp r("^[^<]*<\\([^>]*\\)>.*$"); @@ -397,7 +203,7 @@ void SIPMessage::complete(SIPEngine* engine, const char* user, const char* domai // only set the dialog tag on ACK if (isACK()) { - SIPHeaderLine* hl = const_cast(getHeader("To")); + MimeHeaderLine* hl = const_cast(getHeader("To")); if (dlgTag && hl && !hl->getParam("tag")) hl->setParam("tag",dlgTag); return; @@ -406,12 +212,12 @@ void SIPMessage::complete(SIPEngine* engine, const char* user, const char* domai if (!domain) domain = getParty()->getLocalAddr(); - SIPHeaderLine* hl = const_cast(getHeader("Via")); + MimeHeaderLine* hl = const_cast(getHeader("Via")); if (!hl) { String tmp; tmp << version << "/" << getParty()->getProtoName(); tmp << " " << getParty()->getLocalAddr() << ":" << getParty()->getLocalPort(); - hl = new SIPHeaderLine("Via",tmp); + hl = new MimeHeaderLine("Via",tmp); if (!(isAnswer() || isACK())) hl->setParam("rport"); header.append(hl); @@ -427,24 +233,24 @@ void SIPMessage::complete(SIPEngine* engine, const char* user, const char* domai } if (!isAnswer()) { - hl = const_cast(getHeader("From")); + hl = const_cast(getHeader("From")); if (!hl) { String tmp = ""; - hl = new SIPHeaderLine("From",tmp); + hl = new MimeHeaderLine("From",tmp); header.append(hl); } if (!hl->getParam("tag")) hl->setParam("tag",String((int)::random())); } - hl = const_cast(getHeader("To")); + hl = const_cast(getHeader("To")); if (!(isAnswer() || hl)) { String tmp; tmp << "<" << uri << ">"; - hl = new SIPHeaderLine("To",tmp); + hl = new MimeHeaderLine("To",tmp); header.append(hl); } if (hl && dlgTag && !hl->getParam("tag")) @@ -499,7 +305,7 @@ void SIPMessage::complete(SIPEngine* engine, const char* user, const char* domai bool SIPMessage::copyHeader(const SIPMessage* message, const char* name, const char* newName) { - const SIPHeaderLine* hl = message ? message->getHeader(name) : 0; + const MimeHeaderLine* hl = message ? message->getHeader(name) : 0; if (hl) { header.append(hl->clone(newName)); return true; @@ -514,7 +320,7 @@ int SIPMessage::copyAllHeaders(const SIPMessage* message, const char* name, cons int c = 0; const ObjList* l = &message->header; for (; l; l = l->next()) { - const SIPHeaderLine* hl = static_cast(l->get()); + const MimeHeaderLine* hl = static_cast(l->get()); if (hl && (hl->name() &= name)) { ++c; header.append(hl->clone(newName)); @@ -606,9 +412,9 @@ bool SIPMessage::parse(const char* buf, int len) (name &= "Proxy-Authenticate") || (name &= "Authorization") || (name &= "Proxy-Authorization")) - header.append(new SIPAuthLine(name,*line)); + header.append(new MimeAuthLine(name,*line)); else - header.append(new SIPHeaderLine(name,*line)); + header.append(new MimeHeaderLine(name,*line)); if (content.null() && (name &= "Content-Type")) { content = *line; @@ -650,27 +456,27 @@ SIPMessage* SIPMessage::fromParsing(SIPParty* ep, const char* buf, int len) return 0; } -const SIPHeaderLine* SIPMessage::getHeader(const char* name) const +const MimeHeaderLine* SIPMessage::getHeader(const char* name) const { if (!(name && *name)) return 0; const ObjList* l = &header; for (; l; l = l->next()) { - const SIPHeaderLine* t = static_cast(l->get()); + const MimeHeaderLine* t = static_cast(l->get()); if (t && (t->name() &= name)) return t; } return 0; } -const SIPHeaderLine* SIPMessage::getLastHeader(const char* name) const +const MimeHeaderLine* SIPMessage::getLastHeader(const char* name) const { if (!(name && *name)) return 0; - const SIPHeaderLine* res = 0; + const MimeHeaderLine* res = 0; const ObjList* l = &header; for (; l; l = l->next()) { - const SIPHeaderLine* t = static_cast(l->get()); + const MimeHeaderLine* t = static_cast(l->get()); if (t && (t->name() &= name)) res = t; } @@ -683,7 +489,7 @@ void SIPMessage::clearHeaders(const char* name) return; ObjList* l = &header; while (l) { - const SIPHeaderLine* t = static_cast(l->get()); + const MimeHeaderLine* t = static_cast(l->get()); if (t && (t->name() &= name)) l->remove(); else @@ -698,7 +504,7 @@ int SIPMessage::countHeaders(const char* name) const int res = 0; const ObjList* l = &header; for (; l; l = l->next()) { - const SIPHeaderLine* t = static_cast(l->get()); + const MimeHeaderLine* t = static_cast(l->get()); if (t && (t->name() &= name)) ++res; } @@ -707,13 +513,13 @@ int SIPMessage::countHeaders(const char* name) const const NamedString* SIPMessage::getParam(const char* name, const char* param) const { - const SIPHeaderLine* hl = getHeader(name); + const MimeHeaderLine* hl = getHeader(name); return hl ? hl->getParam(param) : 0; } const String& SIPMessage::getHeaderValue(const char* name) const { - const SIPHeaderLine* hl = getHeader(name); + const MimeHeaderLine* hl = getHeader(name); return hl ? *static_cast(hl) : String::empty(); } @@ -733,7 +539,7 @@ const String& SIPMessage::getHeaders() const const ObjList* l = &header; for (; l; l = l->next()) { - SIPHeaderLine* t = static_cast(l->get()); + MimeHeaderLine* t = static_cast(l->get()); if (t) { t->buildLine(m_string); m_string << "\r\n"; @@ -749,8 +555,8 @@ const DataBlock& SIPMessage::getBuffer() const m_data.assign((void*)(getHeaders().c_str()),getHeaders().length()); if (body) { String s; - s << "Content-Type: " << body->getType() << "\r\n"; - s << "Content-Length: " << body->getBody().length() << "\r\n\r\n"; + body->getType().buildLine(s); + s << "\r\nContent-Length: " << body->getBody().length() << "\r\n\r\n"; m_data += s; } else @@ -787,30 +593,30 @@ void SIPMessage::setParty(SIPParty* ep) m_ep->ref(); } -SIPAuthLine* SIPMessage::buildAuth(const String& username, const String& password, +MimeAuthLine* 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()); + const MimeAuthLine* t = YOBJECT(MimeAuthLine,l->get()); if (t && (t->name() &= hdr) && (*t &= "Digest")) { String nonce(t->getParam("nonce")); - delQuotes(nonce); + MimeHeaderLine::delQuotes(nonce); if (nonce.null()) continue; String realm(t->getParam("realm")); - delQuotes(realm); + MimeHeaderLine::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)); + MimeAuthLine* auth = new MimeAuthLine(proxy ? "Proxy-Authorization" : "Authorization","Digest"); + auth->setParam("username",MimeHeaderLine::quote(username)); + auth->setParam("realm",MimeHeaderLine::quote(realm)); + auth->setParam("nonce",MimeHeaderLine::quote(nonce)); + auth->setParam("uri",MimeHeaderLine::quote(msguri)); + auth->setParam("response",MimeHeaderLine::quote(response)); auth->setParam("algorithm","MD5"); // copy opaque data as-is, only if present const NamedString* opaque = t->getParam("opaque"); @@ -822,7 +628,7 @@ SIPAuthLine* SIPMessage::buildAuth(const String& username, const String& passwor return 0; } -SIPAuthLine* SIPMessage::buildAuth(const SIPMessage& original) const +MimeAuthLine* SIPMessage::buildAuth(const SIPMessage& original) const { if (original.getAuthUsername().null()) return 0; @@ -835,18 +641,18 @@ ObjList* SIPMessage::getRoutes() const ObjList* list = 0; const ObjList* l = &header; for (; l; l = l->next()) { - const SIPHeaderLine* h = YOBJECT(SIPHeaderLine,l->get()); + const MimeHeaderLine* h = YOBJECT(MimeHeaderLine,l->get()); if (h && (h->name() &= "Record-Route")) { int p = 0; while (p >= 0) { - SIPHeaderLine* line = 0; - int s = findSep(*h,',',p); + MimeHeaderLine* line = 0; + int s = MimeHeaderLine::findSep(*h,',',p); String tmp; if (s < 0) { if (p) tmp = h->substr(p); else - line = new SIPHeaderLine(*h,"Route"); + line = new MimeHeaderLine(*h,"Route"); p = -1; } else { @@ -856,7 +662,7 @@ ObjList* SIPMessage::getRoutes() const } tmp.trimBlanks(); if (tmp) - line = new SIPHeaderLine("Route",tmp); + line = new MimeHeaderLine("Route",tmp); if (!line) continue; if (!list) @@ -877,7 +683,7 @@ void SIPMessage::addRoutes(const ObjList* routes) { if (isAnswer() || !routes) return; - SIPHeaderLine* hl = YOBJECT(SIPHeaderLine,routes->get()); + MimeHeaderLine* hl = YOBJECT(MimeHeaderLine,routes->get()); if (hl) { // check if first route is to a RFC 2543 proxy String tmp = *hl; @@ -886,7 +692,7 @@ void SIPMessage::addRoutes(const ObjList* routes) tmp = tmp.matchString(1); if (tmp.find(";lr") < 0) { // prepare a new final route - hl = new SIPHeaderLine("Route","<" + uri + ">"); + hl = new MimeHeaderLine("Route","<" + uri + ">"); // set the first route as Request-URI and then skip it uri = tmp; routes = routes->next(); @@ -897,7 +703,7 @@ void SIPMessage::addRoutes(const ObjList* routes) // add (remaining) routes for (; routes; routes = routes->next()) { - const SIPHeaderLine* h = YOBJECT(SIPHeaderLine,routes->get()); + const MimeHeaderLine* h = YOBJECT(MimeHeaderLine,routes->get()); if (h) addHeader(h->clone()); } @@ -949,7 +755,7 @@ SIPDialog::SIPDialog(const SIPMessage& message) { Regexp r("<\\([^>]\\+\\)>"); bool local = message.isOutgoing() ^ message.isAnswer(); - const SIPHeaderLine* hl = message.getHeader(local ? "From" : "To"); + const MimeHeaderLine* hl = message.getHeader(local ? "From" : "To"); localURI = hl; if (localURI.matches(r)) localURI = localURI.matchString(1); @@ -972,7 +778,7 @@ SIPDialog& SIPDialog::operator=(const SIPMessage& message) String::operator=(cid); Regexp r("<\\([^>]\\+\\)>"); bool local = message.isOutgoing() ^ message.isAnswer(); - const SIPHeaderLine* hl = message.getHeader(local ? "From" : "To"); + const MimeHeaderLine* hl = message.getHeader(local ? "From" : "To"); localURI = hl; if (localURI.matches(r)) localURI = localURI.matchString(1); diff --git a/libs/ysip/transaction.cpp b/libs/ysip/transaction.cpp index 27b629c1..e4f6db73 100644 --- a/libs/ysip/transaction.cpp +++ b/libs/ysip/transaction.cpp @@ -48,7 +48,7 @@ SIPTransaction::SIPTransaction(SIPMessage* message, SIPEngine* engine, bool outg if (ns) m_tag = *ns; - const SIPHeaderLine* hl = message->getHeader("Call-ID"); + const MimeHeaderLine* hl = message->getHeader("Call-ID"); if (hl) m_callid = *hl; @@ -83,7 +83,7 @@ SIPTransaction::SIPTransaction(SIPTransaction& original, SIPMessage* answer) &original,answer,this); SIPMessage* msg = new SIPMessage(*original.m_firstMessage); - SIPAuthLine* auth = answer->buildAuth(*original.m_firstMessage); + MimeAuthLine* auth = answer->buildAuth(*original.m_firstMessage); m_firstMessage->setAutoAuth(); msg->complete(m_engine); msg->addHeader(auth); @@ -370,7 +370,7 @@ void SIPTransaction::requestAuth(const String& realm, const String& domain, bool if (realm) { String tmp; tmp << "Digest realm=\"" << realm << "\""; - SIPHeaderLine* line = new SIPHeaderLine(hdr,tmp,','); + MimeHeaderLine* line = new MimeHeaderLine(hdr,tmp,','); if (domain) line->setParam(" domain","\"" + domain + "\""); m_engine->nonceGet(tmp); diff --git a/libs/ysip/util.cpp b/libs/ysip/util.cpp index 75259737..1c5b51b1 100644 --- a/libs/ysip/util.cpp +++ b/libs/ysip/util.cpp @@ -75,68 +75,6 @@ const char* compactForm(const char* header) return header; } -// Utility function, puts quotes around a string -void addQuotes(String& str) -{ - str.trimBlanks(); - int l = str.length(); - if ((l < 2) || (str[0] != '"') || (str[l-1] != '"')) - str = "\"" + str + "\""; -} - -// Utility function, removes quotes around a string -void delQuotes(String& str) -{ - str.trimBlanks(); - int l = str.length(); - if ((l >= 2) && (str[0] == '"') && (str[l-1] == '"')) { - str = str.substr(1,l-2); - str.trimBlanks(); - } -} - -// Utility function, puts quotes around a string -String quote(const String& str) -{ - String tmp(str); - addQuotes(tmp); - return tmp; -} - -// Utility function to find a separator not in "quotes" or inside -int findSep(const char* str, char sep, int offs) -{ - if (!(str && sep)) - return -1; - str += offs; - bool inQ = false; - bool inU = false; - char c; - for (; (c = *str++) ; offs++) { - if (inQ) { - if (c == '"') - inQ = false; - continue; - } - if (inU) { - if (c == '>') - inU = false; - continue; - } - if (c == sep) - return offs; - switch (c) { - case '"': - inQ = true; - break; - case '<': - inU = true; - break; - } - } - return -1; -} - } /* vi: set ts=8 sw=4 sts=4 noet: */ diff --git a/libs/ysip/util.h b/libs/ysip/util.h index e75326bc..01982c6f 100644 --- a/libs/ysip/util.h +++ b/libs/ysip/util.h @@ -31,18 +31,6 @@ const char* uncompactForm(const char* header); // Utility function, returns a compacted header name const char* compactForm(const char* header); -// Utility function, puts quotes around a string -void addQuotes(String& str); - -// Utility function, removes quotes around a string -void delQuotes(String& str); - -// Utility function, puts quotes around a string -String quote(const String& str); - -// Utility function to find a separator not in "quotes" or inside -int findSep(const char* str, char sep, int offs = 0); - } /* vi: set ts=8 sw=4 sts=4 noet: */ diff --git a/libs/ysip/yatesip.h b/libs/ysip/yatesip.h index d7435e84..ceed69de 100644 --- a/libs/ysip/yatesip.h +++ b/libs/ysip/yatesip.h @@ -84,39 +84,6 @@ protected: int m_partyPort; }; -class YSIP_API SIPHeaderLine : public NamedString -{ -public: - SIPHeaderLine(const char* name, const String& value, char sep = 0); - SIPHeaderLine(const SIPHeaderLine& original, const char* newName = 0); - virtual ~SIPHeaderLine(); - virtual void* getObject(const String& name) const; - virtual SIPHeaderLine* clone(const char* newName = 0) const; - virtual void buildLine(String& line) const; - inline SIPHeaderLine& operator=(const char* value) - { NamedString::operator=(value); return *this; } - inline const ObjList& params() const - { return m_params; } - inline char separator() const - { return m_separator; } - void setParam(const char* name, const char* value = 0); - void delParam(const char* name); - const NamedString* getParam(const char* name) const; -protected: - ObjList m_params; - char m_separator; -}; - -class YSIP_API SIPAuthLine : public SIPHeaderLine -{ -public: - SIPAuthLine(const char* name, const String& value); - SIPAuthLine(const SIPAuthLine& original, const char* newName = 0); - virtual void* getObject(const String& name) const; - virtual SIPHeaderLine* clone(const char* newName = 0) const; - virtual void buildLine(String& line) const; -}; - /** * An object that holds the sip message parsed into this library model. * This class can be used to parse a sip message from a text buffer, or it @@ -241,14 +208,14 @@ public: * @param name Name of the header to locate * @return A pointer to the first matching header line or 0 if not found */ - const SIPHeaderLine* getHeader(const char* name) const; + const MimeHeaderLine* getHeader(const char* name) const; /** * Find the last header line that matches a given name name * @param name Name of the header to locate * @return A pointer to the last matching header line or 0 if not found */ - const SIPHeaderLine* getLastHeader(const char* name) const; + const MimeHeaderLine* getLastHeader(const char* name) const; /** * Count the header lines matching a specific name @@ -286,13 +253,13 @@ public: * @param value Content of the new header line */ inline void addHeader(const char* name, const char* value = 0) - { header.append(new SIPHeaderLine(name,value)); } + { header.append(new MimeHeaderLine(name,value)); } /** * Append an already constructed header line * @param line Header line to add */ - inline void addHeader(SIPHeaderLine* line) + inline void addHeader(MimeHeaderLine* line) { header.append(line); } /** @@ -316,7 +283,7 @@ public: * @param proxy Set to true to authenticate to a proxy, false to a server * @return A new authorization line to be used in a new transaction */ - SIPAuthLine* buildAuth(const String& username, const String& password, + MimeAuthLine* buildAuth(const String& username, const String& password, const String& meth, const String& uri, bool proxy = false) const; /** @@ -324,7 +291,7 @@ public: * @param original Origianl outgoing message * @return A new authorization line to be used in a new transaction */ - SIPAuthLine* buildAuth(const SIPMessage& original) const; + MimeAuthLine* buildAuth(const SIPMessage& original) const; /** * Prepare the message for automatic client transaction authentication. @@ -350,13 +317,13 @@ public: /** * Extract routes from Record-Route: headers - * @return A list of SIPHeaderLine representing SIP routes + * @return A list of MimeHeaderLine representing SIP routes */ ObjList* getRoutes() const; /** * Add Route: headers to an outgoing message - * @param routes List of SIPHeaderLine representing SIP routes + * @param routes List of MimeHeaderLine representing SIP routes */ void addRoutes(const ObjList* routes); diff --git a/modules/ysipchan.cpp b/modules/ysipchan.cpp index 20b04eb6..d66190f2 100644 --- a/modules/ysipchan.cpp +++ b/modules/ysipchan.cpp @@ -377,7 +377,7 @@ private: bool addSdpParams(Message& msg, const MimeBody* body); bool addRtpParams(Message& msg, const String& natAddr, const MimeBody* body); bool startClientReInvite(Message& msg); - bool initUnattendedTransfer(Message*& msg, SIPMessage*& sipNotify, const SIPMessage* sipRefer, const SIPHeaderLine* refHdr); + bool initUnattendedTransfer(Message*& msg, SIPMessage*& sipNotify, const SIPMessage* sipRefer, const MimeHeaderLine* refHdr); SIPTransaction* m_tr; SIPTransaction* m_tr2; @@ -723,7 +723,7 @@ static void copySipHeaders(Message& msg, const SIPMessage& sip, bool filter = tr { const ObjList* l = sip.header.skipNull(); for (; l; l = l->skipNext()) { - const SIPHeaderLine* t = static_cast(l->get()); + const MimeHeaderLine* t = static_cast(l->get()); String name(t->name()); name.toLower(); if (matchAny(name,s_rejectHeaders)) @@ -763,7 +763,7 @@ static void copySipHeaders(SIPMessage& sip, const Message& msg, const char* pref static void copyPrivacy(Message& msg, const SIPMessage& sip) { bool anonip = (sip.getHeaderValue("Anonymity") &= "ipaddr"); - const SIPHeaderLine* hl = sip.getHeader("Remote-Party-ID"); + const MimeHeaderLine* hl = sip.getHeader("Remote-Party-ID"); if (!(anonip || hl)) return; const NamedString* p = hl ? hl->getParam("screen") : 0; @@ -807,7 +807,7 @@ static void copyPrivacy(SIPMessage& sip, const Message& msg) if (tmp) tmp = "\"" + tmp + "\" "; tmp << ""; - SIPHeaderLine* hl = new SIPHeaderLine("Remote-Party-ID",tmp); + MimeHeaderLine* hl = new MimeHeaderLine("Remote-Party-ID",tmp); if (screen) hl->setParam("screen","yes"); if (privname && privuri) @@ -1451,7 +1451,7 @@ void YateSIPEndPoint::regreq(SIPEvent* e, SIPTransaction* t) return; } const SIPMessage* message = e->getMessage(); - const SIPHeaderLine* hl = message->getHeader("Contact"); + const MimeHeaderLine* hl = message->getHeader("Contact"); if (!hl) { t->setResponse(400); return; @@ -1542,7 +1542,7 @@ void YateSIPEndPoint::regreq(SIPEvent* e, SIPTransaction* t) tmp = expires; SIPMessage* r = new SIPMessage(t->initialMessage(),200); r->addHeader("Expires",tmp); - SIPHeaderLine* contact = new SIPHeaderLine("Contact","<" + addr + ">"); + MimeHeaderLine* contact = new MimeHeaderLine("Contact","<" + addr + ">"); contact->setParam("expires",tmp); r->addHeader(contact); if (natChanged) { @@ -1562,7 +1562,7 @@ void YateSIPEndPoint::regreq(SIPEvent* e, SIPTransaction* t) void YateSIPEndPoint::options(SIPEvent* e, SIPTransaction* t) { - const SIPHeaderLine* acpt = e->getMessage()->getHeader("Accept"); + const MimeHeaderLine* acpt = e->getMessage()->getHeader("Accept"); if (acpt) { if (*acpt != "application/sdp") { t->setResponse(415); @@ -1736,7 +1736,7 @@ YateSIPConnection::YateSIPConnection(SIPEvent* ev, SIPTransaction* tr) m->addParam("called",uri.getUser()); if (m_uri.getDescription()) m->addParam("callername",m_uri.getDescription()); - const SIPHeaderLine* hl = m_tr->initialMessage()->getHeader("Call-Info"); + const MimeHeaderLine* hl = m_tr->initialMessage()->getHeader("Call-Info"); if (hl) { const NamedString* type = hl->getParam("purpose"); if (!type || *type == "info") @@ -1885,14 +1885,14 @@ YateSIPConnection::YateSIPConnection(Message& msg, const String& uri, const char if (display) { String desc; desc << "\"" << display << "\" "; - SIPHeaderLine* hl = const_cast(m->getHeader("From")); + MimeHeaderLine* hl = const_cast(m->getHeader("From")); if (hl) *hl = desc + *hl; } if (msg.getParam("calledname")) { String desc; desc << "\"" << msg.getValue("calledname") << "\" "; - SIPHeaderLine* hl = const_cast(m->getHeader("To")); + MimeHeaderLine* hl = const_cast(m->getHeader("To")); if (hl) *hl = desc + *hl; } @@ -1909,19 +1909,19 @@ YateSIPConnection::YateSIPConnection(Message& msg, const String& uri, const char // add some Call-Info headers const char* info = msg.getValue("caller_info_uri"); if (info) { - SIPHeaderLine* hl = new SIPHeaderLine("Call-Info",info); + MimeHeaderLine* hl = new MimeHeaderLine("Call-Info",info); hl->setParam("purpose","info"); m->addHeader(hl); } info = msg.getValue("caller_icon_uri"); if (info) { - SIPHeaderLine* hl = new SIPHeaderLine("Call-Info",info); + MimeHeaderLine* hl = new MimeHeaderLine("Call-Info",info); hl->setParam("purpose","icon"); m->addHeader(hl); } info = msg.getValue("caller_card_uri"); if (info) { - SIPHeaderLine* hl = new SIPHeaderLine("Call-Info",info); + MimeHeaderLine* hl = new MimeHeaderLine("Call-Info",info); hl->setParam("purpose","card"); m->addHeader(hl); } @@ -2058,7 +2058,7 @@ void YateSIPConnection::hangup() tmp << i->getCSeq() << " CANCEL"; m->addHeader("CSeq",tmp); if (m_reason == "pickup") { - SIPHeaderLine* hl = new SIPHeaderLine("Reason","SIP"); + MimeHeaderLine* hl = new MimeHeaderLine("Reason","SIP"); hl->setParam("cause","200"); hl->setParam("text","\"Call completed elsewhere\""); m->addHeader(hl); @@ -2078,7 +2078,7 @@ void YateSIPConnection::hangup() if (m) { if (m_reason) { // FIXME: add SIP and Q.850 cause codes, set the proper reason - SIPHeaderLine* hl = new SIPHeaderLine("Reason","SIP"); + MimeHeaderLine* hl = new MimeHeaderLine("Reason","SIP"); hl->setParam("text","\"" + m_reason + "\""); m->addHeader(hl); } @@ -2108,7 +2108,7 @@ SIPMessage* YateSIPConnection::createDlgMsg(const char* method, const char* uri) m->addHeader("Call-ID",m_callid); String tmp; tmp << "<" << m_dialog.localURI << ">"; - SIPHeaderLine* hl = new SIPHeaderLine("From",tmp); + MimeHeaderLine* hl = new MimeHeaderLine("From",tmp); tmp = m_dialog.localTag; if (tmp.null() && m_tr) tmp = m_tr->getDialogTag(); @@ -2117,7 +2117,7 @@ SIPMessage* YateSIPConnection::createDlgMsg(const char* method, const char* uri) m->addHeader(hl); tmp.clear(); tmp << "<" << m_dialog.remoteURI << ">"; - hl = new SIPHeaderLine("To",tmp); + hl = new MimeHeaderLine("To",tmp); tmp = m_dialog.remoteTag; if (tmp.null() && m_tr) tmp = m_tr->getDialogTag(); @@ -2134,8 +2134,8 @@ bool YateSIPConnection::emitPRACK(const SIPMessage* msg) return false; if (!plugin.ep()->engine()->prack()) return true; - const SIPHeaderLine* rs = msg->getHeader("RSeq"); - const SIPHeaderLine* cs = msg->getHeader("CSeq"); + const MimeHeaderLine* rs = msg->getHeader("RSeq"); + const MimeHeaderLine* cs = msg->getHeader("CSeq"); if (!(rs && cs)) return true; int seq = rs->toInteger(0,10); @@ -2148,7 +2148,7 @@ bool YateSIPConnection::emitPRACK(const SIPMessage* msg) return false; } String tmp; - const SIPHeaderLine* co = msg->getHeader("Contact"); + const MimeHeaderLine* co = msg->getHeader("Contact"); if (co) { tmp = *co; Regexp r("^[^<]*<\\([^>]*\\)>.*$"); @@ -2616,7 +2616,7 @@ bool YateSIPConnection::process(SIPEvent* ev) // see if we should detect our external address const YateSIPLine* line = plugin.findLine(m_line); if (line && line->localDetect()) { - SIPHeaderLine* hl = const_cast(msg->getHeader("Via")); + MimeHeaderLine* hl = const_cast(msg->getHeader("Via")); if (hl) { const NamedString* par = hl->getParam("received"); if (par && *par) { @@ -2922,7 +2922,7 @@ void YateSIPConnection::doBye(SIPTransaction* t) if (m_authBye && !checkUser(t)) return; DDebug(this,DebugAll,"YateSIPConnection::doBye(%p) [%p]",t,this); - const SIPHeaderLine* hl = t->initialMessage()->getHeader("Reason"); + const MimeHeaderLine* hl = t->initialMessage()->getHeader("Reason"); if (hl) { const NamedString* text = hl->getParam("text"); if (text) @@ -3001,7 +3001,7 @@ void YateSIPConnection::doRefer(SIPTransaction* t) return; } m_referring = true; - const SIPHeaderLine* refHdr = t->initialMessage()->getHeader("Refer-To"); + const MimeHeaderLine* refHdr = t->initialMessage()->getHeader("Refer-To"); if (!(refHdr && refHdr->length())) { DDebug(this,DebugAll,"YateSIPConnection::doRefer(%p) [%p]. Empty or missing 'Refer-To' header.",t,this); t->setResponse(400); // Bad request @@ -3093,7 +3093,7 @@ bool YateSIPConnection::msgAnswered(Message& msg) } m->setBody(sdp); - const SIPHeaderLine* co = m_tr->initialMessage()->getHeader("Contact"); + const MimeHeaderLine* co = m_tr->initialMessage()->getHeader("Contact"); if (co) { // INVITE had a Contact: header - time to change remote URI m_uri = *co; @@ -3422,7 +3422,7 @@ void YateSIPConnection::startPendingUpdate() // sipRefer: received REFER message, refHdr: 'Refer-To' header // If return false, msg and sipNotify are 0 bool YateSIPConnection::initUnattendedTransfer(Message*& msg, SIPMessage*& sipNotify, - const SIPMessage* sipRefer, const SIPHeaderLine* refHdr) + const SIPMessage* sipRefer, const MimeHeaderLine* refHdr) { // call.route msg = new Message("call.route"); @@ -3432,7 +3432,7 @@ bool YateSIPConnection::initUnattendedTransfer(Message*& msg, SIPMessage*& sipNo if (m_user) msg->addParam("username",m_user); - const SIPHeaderLine* sh = sipRefer->getHeader("To"); // caller + const MimeHeaderLine* sh = sipRefer->getHeader("To"); // caller if (sh) { URI uriCaller(*sh); uriCaller.parse(); @@ -3456,7 +3456,7 @@ bool YateSIPConnection::initUnattendedTransfer(Message*& msg, SIPMessage*& sipNo msg->addParam("reason","transfer"); // reason // NOTIFY String tmp; - const SIPHeaderLine* co = sipRefer->getHeader("Contact"); + const MimeHeaderLine* co = sipRefer->getHeader("Contact"); if (co) { tmp = *co; Regexp r("^[^<]*<\\([^>]*\\)>.*$"); @@ -3651,7 +3651,7 @@ void YateSIPLine::detectLocal(const SIPMessage* msg) return; String laddr = m_localAddr; int lport = m_localPort; - SIPHeaderLine* hl = const_cast(msg->getHeader("Via")); + MimeHeaderLine* hl = const_cast(msg->getHeader("Via")); if (hl) { const NamedString* par = hl->getParam("received"); if (par && *par) diff --git a/yatemime.h b/yatemime.h index ecc93dff..543a91c9 100644 --- a/yatemime.h +++ b/yatemime.h @@ -36,6 +36,176 @@ */ namespace TelEngine { +/** + * A MIME header line. + * The NamedString's value contain the first parameter after the header name + * @short MIME header line + */ +class YATE_API MimeHeaderLine : public NamedString +{ +public: + /** + * Constructor. + * Builds a MIME header line from a string buffer. + * Splits the value into header parameters + * @param name The header name + * @param value The header value + * @param sep Optional parameter separator. If 0, the default ';' will be used + */ + MimeHeaderLine(const char* name, const String& value, char sep = 0); + + /** + * Constructor. + * Builds this MIME header line from another one + * @param original Original header line to build from. + * @param newName Optional new header name. If 0, the original name will be used + */ + MimeHeaderLine(const MimeHeaderLine& original, const char* newName = 0); + + /** + * Destructor. + */ + virtual ~MimeHeaderLine(); + + /** + * RTTI method, get a pointer to a derived class given the class name. + * @param name Name of the class we are asking for + * @return Pointer to the requested class or NULL if this object doesn't implement it + */ + virtual void* getObject(const String& name) const; + + /** + * Duplicate this MIME header line. + * @param newName Optional new header name. If 0, this header's name will be used + * @return Copy of this MIME header line + */ + virtual MimeHeaderLine* clone(const char* newName = 0) const; + + /** + * Build a string line from this MIME header without adding a line separator + * @param line Destination string + */ + virtual void buildLine(String& line) const; + + /** + * Assignement operator. Set the header's value + * @param value The new headr value + */ + inline MimeHeaderLine& operator=(const char* value) + { NamedString::operator=(value); return *this; } + + /** + * Get the header's parameters + * @return This header's list of parameters + */ + inline const ObjList& params() const + { return m_params; } + + /** + * Get the character used as separator in header line + * @return This header's separator + */ + inline char separator() const + { return m_separator; } + + /** + * Replace the value of an existing parameter or add a new one + * @param name Parameter's name + * @param value Parameter's value + */ + void setParam(const char* name, const char* value = 0); + + /** + * Remove a parameter from list + * @param name Parameter's name + */ + void delParam(const char* name); + + /** + * Get a header parameter + * @param name Parameter's name + * @return Pointer to the desired parameter or 0 if not found + */ + const NamedString* getParam(const char* name) const; + + /** + * Utility function, puts quotes around a string. + * @param str String to put quotes around. + */ + static void addQuotes(String& str); + + /** + * Utility function, removes quotes around a string. + * @param str String to remove quotes. + */ + static void delQuotes(String& str); + + /** + * Utility function, puts quotes around a string. + * @param str String to put quotes around. + * @return The input string enclosed in quotes. + */ + static String quote(const String& str); + + /** + * Utility function to find a separator not in "quotes" or inside . + * @param str Input string used to find the separator. + * @param sep The separator to find. + * @param offs Starting offset in input string. + * @return The position of the separator in input string or -1 if not found. + */ + static int findSep(const char* str, char sep, int offs = 0); + +protected: + ObjList m_params; // Header list of parameters + char m_separator; // Parameter separator +}; + +/** + * A MIME header line containing authentication data. + * @short MIME authentication line + */ +class YATE_API MimeAuthLine : public MimeHeaderLine +{ +public: + /** + * Constructor. + * Builds a MIME authentication header line from a string buffer. + * Splits the value into header parameters + * @param name The header name + * @param value The header value + */ + MimeAuthLine(const char* name, const String& value); + + /** + * Constructor. + * Builds this MIME authentication header line from another one + * @param original Original header line to build from. + * @param newName Optional new header name. If 0, the original name will be used + */ + MimeAuthLine(const MimeAuthLine& original, const char* newName = 0); + + /** + * RTTI method, get a pointer to a derived class given the class name. + * @param name Name of the class we are asking for + * @return Pointer to the requested class or NULL if this object doesn't implement it + */ + virtual void* getObject(const String& name) const; + + /** + * Duplicate this MIME header line. + * @param newName Optional new header name. If 0, this header's name will be used + * @return Copy of this MIME header line + */ + virtual MimeHeaderLine* clone(const char* newName = 0) const; + + /** + * Build a string line from this MIME header without adding a line separator + * @param line Destination string + */ + virtual void buildLine(String& line) const; +}; + /** * Abstract base class for holding Multipurpose Internet Mail Extensions data * @short Abstract MIME data holder @@ -49,7 +219,7 @@ public: virtual ~MimeBody(); /** - * RTTI method, get a pointer to a derived class given that class name + * RTTI method, get a pointer to a derived class given the class name * @param name Name of the class we are asking for * @return Pointer to the requested class or NULL if this object doesn't implement it */ @@ -59,7 +229,7 @@ public: * Retrive the MIME type of this body * @return Name of the MIME type/subtype */ - inline const String& getType() const + inline const MimeHeaderLine& getType() const { return m_type; } /** @@ -92,7 +262,8 @@ public: * Method to build a MIME body from a type and data buffer * @param buf Pointer to buffer of data * @param len Length of data in buffer - * @param type Name of the MIME type/subtype, must be lower case + * @param type Name of the MIME type/subtype, must be lower case. + * This is the whole content type line, including the parameters * @return Newly allocated MIME body or NULL if type is unknown */ static MimeBody* build(const char* buf, int len, const String& type); @@ -123,7 +294,7 @@ protected: mutable DataBlock m_body; private: - String m_type; + MimeHeaderLine m_type; // Content type header line }; /** @@ -140,9 +311,9 @@ public: /** * Constructor from block of data + * @param type Name of the MIME type/subtype, should be "application/sdp" * @param buf Pointer to buffer of data * @param len Length of data in buffer - * @param type Name of the MIME type/subtype, should be "application/sdp" */ MimeSdpBody(const String& type, const char* buf, int len); @@ -152,7 +323,7 @@ public: virtual ~MimeSdpBody(); /** - * RTTI method, get a pointer to a derived class given that class name + * RTTI method, get a pointer to a derived class given the class name * @param name Name of the class we are asking for * @return Pointer to the requested class or NULL if this object doesn't implement it */ @@ -236,7 +407,7 @@ public: virtual ~MimeBinaryBody(); /** - * RTTI method, get a pointer to a derived class given that class name + * RTTI method, get a pointer to a derived class given the class name * @param name Name of the class we are asking for * @return Pointer to the requested class or NULL if this object doesn't implement it */ @@ -281,7 +452,7 @@ public: virtual ~MimeStringBody(); /** - * RTTI method, get a pointer to a derived class given that class name + * RTTI method, get a pointer to a derived class given the class name * @param name Name of the class we are asking for * @return Pointer to the requested class or NULL if this object doesn't implement it */ @@ -336,7 +507,7 @@ public: virtual ~MimeLinesBody(); /** - * RTTI method, get a pointer to a derived class given that class name + * RTTI method, get a pointer to a derived class given the class name * @param name Name of the class we are asking for * @return Pointer to the requested class or NULL if this object doesn't implement it */