From 05d646e887efa2feededc927e467e08b370df29d Mon Sep 17 00:00:00 2001 From: paulc Date: Thu, 26 Jul 2007 23:45:33 +0000 Subject: [PATCH] Added MIME related classes in engine. git-svn-id: http://yate.null.ro/svn/yate/trunk@1410 acf43c95-373e-0410-b603-e72c3f656dc1 --- Makefile.in | 4 +- engine/Makefile.in | 4 +- engine/Mime.cpp | 318 +++++++++++++++++++++++++++++++++++++ yatemime.h | 384 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 706 insertions(+), 4 deletions(-) create mode 100644 engine/Mime.cpp create mode 100644 yatemime.h diff --git a/Makefile.in b/Makefile.in index 36d09935..cc9e82c0 100644 --- a/Makefile.in +++ b/Makefile.in @@ -20,7 +20,7 @@ MKDEPS := ./config.status PROGS:= yate YLIB := libyate.so.@PACKAGE_VERSION@ SLIBS:= $(YLIB) libyate.so -INCS := yateclass.h yatengine.h yatephone.h yatecbase.h +INCS := yateclass.h yatemime.h yatengine.h yatephone.h yatecbase.h GENS := yateversn.h LIBS := MAN8 := yate.8 yate-config.8 @@ -139,7 +139,7 @@ apidocs-build: check-topdir apidocs: @srcdir@/docs/api/index.html @srcdir@/docs/api/index.html: Doxyfile \ - @srcdir@/yateclass.h @srcdir@/yatengine.h \ + @srcdir@/yateclass.h @srcdir@/yatemime.h @srcdir@/yatengine.h \ @srcdir@/yatephone.h @srcdir@/yatecbase.h $(MAKE) apidocs-build diff --git a/engine/Makefile.in b/engine/Makefile.in index da220c33..c2e33865 100644 --- a/engine/Makefile.in +++ b/engine/Makefile.in @@ -18,13 +18,13 @@ LDCONFIG:=true MKDEPS := ../config.status YLIB:= libyate.so.@PACKAGE_VERSION@ -CINC := @top_srcdir@/yateclass.h +CINC := @top_srcdir@/yateclass.h @top_srcdir@/yatemime.h EINC := $(CINC) @top_srcdir@/yatengine.h PINC := $(EINC) @top_srcdir@/yatephone.h CLINC:= $(PINC) @top_srcdir@/yatecbase.h LIBS := CLSOBJS := TelEngine.o ObjList.o HashList.o String.o DataBlock.o NamedList.o \ - URI.o Array.o Iterator.o YMD5.o YSHA1.o Mutex.o Thread.o Socket.o + URI.o Mime.o Array.o Iterator.o YMD5.o YSHA1.o Mutex.o Thread.o Socket.o ENGOBJS := Configuration.o Message.o Plugin.o Engine.o TELOBJS := DataFormat.o Channel.o CLIOBJS := Client.o diff --git a/engine/Mime.cpp b/engine/Mime.cpp new file mode 100644 index 00000000..bd1c3fc0 --- /dev/null +++ b/engine/Mime.cpp @@ -0,0 +1,318 @@ +/** + * Mime.cpp + * This file is part of the YATE Project http://YATE.null.ro + * + * Yet Another Telephony Engine - a fully featured software PBX and IVR + * Copyright (C) 2004-2006 Null Team + * + * 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 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "yatemime.h" + +using namespace TelEngine; + +// Utility function, checks if a character is a folded line continuation +static bool isContinuationBlank(char c) +{ + return ((c == ' ') || (c == '\t')); +} + +YCLASSIMP(MimeBody,GenObject) + +MimeBody::MimeBody(const String& type) + : m_type(type) +{ + DDebug(DebugAll,"MimeBody::MimeBody('%s') [%p]",m_type.c_str(),this); +} + +MimeBody::~MimeBody() +{ + DDebug(DebugAll,"MimeBody::~MimeBody() '%s' [%p]",m_type.c_str(),this); +} + +const DataBlock& MimeBody::getBody() const +{ + if (m_body.null()) + buildBody(); + return m_body; +} + +MimeBody* MimeBody::build(const char* buf, int len, const String& type) +{ + DDebug(DebugAll,"MimeBody::build(%p,%d,'%s')",buf,len,type.c_str()); + if ((len <= 0) || !buf) + return 0; + if (type == "application/sdp") + return new MimeSdpBody(type,buf,len); + if (type == "application/dtmf-relay") + return new MimeLinesBody(type,buf,len); + if (type.startsWith("text/") || (type == "application/dtmf")) + return new MimeStringBody(type,buf,len); + return new MimeBinaryBody(type,buf,len); +} + +String* MimeBody::getUnfoldedLine(const char*& buf, int& len) +{ + String* res = new String; + const char* b = buf; + const char* s = b; + int l = len; + int e = 0; + for (;(l > 0); ++b, --l) { + bool goOut = false; + switch (*b) { + case '\r': + // CR is optional but skip over it if exists + if ((l > 0) && (b[1] == '\n')) { + ++b; + --l; + } + case '\n': + ++b; + --l; + { + String line(s,e); + *res << line; + } + // Skip over any continuation characters at start of next line + goOut = true; + while ((l > 0) && isContinuationBlank(b[0])) { + ++b; + --l; + goOut = false; + } + s = b; + e = 0; + if (!goOut) { + --b; + ++l; + } + break; + case '\0': + // Should not happen - but let's accept what we got + Debug(DebugMild,"Unexpected NUL character while unfolding lines"); + *res << s; + goOut = true; + // End parsing + b += l; + l = 0; + e = 0; + break; + default: + // Just count this character - we'll pick it later + ++e; + } + // Exit without adjusting p and l + if (goOut) + break; + } + buf = b; + len = l; + // Collect any leftover characters + if (e) { + String line(s,e); + *res << line; + } + res->trimBlanks(); + return res; +} + + +YCLASSIMP(MimeSdpBody,MimeBody) + +MimeSdpBody::MimeSdpBody() + : MimeBody("application/sdp") +{ +} + +MimeSdpBody::MimeSdpBody(const String& type, const char* buf, int len) + : MimeBody(type) +{ + while (len > 0) { + String* line = getUnfoldedLine(buf,len); + int eq = line->find('='); + if (eq > 0) + m_lines.append(new NamedString(line->substr(0,eq),line->substr(eq+1))); + line->destruct(); + } +} + +MimeSdpBody::MimeSdpBody(const MimeSdpBody& original) + : MimeBody(original.getType()) +{ + const ObjList* l = &original.m_lines; + for (; l; l = l->next()) { + const NamedString* t = static_cast(l->get()); + if (t) + m_lines.append(new NamedString(t->name(),*t)); + } +} + +MimeSdpBody::~MimeSdpBody() +{ +} + +void MimeSdpBody::buildBody() const +{ + DDebug(DebugAll,"MimeSdpBody::buildBody() [%p]",this); + const ObjList* l = &m_lines; + for (; l; l = l->next()) { + const NamedString* t = static_cast(l->get()); + if (t) { + String line; + line << t->name() << "=" << *t << "\r\n"; + m_body += line; + } + } +} + +MimeBody* MimeSdpBody::clone() const +{ + return new MimeSdpBody(*this); +} + +const NamedString* MimeSdpBody::getLine(const char* name) const +{ + if (!(name && *name)) + return 0; + const ObjList* l = &m_lines; + for (; l; l = l->next()) { + const NamedString* t = static_cast(l->get()); + if (t && (t->name() &= name)) + return t; + } + return 0; +} + +const NamedString* MimeSdpBody::getNextLine(const NamedString* line) const +{ + if (!line) + return 0; + const ObjList* l = m_lines.find(line); + if (!l) + return 0; + l = l->next(); + for (; l; l = l->next()) { + const NamedString* t = static_cast(l->get()); + if (t && (t->name() &= line->name())) + return t; + } + return 0; +} + + +YCLASSIMP(MimeBinaryBody,MimeBody) + +MimeBinaryBody::MimeBinaryBody(const String& type, const char* buf, int len) + : MimeBody(type) +{ + m_body.assign((void*)buf,len); +} + +MimeBinaryBody::MimeBinaryBody(const MimeBinaryBody& original) + : MimeBody(original.getType()) +{ + m_body = original.m_body; +} + +MimeBinaryBody::~MimeBinaryBody() +{ +} + +void MimeBinaryBody::buildBody() const +{ + DDebug(DebugAll,"MimeBinaryBody::buildBody() [%p]",this); + // nothing to do +} + +MimeBody* MimeBinaryBody::clone() const +{ + return new MimeBinaryBody(*this); +} + + +YCLASSIMP(MimeStringBody,MimeBody) + +MimeStringBody::MimeStringBody(const String& type, const char* buf, int len) + : MimeBody(type), m_text(buf,len) +{ +} + +MimeStringBody::MimeStringBody(const MimeStringBody& original) + : MimeBody(original.getType()), m_text(original.m_text) +{ +} + +MimeStringBody::~MimeStringBody() +{ +} + +void MimeStringBody::buildBody() const +{ + DDebug(DebugAll,"MimeStringBody::buildBody() [%p]",this); + m_body.assign((void*)m_text.c_str(),m_text.length()); +} + +MimeBody* MimeStringBody::clone() const +{ + return new MimeStringBody(*this); +} + + +YCLASSIMP(MimeLinesBody,MimeBody) + +MimeLinesBody::MimeLinesBody(const String& type, const char* buf, int len) + : MimeBody(type) +{ + while (len > 0) + m_lines.append(getUnfoldedLine(buf,len)); +} + +MimeLinesBody::MimeLinesBody(const MimeLinesBody& original) + : MimeBody(original.getType()) +{ + const ObjList* l = &original.m_lines; + for (; l; l = l->next()) { + const String* s = static_cast(l->get()); + if (s) + m_lines.append(new String(*s)); + } +} + +MimeLinesBody::~MimeLinesBody() +{ +} + +void MimeLinesBody::buildBody() const +{ + DDebug(DebugAll,"MimeLinesBody::buildBody() [%p]",this); + const ObjList* l = &m_lines; + for (; l; l = l->next()) { + const String* s = static_cast(l->get()); + if (s) { + String line; + line << *s << "\r\n"; + m_body += line; + } + } +} + +MimeBody* MimeLinesBody::clone() const +{ + return new MimeLinesBody(*this); +} + +/* vi: set ts=8 sw=4 sts=4 noet: */ diff --git a/yatemime.h b/yatemime.h new file mode 100644 index 00000000..ecc93dff --- /dev/null +++ b/yatemime.h @@ -0,0 +1,384 @@ +/* + * yatemime.h + * This file is part of the YATE Project http://YATE.null.ro + * + * MIME types, body codecs and related functions + * + * Yet Another Telephony Engine - a fully featured software PBX and IVR + * Copyright (C) 2004-2006 Null Team + * + * 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 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __YATEMIME_H +#define __YATEMIME_H + +#ifndef __cplusplus +#error C++ is required +#endif + +#include + +/** + * Holds all Telephony Engine related classes. + */ +namespace TelEngine { + +/** + * Abstract base class for holding Multipurpose Internet Mail Extensions data + * @short Abstract MIME data holder + */ +class YATE_API MimeBody : public GenObject +{ +public: + /** + * Destructor + */ + virtual ~MimeBody(); + + /** + * RTTI method, get a pointer to a derived class given that 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; + + /** + * Retrive the MIME type of this body + * @return Name of the MIME type/subtype + */ + inline const String& getType() const + { return m_type; } + + /** + * Retrive the binary encoding of this MIME body + * @return Block of binary data + */ + const DataBlock& getBody() const; + + /** + * Check if this body is an Session Description Protocol + * @return True if this body holds a SDP + */ + virtual bool isSDP() const + { return false; } + + /** + * Check if this body is multipart (can hold other MIME bodies) + * @return True if this body is multipart + */ + virtual bool isMultipart() const + { return false; } + + /** + * Duplicate this MIME body + * @return Copy of this MIME body + */ + virtual MimeBody* clone() const = 0; + + /** + * 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 + * @return Newly allocated MIME body or NULL if type is unknown + */ + static MimeBody* build(const char* buf, int len, const String& type); + + /** + * Utility method, returns an unfolded line and advances the pointer + * @param buf Reference to pointer to start of buffer data + * @param len Reference to variable holding buffer length + * @return Newly allocated String holding the line of text + */ + static String* getUnfoldedLine(const char*& buf, int& len); + +protected: + /** + * Constructor to be used only by derived classes + * @param type Name of the MIME type/subtype, must be lower case + */ + MimeBody(const String& type); + + /** + * Method that is called internally to build the binary encoded body + */ + virtual void buildBody() const = 0; + + /** + * Block of binary data that @ref buildBody() must fill + */ + mutable DataBlock m_body; + +private: + String m_type; +}; + +/** + * An object holding the lines of an application/sdp MIME type + * @short MIME for application/sdp + */ +class YATE_API MimeSdpBody : public MimeBody +{ +public: + /** + * Default constructor, builds an empty application/sdp + */ + MimeSdpBody(); + + /** + * Constructor from block of data + * @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); + + /** + * Destructor + */ + virtual ~MimeSdpBody(); + + /** + * RTTI method, get a pointer to a derived class given that 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; + + /** + * Override that checks if this body is an Session Description Protocol + * @return True, since this body holds a SDP + */ + virtual bool isSDP() const + { return true; } + + /** + * Duplicate this MIME body + * @return Copy of this MIME body - a new MimeSdpBody + */ + virtual MimeBody* clone() const; + + /** + * Retrive the lines hold in data + * @return List of NamedStrings + */ + inline const ObjList& lines() const + { return m_lines; } + + /** + * Append a new name=value line of SDP data + * @param name Name of the line, should be one character + * @param value Text of the line + */ + inline void addLine(const char* name, const char* value = 0) + { m_lines.append(new NamedString(name,value)); } + + /** + * Retrive the first line matching a name + * @param name Name of the line to search + * @return First instance of the searched name or NULL if none present + */ + const NamedString* getLine(const char* name) const; + + /** + * Retrive the next line of the same type as the current + * @param line Current line + * @return Next instance of same name or NULL if no more + */ + const NamedString* getNextLine(const NamedString* line) const; + +protected: + /** + * Copy constructor + */ + MimeSdpBody(const MimeSdpBody& original); + + /** + * Override that is called internally to build the binary encoded body + */ + virtual void buildBody() const; + +private: + ObjList m_lines; +}; + +/** + * An object holding a binary block of MIME data + * @short MIME for obscure binary data + */ +class YATE_API MimeBinaryBody : public MimeBody +{ +public: + /** + * Constructor from block of data + * @param buf Pointer to buffer of data + * @param len Length of data in buffer + * @param type Name of the specific MIME type/subtype + */ + MimeBinaryBody(const String& type, const char* buf, int len); + + /** + * Destructor + */ + virtual ~MimeBinaryBody(); + + /** + * RTTI method, get a pointer to a derived class given that 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 body + * @return Copy of this MIME body - a new MimeBinaryBody + */ + virtual MimeBody* clone() const; + +protected: + /** + * Copy constructor + */ + MimeBinaryBody(const MimeBinaryBody& original); + + /** + * Override that is called internally to build the binary encoded body + */ + virtual void buildBody() const; +}; + +/** + * An object holding MIME data as just one text string + * @short MIME for one text string + */ +class YATE_API MimeStringBody : public MimeBody +{ +public: + /** + * Constructor from block of data + * @param buf Pointer to buffer of data + * @param len Length of data in buffer + * @param type Name of the specific MIME type/subtype + */ + MimeStringBody(const String& type, const char* buf, int len = -1); + + /** + * Destructor + */ + virtual ~MimeStringBody(); + + /** + * RTTI method, get a pointer to a derived class given that 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 body + * @return Copy of this MIME body - a new MimeStringBody + */ + virtual MimeBody* clone() const; + + /** + * Retrive the stored data + * @return String holding the data text + */ + inline const String& text() const + { return m_text; } + +protected: + /** + * Copy constructor + */ + MimeStringBody(const MimeStringBody& original); + + /** + * Override that is called internally to build the binary encoded body + */ + virtual void buildBody() const; + +private: + String m_text; +}; + +/** + * An object holding MIME data as separate text lines + * @short MIME for multiple text lines + */ +class YATE_API MimeLinesBody : public MimeBody +{ +public: + /** + * Constructor from block of data + * @param buf Pointer to buffer of data + * @param len Length of data in buffer + * @param type Name of the specific MIME type/subtype + */ + MimeLinesBody(const String& type, const char* buf, int len); + + /** + * Destructor + */ + virtual ~MimeLinesBody(); + + /** + * RTTI method, get a pointer to a derived class given that 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 body + * @return Copy of this MIME body - a new MimeLinesBody + */ + virtual MimeBody* clone() const; + + /** + * Retrive the stored lines of text + * @return List of Strings + */ + inline const ObjList& lines() const + { return m_lines; } + + /** + * Append a line of text to the data + * @param line Text to append + */ + inline void addLine(const char* line) + { m_lines.append(new String(line)); } + +protected: + /** + * Copy constructor + */ + MimeLinesBody(const MimeLinesBody& original); + + /** + * Override that is called internally to build the binary encoded body + */ + virtual void buildBody() const; + +private: + ObjList m_lines; +}; + +}; // namespace TelEngine + +#endif /* __YATEMIME_H */ + +/* vi: set ts=8 sw=4 sts=4 noet: */