mirror of
https://gitlab.linphone.org/BC/public/linphone-iphone.git
synced 2026-01-18 11:38:08 +00:00
Merge branch 'dev_cpim_improvements' into dev_refactor_cpp
This commit is contained in:
commit
2bb1893802
19 changed files with 1184 additions and 805 deletions
Binary file not shown.
|
|
@ -17,6 +17,13 @@
|
|||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
|
||||
#include "linphone/utils/utils.h"
|
||||
|
||||
#include "logger/logger.h"
|
||||
|
||||
#include "chat/cpim/parser/cpim-parser.h"
|
||||
#include "cpim-header-p.h"
|
||||
|
||||
|
|
@ -28,50 +35,278 @@ using namespace std;
|
|||
|
||||
LINPHONE_BEGIN_NAMESPACE
|
||||
|
||||
Cpim::CoreHeader::CoreHeader () : Header(*new HeaderPrivate) {}
|
||||
class Cpim::ContactHeaderPrivate : public HeaderPrivate {
|
||||
public:
|
||||
string uri;
|
||||
string formalName;
|
||||
};
|
||||
|
||||
Cpim::CoreHeader::CoreHeader (HeaderPrivate &p) : Header(p) {}
|
||||
Cpim::ContactHeader::ContactHeader () : Header(*new ContactHeaderPrivate) {}
|
||||
|
||||
Cpim::CoreHeader::~CoreHeader () {}
|
||||
Cpim::ContactHeader::ContactHeader (const string &uri, const string &formalName) : ContactHeader() {
|
||||
setUri(uri);
|
||||
setFormalName(formalName);
|
||||
}
|
||||
|
||||
bool Cpim::CoreHeader::isValid () const {
|
||||
return !getValue().empty();
|
||||
string Cpim::ContactHeader::getUri () const {
|
||||
L_D();
|
||||
return d->uri;
|
||||
}
|
||||
|
||||
void Cpim::ContactHeader::setUri (const string &uri) {
|
||||
L_D();
|
||||
d->uri = uri;
|
||||
}
|
||||
|
||||
string Cpim::ContactHeader::getFormalName () const {
|
||||
L_D();
|
||||
return d->formalName;
|
||||
}
|
||||
|
||||
void Cpim::ContactHeader::setFormalName (const string &formalName) {
|
||||
L_D();
|
||||
if (formalName.front() == '\"' && formalName.back() == '\"')
|
||||
d->formalName = formalName.substr(1, formalName.size() - 2);
|
||||
else if (formalName.back() == ' ')
|
||||
d->formalName = formalName.substr(0, formalName.size() - 1);
|
||||
else
|
||||
d->formalName = formalName;
|
||||
}
|
||||
|
||||
string Cpim::ContactHeader::getValue () const {
|
||||
L_D();
|
||||
string result;
|
||||
if (!d->formalName.empty())
|
||||
result += "\"" + d->formalName + "\"";
|
||||
result += "<" + d->uri + ">";
|
||||
return result;
|
||||
}
|
||||
|
||||
string Cpim::ContactHeader::asString () const {
|
||||
return getName() + ": " + getValue() + "\r\n";
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#define MAKE_CORE_HEADER_IMPL(CLASS_PREFIX) \
|
||||
bool Cpim::CLASS_PREFIX ## Header::setValue(const string &value) { \
|
||||
return Parser::getInstance()->coreHeaderIsValid<CLASS_PREFIX ## Header>(value) && Header::setValue(value); \
|
||||
class Cpim::DateTimeHeaderPrivate : public HeaderPrivate {
|
||||
public:
|
||||
tm dateTime;
|
||||
tm dateTimeOffset;
|
||||
string signOffset;
|
||||
};
|
||||
|
||||
Cpim::DateTimeHeader::DateTimeHeader () : Header(*new DateTimeHeaderPrivate) {}
|
||||
|
||||
Cpim::DateTimeHeader::DateTimeHeader (time_t time) : DateTimeHeader() {
|
||||
setTime(time);
|
||||
}
|
||||
|
||||
Cpim::DateTimeHeader::DateTimeHeader (const tm &time, const tm &timeOffset, const string &signOffset) : DateTimeHeader() {
|
||||
setTime(time, timeOffset, signOffset);
|
||||
}
|
||||
|
||||
time_t Cpim::DateTimeHeader::getTime () const {
|
||||
L_D();
|
||||
|
||||
tm result = d->dateTime;
|
||||
result.tm_year -= 1900;
|
||||
result.tm_isdst = 0;
|
||||
|
||||
if (d->signOffset == "+") {
|
||||
result.tm_hour += d->dateTimeOffset.tm_hour;
|
||||
result.tm_min += d->dateTimeOffset.tm_min;
|
||||
|
||||
while (result.tm_min > 59) {
|
||||
result.tm_hour++;
|
||||
result.tm_min -= 60;
|
||||
}
|
||||
}
|
||||
else if (d->signOffset == "-") {
|
||||
result.tm_hour -= d->dateTimeOffset.tm_hour;
|
||||
result.tm_hour -= d->dateTimeOffset.tm_min;
|
||||
|
||||
while (result.tm_min < 0) {
|
||||
result.tm_hour--;
|
||||
result.tm_min += 60;
|
||||
}
|
||||
}
|
||||
|
||||
MAKE_CORE_HEADER_IMPL(From);
|
||||
MAKE_CORE_HEADER_IMPL(To);
|
||||
MAKE_CORE_HEADER_IMPL(Cc);
|
||||
MAKE_CORE_HEADER_IMPL(DateTime);
|
||||
return Utils::getTmAsTimeT(result);
|
||||
}
|
||||
|
||||
MAKE_CORE_HEADER_IMPL(Ns);
|
||||
MAKE_CORE_HEADER_IMPL(Require);
|
||||
void Cpim::DateTimeHeader::setTime (const time_t time) {
|
||||
L_D();
|
||||
|
||||
#undef MAKE_CORE_HEADER_IMPL
|
||||
d->signOffset = "Z";
|
||||
d->dateTime = Utils::getTimeTAsTm(time);
|
||||
d->dateTime.tm_year += 1900;
|
||||
}
|
||||
|
||||
void Cpim::DateTimeHeader::setTime (const tm &time, const tm &timeOffset, const string &signOffset) {
|
||||
L_D();
|
||||
|
||||
d->dateTime = time;
|
||||
d->dateTimeOffset = timeOffset;
|
||||
d->signOffset = signOffset;
|
||||
}
|
||||
|
||||
string Cpim::DateTimeHeader::getValue () const {
|
||||
L_D();
|
||||
|
||||
stringstream ss;
|
||||
ss << setfill('0') << setw(4) << d->dateTime.tm_year << "-"
|
||||
<< setfill('0') << setw(2) << d->dateTime.tm_mon + 1 << "-"
|
||||
<< setfill('0') << setw(2) << d->dateTime.tm_mday << "T"
|
||||
<< setfill('0') << setw(2) << d->dateTime.tm_hour << ":"
|
||||
<< setfill('0') << setw(2) << d->dateTime.tm_min << ":"
|
||||
<< setfill('0') << setw(2) << d->dateTime.tm_sec;
|
||||
|
||||
ss << d->signOffset;
|
||||
if (d->signOffset != "Z")
|
||||
ss << setfill('0') << setw(2) << d->dateTimeOffset.tm_hour << ":"
|
||||
<< setfill('0') << setw(2) << d->dateTimeOffset.tm_min;
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
string Cpim::DateTimeHeader::asString () const {
|
||||
return getName() + ": " + getValue() + "\r\n";
|
||||
}
|
||||
|
||||
struct tm Cpim::DateTimeHeader::getTimeStruct () const {
|
||||
L_D();
|
||||
return d->dateTime;
|
||||
}
|
||||
|
||||
struct tm Cpim::DateTimeHeader::getTimeOffset () const {
|
||||
L_D();
|
||||
return d->dateTimeOffset;
|
||||
}
|
||||
|
||||
string Cpim::DateTimeHeader::getSignOffset () const {
|
||||
L_D();
|
||||
return d->signOffset;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void Cpim::CoreHeader::force (const string &value) {
|
||||
Header::setValue(value);
|
||||
class Cpim::NsHeaderPrivate : public HeaderPrivate {
|
||||
public:
|
||||
string uri;
|
||||
string prefixName;
|
||||
};
|
||||
|
||||
Cpim::NsHeader::NsHeader () : Header(*new NsHeaderPrivate) {}
|
||||
|
||||
Cpim::NsHeader::NsHeader (const string &uri, const string &prefixName) : NsHeader() {
|
||||
setUri(uri);
|
||||
setPrefixName(prefixName);
|
||||
}
|
||||
|
||||
string Cpim::NsHeader::getUri () const {
|
||||
L_D();
|
||||
return d->uri;
|
||||
}
|
||||
|
||||
void Cpim::NsHeader::setUri (const string &uri) {
|
||||
L_D();
|
||||
d->uri = uri;
|
||||
}
|
||||
|
||||
string Cpim::NsHeader::getPrefixName () const {
|
||||
L_D();
|
||||
return d->prefixName;
|
||||
}
|
||||
|
||||
void Cpim::NsHeader::setPrefixName (const string &prefixName) {
|
||||
L_D();
|
||||
d->prefixName = prefixName;
|
||||
}
|
||||
|
||||
string Cpim::NsHeader::getValue () const {
|
||||
L_D();
|
||||
|
||||
string ns;
|
||||
if (!d->prefixName.empty())
|
||||
ns = d->prefixName + " ";
|
||||
|
||||
return ns + "<" + d->uri + ">";
|
||||
}
|
||||
|
||||
string Cpim::NsHeader::asString () const {
|
||||
return getName() + ": " + getValue() + "\r\n";
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
class Cpim::RequireHeaderPrivate : public HeaderPrivate {
|
||||
public:
|
||||
list<string> headerNames;
|
||||
};
|
||||
|
||||
Cpim::RequireHeader::RequireHeader () : Header(*new RequireHeaderPrivate) {}
|
||||
|
||||
Cpim::RequireHeader::RequireHeader (const string &headerNames) : RequireHeader() {
|
||||
for (const string &header : Utils::split(headerNames, ",")) {
|
||||
addHeaderName(header);
|
||||
}
|
||||
}
|
||||
|
||||
Cpim::RequireHeader::RequireHeader (const list<string> &headerNames) : RequireHeader() {
|
||||
L_D();
|
||||
d->headerNames = headerNames;
|
||||
}
|
||||
|
||||
list<string> Cpim::RequireHeader::getHeaderNames () const {
|
||||
L_D();
|
||||
return d->headerNames;
|
||||
}
|
||||
|
||||
void Cpim::RequireHeader::addHeaderName (const string &headerName) {
|
||||
L_D();
|
||||
d->headerNames.push_back(headerName);
|
||||
}
|
||||
|
||||
string Cpim::RequireHeader::getValue () const {
|
||||
L_D();
|
||||
|
||||
string requires;
|
||||
for (const string &header : d->headerNames) {
|
||||
if (header != d->headerNames.front())
|
||||
requires += ",";
|
||||
requires += header;
|
||||
}
|
||||
|
||||
return requires;
|
||||
}
|
||||
|
||||
string Cpim::RequireHeader::asString () const {
|
||||
return getName() + ": " + getValue() + "\r\n";
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
class Cpim::SubjectHeaderPrivate : public HeaderPrivate {
|
||||
public:
|
||||
string subject;
|
||||
string language;
|
||||
};
|
||||
|
||||
Cpim::SubjectHeader::SubjectHeader () : CoreHeader(*new SubjectHeaderPrivate) {}
|
||||
Cpim::SubjectHeader::SubjectHeader () : Header(*new SubjectHeaderPrivate) {}
|
||||
|
||||
bool Cpim::SubjectHeader::setValue (const string &value) {
|
||||
return Parser::getInstance()->coreHeaderIsValid<SubjectHeader>(value) && Header::setValue(value);
|
||||
Cpim::SubjectHeader::SubjectHeader (const string &subject, const string &language) : SubjectHeader() {
|
||||
setSubject(subject);
|
||||
setLanguage(language);
|
||||
}
|
||||
|
||||
string Cpim::SubjectHeader::getSubject () const {
|
||||
L_D();
|
||||
return d->subject;
|
||||
}
|
||||
|
||||
void Cpim::SubjectHeader::setSubject (const string &subject) {
|
||||
L_D();
|
||||
d->subject = subject;
|
||||
}
|
||||
|
||||
string Cpim::SubjectHeader::getLanguage () const {
|
||||
|
|
@ -79,30 +314,23 @@ string Cpim::SubjectHeader::getLanguage () const {
|
|||
return d->language;
|
||||
}
|
||||
|
||||
bool Cpim::SubjectHeader::setLanguage (const string &language) {
|
||||
if (!language.empty() && !Parser::getInstance()->subjectHeaderLanguageIsValid(language))
|
||||
return false;
|
||||
|
||||
void Cpim::SubjectHeader::setLanguage (const string &language) {
|
||||
L_D();
|
||||
d->language = language;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
string Cpim::SubjectHeader::asString () const {
|
||||
string Cpim::SubjectHeader::getValue () const {
|
||||
L_D();
|
||||
|
||||
string languageParam;
|
||||
if (!d->language.empty())
|
||||
languageParam = ";lang=" + d->language;
|
||||
|
||||
return getName() + ":" + languageParam + " " + getValue() + "\r\n";
|
||||
return languageParam + " " + d->subject;
|
||||
}
|
||||
|
||||
void Cpim::SubjectHeader::force (const string &value, const string &language) {
|
||||
L_D();
|
||||
CoreHeader::force(value);
|
||||
d->language = language;
|
||||
string Cpim::SubjectHeader::asString () const {
|
||||
return getName() + ":" + getValue() + "\r\n";
|
||||
}
|
||||
|
||||
LINPHONE_END_NAMESPACE
|
||||
|
|
|
|||
|
|
@ -20,60 +20,160 @@
|
|||
#ifndef _L_CPIM_CORE_HEADERS_H_
|
||||
#define _L_CPIM_CORE_HEADERS_H_
|
||||
|
||||
#include <ctime>
|
||||
#include <list>
|
||||
|
||||
#include "cpim-header.h"
|
||||
|
||||
// =============================================================================
|
||||
|
||||
LINPHONE_BEGIN_NAMESPACE
|
||||
|
||||
#define MAKE_CORE_HEADER(CLASS_PREFIX, NAME) \
|
||||
class LINPHONE_PUBLIC CLASS_PREFIX ## Header : public CoreHeader { \
|
||||
#define MAKE_CONTACT_HEADER(CLASS_PREFIX, NAME) \
|
||||
class LINPHONE_PUBLIC CLASS_PREFIX ## Header : public ContactHeader { \
|
||||
public: \
|
||||
CLASS_PREFIX ## Header() = default; \
|
||||
inline std::string getName() const override { \
|
||||
CLASS_PREFIX ## Header () = default; \
|
||||
CLASS_PREFIX ## Header (const std::string &uri, const std::string &formalName = "") : ContactHeader (uri, formalName) {} \
|
||||
inline std::string getName () const override { \
|
||||
return NAME; \
|
||||
} \
|
||||
bool setValue(const std::string &value) override; \
|
||||
private: \
|
||||
L_DISABLE_COPY(CLASS_PREFIX ## Header); \
|
||||
};
|
||||
|
||||
namespace Cpim {
|
||||
class HeaderNode;
|
||||
class DateTimeHeaderNode;
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Generic core header.
|
||||
// Specific Contact headers declaration.
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
class LINPHONE_PUBLIC CoreHeader : public Header {
|
||||
friend class HeaderNode;
|
||||
class ContactHeaderPrivate;
|
||||
|
||||
class LINPHONE_PUBLIC ContactHeader : public Header {
|
||||
public:
|
||||
CoreHeader ();
|
||||
ContactHeader ();
|
||||
|
||||
virtual ~CoreHeader () = 0;
|
||||
ContactHeader (const std::string &uri, const std::string &formalName = "");
|
||||
|
||||
bool isValid () const override;
|
||||
std::string getUri () const;
|
||||
void setUri (const std::string &uri);
|
||||
|
||||
protected:
|
||||
explicit CoreHeader (HeaderPrivate &p);
|
||||
std::string getFormalName () const;
|
||||
void setFormalName (const std::string &formalName);
|
||||
|
||||
void force (const std::string &value);
|
||||
std::string getValue () const override;
|
||||
|
||||
std::string asString () const override;
|
||||
|
||||
private:
|
||||
L_DISABLE_COPY(CoreHeader);
|
||||
L_DECLARE_PRIVATE(ContactHeader);
|
||||
L_DISABLE_COPY(ContactHeader);
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Core headers.
|
||||
|
||||
MAKE_CONTACT_HEADER(From, "From");
|
||||
MAKE_CONTACT_HEADER(To, "To");
|
||||
MAKE_CONTACT_HEADER(Cc, "cc");
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Specific DateTime declaration.
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
MAKE_CORE_HEADER(From, "From");
|
||||
MAKE_CORE_HEADER(To, "To");
|
||||
MAKE_CORE_HEADER(Cc, "cc");
|
||||
MAKE_CORE_HEADER(DateTime, "DateTime");
|
||||
MAKE_CORE_HEADER(Ns, "NS");
|
||||
MAKE_CORE_HEADER(Require, "Require");
|
||||
class DateTimeHeaderPrivate;
|
||||
|
||||
class LINPHONE_PUBLIC DateTimeHeader : public Header {
|
||||
friend class DateTimeHeaderNode;
|
||||
|
||||
public:
|
||||
DateTimeHeader ();
|
||||
|
||||
DateTimeHeader (time_t time);
|
||||
|
||||
DateTimeHeader (const tm &time, const tm &timeOffset, const std::string &signOffset);
|
||||
|
||||
inline std::string getName () const override {
|
||||
return "DateTime";
|
||||
}
|
||||
|
||||
time_t getTime () const;
|
||||
void setTime (const time_t time);
|
||||
|
||||
void setTime (const tm &time, const tm &timeOffset, const std::string &signOffset);
|
||||
|
||||
std::string getValue () const override;
|
||||
|
||||
std::string asString () const override;
|
||||
|
||||
private:
|
||||
tm getTimeStruct () const;
|
||||
tm getTimeOffset () const;
|
||||
std::string getSignOffset () const;
|
||||
|
||||
L_DECLARE_PRIVATE(DateTimeHeader);
|
||||
L_DISABLE_COPY(DateTimeHeader);
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Specific Ns declaration.
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
class NsHeaderPrivate;
|
||||
|
||||
class LINPHONE_PUBLIC NsHeader : public Header {
|
||||
public:
|
||||
NsHeader ();
|
||||
|
||||
NsHeader (const std::string &uri, const std::string &prefixName = "");
|
||||
|
||||
inline std::string getName () const override {
|
||||
return "NS";
|
||||
}
|
||||
|
||||
std::string getPrefixName () const;
|
||||
void setPrefixName (const std::string &prefixName);
|
||||
|
||||
std::string getUri () const;
|
||||
void setUri (const std::string &uri);
|
||||
|
||||
std::string getValue () const override;
|
||||
|
||||
std::string asString () const override;
|
||||
|
||||
private:
|
||||
L_DECLARE_PRIVATE(NsHeader);
|
||||
L_DISABLE_COPY(NsHeader);
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Specific Require declaration.
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
class RequireHeaderPrivate;
|
||||
|
||||
class LINPHONE_PUBLIC RequireHeader : public Header {
|
||||
public:
|
||||
RequireHeader ();
|
||||
|
||||
RequireHeader (const std::string &headerNames);
|
||||
RequireHeader (const std::list<std::string> &headerNames);
|
||||
|
||||
inline std::string getName () const override {
|
||||
return "Require";
|
||||
}
|
||||
|
||||
std::list<std::string> getHeaderNames () const;
|
||||
void addHeaderName (const std::string &headerName);
|
||||
|
||||
std::string getValue () const override;
|
||||
|
||||
std::string asString () const override;
|
||||
|
||||
private:
|
||||
L_DECLARE_PRIVATE(RequireHeader);
|
||||
L_DISABLE_COPY(RequireHeader);
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Specific Subject declaration.
|
||||
|
|
@ -81,33 +181,33 @@ namespace Cpim {
|
|||
|
||||
class SubjectHeaderPrivate;
|
||||
|
||||
class LINPHONE_PUBLIC SubjectHeader : public CoreHeader {
|
||||
friend class HeaderNode;
|
||||
|
||||
class LINPHONE_PUBLIC SubjectHeader : public Header {
|
||||
public:
|
||||
SubjectHeader ();
|
||||
|
||||
SubjectHeader (const std::string &subject, const std::string &language = "");
|
||||
|
||||
inline std::string getName () const override {
|
||||
return "Subject";
|
||||
}
|
||||
|
||||
bool setValue (const std::string &value) override;
|
||||
std::string getSubject () const;
|
||||
void setSubject (const std::string &subject);
|
||||
|
||||
std::string getLanguage () const;
|
||||
bool setLanguage (const std::string &language);
|
||||
void setLanguage (const std::string &language);
|
||||
|
||||
std::string getValue () const override;
|
||||
|
||||
std::string asString () const override;
|
||||
|
||||
protected:
|
||||
void force (const std::string &value, const std::string &language);
|
||||
|
||||
private:
|
||||
L_DECLARE_PRIVATE(SubjectHeader);
|
||||
L_DISABLE_COPY(SubjectHeader);
|
||||
};
|
||||
}
|
||||
|
||||
#undef MAKE_CORE_HEADER
|
||||
#undef MAKE_CONTACT_HEADER
|
||||
|
||||
LINPHONE_END_NAMESPACE
|
||||
|
||||
|
|
|
|||
|
|
@ -34,38 +34,50 @@ LINPHONE_BEGIN_NAMESPACE
|
|||
|
||||
class Cpim::GenericHeaderPrivate : public HeaderPrivate {
|
||||
public:
|
||||
GenericHeaderPrivate () : parameters(make_shared<list<pair<string, string> > >()) {}
|
||||
GenericHeaderPrivate () : parameters(make_shared<list<pair<string, string>>>()) {}
|
||||
|
||||
string name;
|
||||
shared_ptr<list<pair<string, string> > > parameters;
|
||||
string value;
|
||||
shared_ptr<list<pair<string, string>>> parameters;
|
||||
};
|
||||
|
||||
Cpim::GenericHeader::GenericHeader () : Header(*new GenericHeaderPrivate) {}
|
||||
|
||||
Cpim::GenericHeader::GenericHeader (string name, string value, string parameters) : GenericHeader() {
|
||||
setName(name);
|
||||
setValue(value);
|
||||
|
||||
for (const auto ¶meter : Utils::split(parameters, ';')) {
|
||||
size_t equalIndex = parameter.find('=');
|
||||
if (equalIndex != string::npos)
|
||||
addParameter(parameter.substr(0, equalIndex), parameter.substr(equalIndex + 1));
|
||||
}
|
||||
}
|
||||
|
||||
string Cpim::GenericHeader::getName () const {
|
||||
L_D();
|
||||
return d->name;
|
||||
}
|
||||
|
||||
bool Cpim::GenericHeader::setName (const string &name) {
|
||||
void Cpim::GenericHeader::setName (const string &name) {
|
||||
L_D();
|
||||
|
||||
static const set<string> reserved = {
|
||||
"From", "To", "cc", "DateTime", "Subject", "NS", "Require"
|
||||
};
|
||||
|
||||
if (
|
||||
reserved.find(name) != reserved.end() ||
|
||||
!Parser::getInstance()->headerNameIsValid(name)
|
||||
)
|
||||
return false;
|
||||
|
||||
d->name = name;
|
||||
return true;
|
||||
if (reserved.find(name) == reserved.end())
|
||||
d->name = name;
|
||||
}
|
||||
|
||||
bool Cpim::GenericHeader::setValue (const string &value) {
|
||||
return Parser::getInstance()->headerValueIsValid(value) && Header::setValue(value);
|
||||
string Cpim::GenericHeader::getValue () const {
|
||||
L_D();
|
||||
return d->value;
|
||||
}
|
||||
|
||||
void Cpim::GenericHeader::setValue (const string &value) {
|
||||
L_D();
|
||||
d->value = value;
|
||||
}
|
||||
|
||||
Cpim::GenericHeader::ParameterList Cpim::GenericHeader::getParameters () const {
|
||||
|
|
@ -73,14 +85,9 @@ Cpim::GenericHeader::ParameterList Cpim::GenericHeader::getParameters () const {
|
|||
return d->parameters;
|
||||
}
|
||||
|
||||
bool Cpim::GenericHeader::addParameter (const string &key, const string &value) {
|
||||
void Cpim::GenericHeader::addParameter (const string &key, const string &value) {
|
||||
L_D();
|
||||
|
||||
if (!Parser::getInstance()->headerParameterIsValid(key + "=" + value))
|
||||
return false;
|
||||
|
||||
d->parameters->push_back(make_pair(key, value));
|
||||
return true;
|
||||
}
|
||||
|
||||
void Cpim::GenericHeader::removeParameter (const string &key, const string &value) {
|
||||
|
|
@ -88,11 +95,6 @@ void Cpim::GenericHeader::removeParameter (const string &key, const string &valu
|
|||
d->parameters->remove(make_pair(key, value));
|
||||
}
|
||||
|
||||
bool Cpim::GenericHeader::isValid () const {
|
||||
L_D();
|
||||
return !d->name.empty() && !getValue().empty();
|
||||
}
|
||||
|
||||
string Cpim::GenericHeader::asString () const {
|
||||
L_D();
|
||||
|
||||
|
|
@ -103,21 +105,4 @@ string Cpim::GenericHeader::asString () const {
|
|||
return d->name + ":" + parameters + " " + getValue() + "\r\n";
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void Cpim::GenericHeader::force (const string &name, const string &value, const string ¶meters) {
|
||||
L_D();
|
||||
|
||||
// Set name/value.
|
||||
d->name = name;
|
||||
Header::setValue(value);
|
||||
|
||||
// Parse and build parameters list.
|
||||
for (const auto ¶meter : Utils::split(parameters, ';')) {
|
||||
size_t equalIndex = parameter.find('=');
|
||||
if (equalIndex != string::npos)
|
||||
d->parameters->push_back(make_pair(parameter.substr(0, equalIndex), parameter.substr(equalIndex + 1)));
|
||||
}
|
||||
}
|
||||
|
||||
LINPHONE_END_NAMESPACE
|
||||
|
|
|
|||
|
|
@ -38,24 +38,22 @@ namespace Cpim {
|
|||
public:
|
||||
GenericHeader ();
|
||||
|
||||
GenericHeader (std::string name, std::string value, std::string parameters = "");
|
||||
|
||||
std::string getName () const override;
|
||||
bool setName (const std::string &name);
|
||||
void setName (const std::string &name);
|
||||
|
||||
bool setValue (const std::string &value) override;
|
||||
std::string getValue () const override;
|
||||
void setValue (const std::string &value);
|
||||
|
||||
typedef std::shared_ptr<const std::list<std::pair<std::string, std::string> > > ParameterList;
|
||||
typedef std::shared_ptr<const std::list<std::pair<std::string, std::string>>> ParameterList;
|
||||
|
||||
ParameterList getParameters () const;
|
||||
bool addParameter (const std::string &key, const std::string &value);
|
||||
void addParameter (const std::string &key, const std::string &value);
|
||||
void removeParameter (const std::string &key, const std::string &value);
|
||||
|
||||
bool isValid () const override;
|
||||
|
||||
std::string asString () const override;
|
||||
|
||||
protected:
|
||||
void force (const std::string &name, const std::string &value, const std::string ¶meters);
|
||||
|
||||
private:
|
||||
L_DECLARE_PRIVATE(GenericHeader);
|
||||
L_DISABLE_COPY(GenericHeader);
|
||||
|
|
|
|||
|
|
@ -30,8 +30,6 @@ LINPHONE_BEGIN_NAMESPACE
|
|||
namespace Cpim {
|
||||
class HeaderPrivate : public ObjectPrivate {
|
||||
private:
|
||||
std::string value;
|
||||
|
||||
L_DECLARE_PUBLIC(Header);
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,20 +29,4 @@ LINPHONE_BEGIN_NAMESPACE
|
|||
|
||||
Cpim::Header::Header (HeaderPrivate &p) : Object(p) {}
|
||||
|
||||
string Cpim::Header::getValue () const {
|
||||
L_D();
|
||||
return d->value;
|
||||
}
|
||||
|
||||
bool Cpim::Header::setValue (const string &value) {
|
||||
L_D();
|
||||
d->value = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
string Cpim::Header::asString () const {
|
||||
L_D();
|
||||
return getName() + ": " + d->value + "\r\n";
|
||||
}
|
||||
|
||||
LINPHONE_END_NAMESPACE
|
||||
|
|
|
|||
|
|
@ -35,12 +35,9 @@ namespace Cpim {
|
|||
|
||||
virtual std::string getName () const = 0;
|
||||
|
||||
std::string getValue () const;
|
||||
virtual bool setValue (const std::string &value);
|
||||
virtual std::string getValue () const = 0;
|
||||
|
||||
virtual bool isValid () const = 0;
|
||||
|
||||
virtual std::string asString () const;
|
||||
virtual std::string asString () const = 0;
|
||||
|
||||
protected:
|
||||
explicit Header (HeaderPrivate &p);
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
|
||||
#include "linphone/utils/utils.h"
|
||||
|
||||
|
|
@ -36,10 +37,10 @@ LINPHONE_BEGIN_NAMESPACE
|
|||
|
||||
class Cpim::MessagePrivate : public ObjectPrivate {
|
||||
public:
|
||||
typedef list<shared_ptr<const Header> > PrivHeaderList;
|
||||
using PrivHeaderList = list<shared_ptr<const Header>>;
|
||||
using PrivHeaderMap = map<string, shared_ptr<PrivHeaderList>>;
|
||||
|
||||
shared_ptr<PrivHeaderList> cpimHeaders = make_shared<PrivHeaderList>(); // TODO: Remove this useless variable
|
||||
shared_ptr<PrivHeaderList> messageHeaders = make_shared<PrivHeaderList>();
|
||||
PrivHeaderMap messageHeaders;
|
||||
shared_ptr<PrivHeaderList> contentHeaders = make_shared<PrivHeaderList>();
|
||||
string content;
|
||||
};
|
||||
|
|
@ -48,50 +49,47 @@ Cpim::Message::Message () : Object(*new MessagePrivate) {}
|
|||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
Cpim::Message::HeaderList Cpim::Message::getCpimHeaders () const {
|
||||
Cpim::Message::HeaderList Cpim::Message::getMessageHeaders (const string &ns) const {
|
||||
L_D();
|
||||
return d->cpimHeaders;
|
||||
|
||||
if (d->messageHeaders.find(ns) == d->messageHeaders.end())
|
||||
return nullptr;
|
||||
|
||||
return d->messageHeaders.at(ns);
|
||||
}
|
||||
|
||||
bool Cpim::Message::addCpimHeader (const Header &cpimHeader) {
|
||||
void Cpim::Message::addMessageHeader (const Header &messageHeader, const string &ns) {
|
||||
L_D();
|
||||
|
||||
if (!cpimHeader.isValid())
|
||||
return false;
|
||||
if (d->messageHeaders.find(ns) == d->messageHeaders.end())
|
||||
d->messageHeaders[ns] = make_shared<Cpim::MessagePrivate::PrivHeaderList>();
|
||||
|
||||
d->cpimHeaders->push_back(Parser::getInstance()->cloneHeader(cpimHeader));
|
||||
return true;
|
||||
auto list = d->messageHeaders.at(ns);
|
||||
list->push_back(Parser::getInstance()->cloneHeader(messageHeader));
|
||||
}
|
||||
|
||||
void Cpim::Message::removeCpimHeader (const Header &cpimHeader) {
|
||||
void Cpim::Message::removeMessageHeader (const Header &messageHeader, const string &ns) {
|
||||
L_D();
|
||||
d->cpimHeaders->remove_if([&cpimHeader](const shared_ptr<const Header> &header) {
|
||||
return cpimHeader.getName() == header->getName() && cpimHeader.getValue() == header->getValue();
|
||||
});
|
||||
|
||||
if (d->messageHeaders.find(ns) != d->messageHeaders.end())
|
||||
d->messageHeaders.at(ns)->remove_if([&messageHeader](const shared_ptr<const Header> &header) {
|
||||
return messageHeader.getName() == header->getName() && messageHeader.getValue() == header->getValue();
|
||||
});
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
Cpim::Message::HeaderList Cpim::Message::getMessageHeaders () const {
|
||||
L_D();
|
||||
return d->messageHeaders;
|
||||
}
|
||||
|
||||
bool Cpim::Message::addMessageHeader (const Header &messageHeader) {
|
||||
shared_ptr<const Cpim::Header> Cpim::Message::getMessageHeader (const string &name, const string &ns) const {
|
||||
L_D();
|
||||
|
||||
if (!messageHeader.isValid())
|
||||
return false;
|
||||
if (d->messageHeaders.find(ns) == d->messageHeaders.end())
|
||||
return nullptr;
|
||||
|
||||
d->messageHeaders->push_back(Parser::getInstance()->cloneHeader(messageHeader));
|
||||
return true;
|
||||
}
|
||||
auto list = d->messageHeaders.at(ns);
|
||||
for (const auto &messageHeader : *list) {
|
||||
if (messageHeader->getName() == name)
|
||||
return messageHeader;
|
||||
}
|
||||
|
||||
void Cpim::Message::removeMessageHeader (const Header &messageHeader) {
|
||||
L_D();
|
||||
d->messageHeaders->remove_if([&messageHeader](const shared_ptr<const Header> &header) {
|
||||
return messageHeader.getName() == header->getName() && messageHeader.getValue() == header->getValue();
|
||||
});
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
@ -101,14 +99,9 @@ Cpim::Message::HeaderList Cpim::Message::getContentHeaders () const {
|
|||
return d->contentHeaders;
|
||||
}
|
||||
|
||||
bool Cpim::Message::addContentHeader (const Header &contentHeader) {
|
||||
void Cpim::Message::addContentHeader (const Header &contentHeader) {
|
||||
L_D();
|
||||
|
||||
if (!contentHeader.isValid())
|
||||
return false;
|
||||
|
||||
d->contentHeaders->push_back(Parser::getInstance()->cloneHeader(contentHeader));
|
||||
return true;
|
||||
}
|
||||
|
||||
void Cpim::Message::removeContentHeader (const Header &contentHeader) {
|
||||
|
|
@ -118,6 +111,17 @@ void Cpim::Message::removeContentHeader (const Header &contentHeader) {
|
|||
});
|
||||
}
|
||||
|
||||
shared_ptr<const Cpim::Header> Cpim::Message::getContentHeader(const string &name) const {
|
||||
L_D();
|
||||
|
||||
for (const auto &contentHeader : *d->contentHeaders) {
|
||||
if (contentHeader->getName() == name)
|
||||
return contentHeader;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
string Cpim::Message::getContent () const {
|
||||
|
|
@ -133,32 +137,19 @@ bool Cpim::Message::setContent (const string &content) {
|
|||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
bool Cpim::Message::isValid () const {
|
||||
L_D();
|
||||
|
||||
return find_if(d->cpimHeaders->cbegin(), d->cpimHeaders->cend(),
|
||||
[](const shared_ptr<const Header> &header) {
|
||||
return Utils::iequals(header->getName(), "content-type") && (ContentType(header->getValue()) == ContentType::Cpim);
|
||||
}) != d->cpimHeaders->cend();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
string Cpim::Message::asString () const {
|
||||
L_D();
|
||||
|
||||
string output;
|
||||
// TODO: Remove cpimHeaders
|
||||
if (d->cpimHeaders->size() > 0) {
|
||||
for (const auto &cpimHeader : *d->cpimHeaders)
|
||||
output += cpimHeader->asString();
|
||||
output += "\r\n";
|
||||
}
|
||||
// TODO Remove cpimHeaders
|
||||
|
||||
if (d->messageHeaders->size() > 0) {
|
||||
for (const auto &messageHeader : *d->messageHeaders)
|
||||
output += messageHeader->asString();
|
||||
if (d->messageHeaders.size() > 0) {
|
||||
for (const auto &entry : d->messageHeaders) {
|
||||
auto list = entry.second;
|
||||
for (const auto &messageHeader : *list) {
|
||||
if (entry.first != "")
|
||||
output += entry.first + ".";
|
||||
output += messageHeader->asString();
|
||||
}
|
||||
}
|
||||
|
||||
output += "\r\n";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,27 +34,21 @@ namespace Cpim {
|
|||
public:
|
||||
Message ();
|
||||
|
||||
typedef std::shared_ptr<std::list<std::shared_ptr<const Cpim::Header> > > HeaderList;
|
||||
typedef std::shared_ptr<std::list<std::shared_ptr<const Cpim::Header>>> HeaderList;
|
||||
|
||||
// TODO: Remove these useless methods
|
||||
HeaderList getCpimHeaders () const;
|
||||
bool addCpimHeader (const Header &cpimHeader);
|
||||
void removeCpimHeader (const Header &cpimHeader);
|
||||
// TODO: Remove these useless methods
|
||||
HeaderList getMessageHeaders (const std::string &ns = "") const;
|
||||
void addMessageHeader (const Header &messageHeader, const std::string &ns = "");
|
||||
void removeMessageHeader (const Header &messageHeader, const std::string &ns = "");
|
||||
std::shared_ptr<const Cpim::Header> getMessageHeader (const std::string &name, const std::string &ns = "") const;
|
||||
|
||||
HeaderList getMessageHeaders () const;
|
||||
bool addMessageHeader (const Header &messageHeader);
|
||||
void removeMessageHeader (const Header &messageHeader);
|
||||
|
||||
HeaderList getContentHeaders () const;
|
||||
bool addContentHeader (const Header &contentHeader);
|
||||
void addContentHeader (const Header &contentHeader);
|
||||
void removeContentHeader (const Header &contentHeader);
|
||||
std::shared_ptr<const Cpim::Header> getContentHeader (const std::string &name) const;
|
||||
|
||||
std::string getContent () const;
|
||||
bool setContent (const std::string &content);
|
||||
|
||||
bool isValid () const; // TODO: Remove this useless method
|
||||
|
||||
std::string asString () const;
|
||||
|
||||
static std::shared_ptr<const Message> createFromString (const std::string &str);
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <unordered_map>
|
||||
#include <set>
|
||||
|
||||
#include <belr/abnf.h>
|
||||
#include <belr/grammarbuilder.h>
|
||||
|
|
@ -53,20 +53,10 @@ namespace Cpim {
|
|||
HeaderNode () = default;
|
||||
|
||||
explicit HeaderNode (const Header &header) : mName(header.getName()), mValue(header.getValue()) {
|
||||
// Generic header.
|
||||
const GenericHeader *genericHeader = dynamic_cast<const GenericHeader *>(&header);
|
||||
if (genericHeader) {
|
||||
for (const auto ¶meter : *genericHeader->getParameters())
|
||||
mParameters += ";" + parameter.first + "=" + parameter.second;
|
||||
return;
|
||||
}
|
||||
|
||||
// Subject header.
|
||||
const SubjectHeader *subjectHeader = dynamic_cast<const SubjectHeader *>(&header);
|
||||
if (subjectHeader) {
|
||||
const string language = subjectHeader->getLanguage();
|
||||
if (!language.empty())
|
||||
mParameters = ";lang=" + language;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -75,7 +65,12 @@ namespace Cpim {
|
|||
}
|
||||
|
||||
void setName (const string &name) {
|
||||
mName = name;
|
||||
static const set<string> reserved = {
|
||||
"From", "To", "cc", "DateTime", "Subject", "NS", "Require"
|
||||
};
|
||||
|
||||
if (reserved.find(name) == reserved.end())
|
||||
mName = name;
|
||||
}
|
||||
|
||||
string getParameters () const {
|
||||
|
|
@ -94,67 +89,425 @@ namespace Cpim {
|
|||
mValue = value;
|
||||
}
|
||||
|
||||
shared_ptr<Header> createHeader (bool force) const;
|
||||
virtual shared_ptr<Header> createHeader () const;
|
||||
|
||||
virtual bool isValid () const;
|
||||
|
||||
private:
|
||||
template<typename T>
|
||||
shared_ptr<Header> createCoreHeader (bool force) const {
|
||||
shared_ptr<T> header = make_shared<T>();
|
||||
if (force)
|
||||
header->force(mValue);
|
||||
else if (!header->setValue(mValue)) {
|
||||
lWarning() << "Unable to set value on core header: `" << mName << "` => `" << mValue << "`.";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
string mName;
|
||||
string mValue;
|
||||
string mParameters;
|
||||
};
|
||||
|
||||
template<>
|
||||
shared_ptr<Header> HeaderNode::createCoreHeader<SubjectHeader>(bool force) const {
|
||||
shared_ptr<SubjectHeader> header = make_shared<SubjectHeader>();
|
||||
const string language = mParameters.length() >= 6 ? mParameters.substr(6) : "";
|
||||
|
||||
if (force)
|
||||
header->force(mValue, language);
|
||||
else if (!header->setValue(mValue) || (!language.empty() && !header->setLanguage(language))) {
|
||||
lWarning() << "Unable to set value on subject header: `" <<
|
||||
mName << "` => `" << mValue << "`, `" << language << "`.";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return header;
|
||||
bool HeaderNode::isValid () const {
|
||||
return !mName.empty() && !mValue.empty();
|
||||
}
|
||||
|
||||
shared_ptr<Header> HeaderNode::createHeader (bool force = false) const {
|
||||
static const unordered_map<string, shared_ptr<Header>(HeaderNode::*)(bool)const> reservedHandlers = {
|
||||
{ "From", &HeaderNode::createCoreHeader<FromHeader> },
|
||||
{ "To", &HeaderNode::createCoreHeader<ToHeader> },
|
||||
{ "cc", &HeaderNode::createCoreHeader<CcHeader> },
|
||||
{ "DateTime", &HeaderNode::createCoreHeader<DateTimeHeader> },
|
||||
{ "Subject", &HeaderNode::createCoreHeader<SubjectHeader> },
|
||||
{ "NS", &HeaderNode::createCoreHeader<NsHeader> },
|
||||
{ "Require", &HeaderNode::createCoreHeader<RequireHeader> }
|
||||
};
|
||||
shared_ptr<Header> HeaderNode::createHeader () const {
|
||||
if (!isValid())
|
||||
return nullptr;
|
||||
|
||||
// Core Header.
|
||||
const auto it = reservedHandlers.find(mName);
|
||||
if (it != reservedHandlers.cend())
|
||||
return (this->*it->second)(force);
|
||||
|
||||
// Generic Header
|
||||
shared_ptr<GenericHeader> genericHeader = make_shared<GenericHeader>();
|
||||
genericHeader->force(mName, mValue, mParameters);
|
||||
genericHeader->setName(mName);
|
||||
|
||||
for (const auto ¶meter : Utils::split(mParameters, ';')) {
|
||||
size_t equalIndex = parameter.find('=');
|
||||
if (equalIndex != string::npos)
|
||||
genericHeader->addParameter(parameter.substr(0, equalIndex), parameter.substr(equalIndex + 1));
|
||||
}
|
||||
|
||||
genericHeader->setValue(mValue);
|
||||
return genericHeader;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
class ContactHeaderNode : public HeaderNode {
|
||||
public:
|
||||
ContactHeaderNode () = default;
|
||||
|
||||
string getFormalName () const {
|
||||
return mFormalName;
|
||||
}
|
||||
|
||||
void setFormalName (const string &formalName) {
|
||||
mFormalName = formalName;
|
||||
}
|
||||
|
||||
string getUri () const {
|
||||
return mUri;
|
||||
}
|
||||
|
||||
void setUri (const string &uri) {
|
||||
mUri = uri;
|
||||
}
|
||||
|
||||
bool isValid () const override;
|
||||
|
||||
private:
|
||||
string mFormalName;
|
||||
string mUri;
|
||||
};
|
||||
|
||||
bool ContactHeaderNode::isValid () const {
|
||||
return !mUri.empty();
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
class FromHeaderNode : public ContactHeaderNode {
|
||||
public:
|
||||
FromHeaderNode () = default;
|
||||
|
||||
explicit FromHeaderNode (const Header &header) {
|
||||
const FromHeader *fromHeader = dynamic_cast<const FromHeader *>(&header);
|
||||
if (fromHeader) {
|
||||
setFormalName(fromHeader->getFormalName());
|
||||
setUri(fromHeader->getUri());
|
||||
}
|
||||
}
|
||||
|
||||
shared_ptr<Header> createHeader () const override;
|
||||
};
|
||||
|
||||
shared_ptr<Header> FromHeaderNode::createHeader () const {
|
||||
if (!isValid())
|
||||
return nullptr;
|
||||
|
||||
return make_shared<FromHeader>(getUri(), getFormalName());
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
class ToHeaderNode : public ContactHeaderNode {
|
||||
public:
|
||||
ToHeaderNode () = default;
|
||||
|
||||
explicit ToHeaderNode (const Header &header) {
|
||||
const ToHeader *toHeader = dynamic_cast<const ToHeader *>(&header);
|
||||
if (toHeader) {
|
||||
setFormalName(toHeader->getFormalName());
|
||||
setUri(toHeader->getUri());
|
||||
}
|
||||
}
|
||||
|
||||
shared_ptr<Header> createHeader () const override;
|
||||
};
|
||||
|
||||
shared_ptr<Header> ToHeaderNode::createHeader () const {
|
||||
if (!isValid())
|
||||
return nullptr;
|
||||
|
||||
return make_shared<ToHeader>(getUri(), getFormalName());
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
class CcHeaderNode : public ContactHeaderNode {
|
||||
public:
|
||||
CcHeaderNode () = default;
|
||||
|
||||
explicit CcHeaderNode (const Header &header) {
|
||||
const CcHeader *ccHeader = dynamic_cast<const CcHeader *>(&header);
|
||||
if (ccHeader) {
|
||||
setFormalName(ccHeader->getFormalName());
|
||||
setUri(ccHeader->getUri());
|
||||
}
|
||||
}
|
||||
|
||||
shared_ptr<Header> createHeader () const override;
|
||||
};
|
||||
|
||||
shared_ptr<Header> CcHeaderNode::createHeader () const {
|
||||
if (!isValid())
|
||||
return nullptr;
|
||||
|
||||
return make_shared<CcHeader>(getUri(), getFormalName());
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
class DateTimeOffsetNode : public Node {
|
||||
friend class DateTimeHeaderNode;
|
||||
|
||||
public:
|
||||
DateTimeOffsetNode () {
|
||||
mSign = "Z";
|
||||
}
|
||||
|
||||
void setHour (const string &value) {
|
||||
mHour = Utils::stoi(value);
|
||||
}
|
||||
|
||||
void setMinute (const string &value) {
|
||||
mMinute = Utils::stoi(value);
|
||||
}
|
||||
|
||||
void setSign (const string &value) {
|
||||
mSign = value;
|
||||
}
|
||||
|
||||
private:
|
||||
string mSign;
|
||||
int mHour;
|
||||
int mMinute;
|
||||
};
|
||||
|
||||
class DateTimeHeaderNode : public HeaderNode {
|
||||
public:
|
||||
DateTimeHeaderNode () = default;
|
||||
|
||||
explicit DateTimeHeaderNode (const Header &header) {
|
||||
const DateTimeHeader *dateTimeHeader = dynamic_cast<const DateTimeHeader *>(&header);
|
||||
if (dateTimeHeader) {
|
||||
setTime(dateTimeHeader->getTimeStruct());
|
||||
setTimeOffset(dateTimeHeader->getTimeOffset());
|
||||
setSignOffset(dateTimeHeader->getSignOffset());
|
||||
}
|
||||
}
|
||||
|
||||
struct tm getTime () const {
|
||||
return mTime;
|
||||
}
|
||||
|
||||
void setTime (const struct tm &time) {
|
||||
mTime = time;
|
||||
}
|
||||
|
||||
struct tm getTimeOffset () const {
|
||||
return mTimeOffset;
|
||||
}
|
||||
|
||||
void setTimeOffset (const struct tm &timeOffset) {
|
||||
mTimeOffset = timeOffset;
|
||||
}
|
||||
|
||||
string getSignOffset () const {
|
||||
return mSignOffset;
|
||||
}
|
||||
|
||||
void setSignOffset (const string &signOffset) {
|
||||
mSignOffset = signOffset;
|
||||
}
|
||||
|
||||
void setYear (const string &value) {
|
||||
mTime.tm_year = Utils::stoi(value);
|
||||
}
|
||||
|
||||
void setMonth (const string &value) {
|
||||
mTime.tm_mon = Utils::stoi(value) - 1;
|
||||
}
|
||||
|
||||
void setMonthDay (const string &value) {
|
||||
mTime.tm_mday = Utils::stoi(value);
|
||||
}
|
||||
|
||||
void setHour (const string &value) {
|
||||
mTime.tm_hour = Utils::stoi(value);
|
||||
}
|
||||
|
||||
void setMinute (const string &value) {
|
||||
mTime.tm_min = Utils::stoi(value);
|
||||
}
|
||||
|
||||
void setSecond (const string &value) {
|
||||
mTime.tm_sec = Utils::stoi(value);
|
||||
}
|
||||
|
||||
void setOffset (const shared_ptr<DateTimeOffsetNode> &offset) {
|
||||
mTimeOffset.tm_hour = offset->mHour;
|
||||
mTimeOffset.tm_min = offset->mMinute;
|
||||
mSignOffset = offset->mSign;
|
||||
}
|
||||
|
||||
bool isValid () const override;
|
||||
|
||||
shared_ptr<Header> createHeader() const override;
|
||||
|
||||
private:
|
||||
tm mTime;
|
||||
tm mTimeOffset;
|
||||
string mSignOffset;
|
||||
};
|
||||
|
||||
bool DateTimeHeaderNode::isValid () const {
|
||||
static const int daysInMonth[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
|
||||
|
||||
// Check date.
|
||||
const bool isLeapYear = (mTime.tm_year % 4 == 0 && mTime.tm_year % 100 != 0) || mTime.tm_year % 400 == 0;
|
||||
|
||||
if (mTime.tm_mon < 1 || mTime.tm_mon > 12)
|
||||
return false;
|
||||
|
||||
if (mTime.tm_mday < 1 || (mTime.tm_mon == 2 && isLeapYear ? mTime.tm_mday > 29 : mTime.tm_mday > daysInMonth[mTime.tm_mon - 1]))
|
||||
return false;
|
||||
|
||||
// Check time.
|
||||
if (mTime.tm_hour > 24 || mTime.tm_min > 59 || mTime.tm_sec > 60)
|
||||
return false;
|
||||
|
||||
// Check num offset.
|
||||
if (mSignOffset != "Z") {
|
||||
if (mTimeOffset.tm_hour > 24 || mTime.tm_min > 59)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
shared_ptr<Header> DateTimeHeaderNode::createHeader () const {
|
||||
if (!isValid())
|
||||
return nullptr;
|
||||
|
||||
return make_shared<DateTimeHeader>(getTime(), getTimeOffset(), getSignOffset());
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
class SubjectHeaderNode : public HeaderNode {
|
||||
public:
|
||||
SubjectHeaderNode () = default;
|
||||
|
||||
explicit SubjectHeaderNode (const Header &header) {
|
||||
const SubjectHeader *subjectHeader = dynamic_cast<const SubjectHeader *>(&header);
|
||||
if (subjectHeader) {
|
||||
setLanguage(subjectHeader->getLanguage());
|
||||
setSubject(subjectHeader->getSubject());
|
||||
}
|
||||
}
|
||||
|
||||
string getLanguage () const {
|
||||
return mLanguage;
|
||||
}
|
||||
|
||||
void setLanguage (const string &language) {
|
||||
mLanguage = language;
|
||||
}
|
||||
|
||||
string getSubject () const {
|
||||
return mSubject;
|
||||
}
|
||||
|
||||
void setSubject (const string &subject) {
|
||||
mSubject = subject;
|
||||
}
|
||||
|
||||
bool isValid () const override;
|
||||
|
||||
shared_ptr<Header> createHeader () const override;
|
||||
|
||||
private:
|
||||
string mLanguage;
|
||||
string mSubject;
|
||||
};
|
||||
|
||||
bool SubjectHeaderNode::isValid () const {
|
||||
return !mSubject.empty();
|
||||
}
|
||||
|
||||
shared_ptr<Header> SubjectHeaderNode::createHeader () const {
|
||||
if (!isValid())
|
||||
return nullptr;
|
||||
|
||||
return make_shared<SubjectHeader>(getSubject(), getLanguage());
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
class NsHeaderNode : public HeaderNode {
|
||||
public:
|
||||
NsHeaderNode () = default;
|
||||
|
||||
explicit NsHeaderNode (const Header &header) {
|
||||
const NsHeader *nsHeader = dynamic_cast<const NsHeader *>(&header);
|
||||
if (nsHeader) {
|
||||
setPrefixName(nsHeader->getPrefixName());
|
||||
setUri(nsHeader->getUri());
|
||||
}
|
||||
}
|
||||
|
||||
string getPrefixName () const {
|
||||
return mPrefixName;
|
||||
}
|
||||
|
||||
void setPrefixName (const string &prefixName) {
|
||||
mPrefixName = prefixName;
|
||||
}
|
||||
|
||||
string getUri () const {
|
||||
return mUri;
|
||||
}
|
||||
|
||||
void setUri (const string &uri) {
|
||||
mUri = uri;
|
||||
}
|
||||
|
||||
bool isValid () const override;
|
||||
|
||||
shared_ptr<Header> createHeader () const override;
|
||||
|
||||
private:
|
||||
string mPrefixName;
|
||||
string mUri;
|
||||
};
|
||||
|
||||
bool NsHeaderNode::isValid () const {
|
||||
return !mUri.empty();
|
||||
}
|
||||
|
||||
shared_ptr<Header> NsHeaderNode::createHeader () const {
|
||||
if (!isValid())
|
||||
return nullptr;
|
||||
|
||||
return make_shared<NsHeader>(getUri(), getPrefixName());
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
class RequireHeaderNode : public HeaderNode {
|
||||
public:
|
||||
RequireHeaderNode () = default;
|
||||
|
||||
explicit RequireHeaderNode (const Header &header) {
|
||||
const RequireHeader *requireHeader = dynamic_cast<const RequireHeader *>(&header);
|
||||
if (requireHeader) {
|
||||
for (const auto &header : requireHeader->getHeaderNames()) {
|
||||
if (header != requireHeader->getHeaderNames().front())
|
||||
mHeaderNames += ",";
|
||||
mHeaderNames += header;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
string getHeaderNames () const {
|
||||
return mHeaderNames;
|
||||
}
|
||||
|
||||
void setHeaderNames (const string &headerNames) {
|
||||
mHeaderNames = headerNames;
|
||||
}
|
||||
|
||||
bool isValid () const override;
|
||||
|
||||
shared_ptr<Header> createHeader () const override;
|
||||
|
||||
private:
|
||||
string mHeaderNames;
|
||||
};
|
||||
|
||||
bool RequireHeaderNode::isValid () const {
|
||||
return !mHeaderNames.empty();
|
||||
}
|
||||
|
||||
shared_ptr<Header> RequireHeaderNode::createHeader () const {
|
||||
if (!isValid())
|
||||
return nullptr;
|
||||
|
||||
return make_shared<RequireHeader>(mHeaderNames);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
class ListHeaderNode :
|
||||
public Node,
|
||||
public list<shared_ptr<HeaderNode> > {};
|
||||
|
|
@ -163,67 +516,61 @@ namespace Cpim {
|
|||
|
||||
class MessageNode : public Node {
|
||||
public:
|
||||
void addHeaders (const shared_ptr<ListHeaderNode> &headers) {
|
||||
mHeaders->push_back(headers);
|
||||
void addMessageHeaders (const shared_ptr<ListHeaderNode> &headers) {
|
||||
for (const auto &headerNode : *headers) {
|
||||
mMessageHeaders.push_back(headerNode);
|
||||
}
|
||||
}
|
||||
|
||||
void addContentHeaders (const shared_ptr<ListHeaderNode> &headers) {
|
||||
for (const auto &headerNode : *headers) {
|
||||
mContentHeaders.push_back(headerNode);
|
||||
}
|
||||
}
|
||||
|
||||
// Warning: Call this function one time!
|
||||
shared_ptr<Message> createMessage () const {
|
||||
size_t size = mHeaders->size();
|
||||
if (size < 2 || size > 3) { // TODO: Check that size is == 2
|
||||
if (mContentHeaders.empty() || mMessageHeaders.empty()) {
|
||||
lWarning() << "Bad headers lists size.";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//TODO: Verify all headers from other namespaces
|
||||
|
||||
const shared_ptr<Message> message = make_shared<Message>();
|
||||
|
||||
// TODO: To remove
|
||||
if (size == 3) {
|
||||
const shared_ptr<ListHeaderNode> cpimHeaders = mHeaders->front();
|
||||
if (find_if(cpimHeaders->cbegin(), cpimHeaders->cend(),
|
||||
[](const shared_ptr<const HeaderNode> &headerNode) {
|
||||
return Utils::iequals(headerNode->getName(), "content-type") && (ContentType(headerNode->getValue()) == ContentType::Cpim);
|
||||
}) == cpimHeaders->cend()) {
|
||||
lWarning() << "No MIME `Content-Type` found!";
|
||||
// Add message headers.
|
||||
for (const auto &headerNode : mMessageHeaders) {
|
||||
string ns = "";
|
||||
|
||||
string::size_type n = headerNode->getName().find(".");
|
||||
if (n != string::npos) {
|
||||
ns = headerNode->getName().substr(0, n);
|
||||
headerNode->setName(headerNode->getName().substr(n + 1));
|
||||
}
|
||||
|
||||
const shared_ptr<const Header> header = headerNode->createHeader();
|
||||
if (!header)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Add MIME headers.
|
||||
for (const auto &headerNode : *cpimHeaders) {
|
||||
const shared_ptr<const Header> header = headerNode->createHeader();
|
||||
if (!header || !message->addCpimHeader(*header))
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Add message headers.
|
||||
for (const auto &headerNode : **(++mHeaders->cbegin())) {
|
||||
const shared_ptr<const Header> header = headerNode->createHeader();
|
||||
if (!header || !message->addMessageHeader(*header))
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
// TODO: To remove
|
||||
else {
|
||||
// Add message headers.
|
||||
for (const auto &headerNode : *mHeaders->front()) {
|
||||
const shared_ptr<const Header> header = headerNode->createHeader();
|
||||
if (!header || !message->addMessageHeader(*header))
|
||||
return nullptr;
|
||||
}
|
||||
message->addMessageHeader(*header, ns);
|
||||
}
|
||||
|
||||
// Add content headers.
|
||||
for (const auto &headerNode : *mHeaders->back()) {
|
||||
for (const auto &headerNode : mContentHeaders) {
|
||||
const shared_ptr<const Header> header = headerNode->createHeader();
|
||||
if (!header || !message->addContentHeader(*header))
|
||||
if (!header)
|
||||
return nullptr;
|
||||
|
||||
message->addContentHeader(*header);
|
||||
}
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
private:
|
||||
shared_ptr<list<shared_ptr<ListHeaderNode> > > mHeaders = make_shared<list<shared_ptr<ListHeaderNode> > >();
|
||||
list<shared_ptr<HeaderNode>> mContentHeaders;
|
||||
list<shared_ptr<HeaderNode>> mMessageHeaders;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -260,27 +607,64 @@ shared_ptr<Cpim::Message> Cpim::Parser::parseMessage (const string &input) {
|
|||
typedef void (list<shared_ptr<HeaderNode> >::*pushPtr)(const shared_ptr<HeaderNode> &value);
|
||||
|
||||
belr::Parser<shared_ptr<Node> > parser(d->grammar);
|
||||
parser.setHandler(
|
||||
"Message", belr::make_fn(make_shared<MessageNode> )
|
||||
)->setCollector(
|
||||
"Headers", belr::make_sfn(&MessageNode::addHeaders)
|
||||
);
|
||||
parser.setHandler("Message", belr::make_fn(make_shared<MessageNode>))
|
||||
->setCollector("Message-headers", belr::make_sfn(&MessageNode::addMessageHeaders))
|
||||
->setCollector("Content-headers", belr::make_sfn(&MessageNode::addContentHeaders));
|
||||
|
||||
parser.setHandler(
|
||||
"Headers", belr::make_fn(make_shared<ListHeaderNode> )
|
||||
)->setCollector(
|
||||
"Header", belr::make_sfn(static_cast<pushPtr>(&ListHeaderNode::push_back))
|
||||
);
|
||||
parser.setHandler("Message-headers", belr::make_fn(make_shared<ListHeaderNode>))
|
||||
->setCollector("Header", belr::make_sfn(static_cast<pushPtr>(&ListHeaderNode::push_back)))
|
||||
->setCollector("From-header", belr::make_sfn(static_cast<pushPtr>(&ListHeaderNode::push_back)))
|
||||
->setCollector("To-header", belr::make_sfn(static_cast<pushPtr>(&ListHeaderNode::push_back)))
|
||||
->setCollector("DateTime-header", belr::make_sfn(static_cast<pushPtr>(&ListHeaderNode::push_back)))
|
||||
->setCollector("cc-header", belr::make_sfn(static_cast<pushPtr>(&ListHeaderNode::push_back)))
|
||||
->setCollector("Subject-header", belr::make_sfn(static_cast<pushPtr>(&ListHeaderNode::push_back)))
|
||||
->setCollector("NS-header", belr::make_sfn(static_cast<pushPtr>(&ListHeaderNode::push_back)))
|
||||
->setCollector("Require-header", belr::make_sfn(static_cast<pushPtr>(&ListHeaderNode::push_back)));
|
||||
|
||||
parser.setHandler(
|
||||
"Header", belr::make_fn(make_shared<HeaderNode> )
|
||||
)->setCollector(
|
||||
"Header-name", belr::make_sfn(&HeaderNode::setName)
|
||||
)->setCollector(
|
||||
"Header-value", belr::make_sfn(&HeaderNode::setValue)
|
||||
)->setCollector(
|
||||
"Header-parameters", belr::make_sfn(&HeaderNode::setParameters)
|
||||
);
|
||||
parser.setHandler("Content-headers", belr::make_fn(make_shared<ListHeaderNode>))
|
||||
->setCollector("Header", belr::make_sfn(static_cast<pushPtr>(&ListHeaderNode::push_back)));
|
||||
|
||||
parser.setHandler("Header", belr::make_fn(make_shared<HeaderNode>))
|
||||
->setCollector("Header-name", belr::make_sfn(&HeaderNode::setName))
|
||||
->setCollector("Header-value", belr::make_sfn(&HeaderNode::setValue))
|
||||
->setCollector("Header-parameters", belr::make_sfn(&HeaderNode::setParameters));
|
||||
|
||||
parser.setHandler("From-header", belr::make_fn(make_shared<FromHeaderNode>))
|
||||
->setCollector("Formal-name", belr::make_sfn(&FromHeaderNode::setFormalName))
|
||||
->setCollector("URI", belr::make_sfn(&FromHeaderNode::setUri));
|
||||
|
||||
parser.setHandler("To-header", belr::make_fn(make_shared<ToHeaderNode>))
|
||||
->setCollector("Formal-name", belr::make_sfn(&ToHeaderNode::setFormalName))
|
||||
->setCollector("URI", belr::make_sfn(&ToHeaderNode::setUri));
|
||||
|
||||
parser.setHandler("cc-header", belr::make_fn(make_shared<CcHeaderNode>))
|
||||
->setCollector("Formal-name", belr::make_sfn(&CcHeaderNode::setFormalName))
|
||||
->setCollector("URI", belr::make_sfn(&CcHeaderNode::setUri));
|
||||
|
||||
parser.setHandler("DateTime-header", belr::make_fn(make_shared<DateTimeHeaderNode>))
|
||||
->setCollector("date-fullyear", belr::make_sfn(&DateTimeHeaderNode::setYear))
|
||||
->setCollector("date-month", belr::make_sfn(&DateTimeHeaderNode::setMonth))
|
||||
->setCollector("date-mday", belr::make_sfn(&DateTimeHeaderNode::setMonthDay))
|
||||
->setCollector("time-hour", belr::make_sfn(&DateTimeHeaderNode::setHour))
|
||||
->setCollector("time-minute", belr::make_sfn(&DateTimeHeaderNode::setMinute))
|
||||
->setCollector("time-second", belr::make_sfn(&DateTimeHeaderNode::setSecond))
|
||||
->setCollector("time-offset", belr::make_sfn(&DateTimeHeaderNode::setOffset));
|
||||
|
||||
parser.setHandler("time-offset", belr::make_fn(make_shared<DateTimeOffsetNode>))
|
||||
->setCollector("time-sign", belr::make_sfn(&DateTimeOffsetNode::setSign))
|
||||
->setCollector("time-hour", belr::make_sfn(&DateTimeOffsetNode::setHour))
|
||||
->setCollector("time-minute", belr::make_sfn(&DateTimeOffsetNode::setMinute));
|
||||
|
||||
parser.setHandler("Subject-header", belr::make_fn(make_shared<SubjectHeaderNode>))
|
||||
->setCollector("Language-tag", belr::make_sfn(&SubjectHeaderNode::setLanguage))
|
||||
->setCollector("Header-value", belr::make_sfn(&SubjectHeaderNode::setSubject));
|
||||
|
||||
parser.setHandler("Ns-header", belr::make_fn(make_shared<NsHeaderNode>))
|
||||
->setCollector("Name-prefix", belr::make_sfn(&NsHeaderNode::setPrefixName))
|
||||
->setCollector("URI", belr::make_sfn(&NsHeaderNode::setUri));
|
||||
|
||||
parser.setHandler("Require-header", belr::make_fn(make_shared<RequireHeaderNode>))
|
||||
->setCollector("Require-header-value", belr::make_sfn(&RequireHeaderNode::setHeaderNames));
|
||||
|
||||
size_t parsedSize;
|
||||
shared_ptr<Node> node = parser.parseInput("Message", input, &parsedSize);
|
||||
|
|
@ -305,143 +689,28 @@ shared_ptr<Cpim::Message> Cpim::Parser::parseMessage (const string &input) {
|
|||
// -----------------------------------------------------------------------------
|
||||
|
||||
shared_ptr<Cpim::Header> Cpim::Parser::cloneHeader (const Header &header) {
|
||||
return HeaderNode(header).createHeader(true);
|
||||
}
|
||||
if (header.getName() == "From")
|
||||
return FromHeaderNode(header).createHeader();
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
if (header.getName() == "To")
|
||||
return ToHeaderNode(header).createHeader();
|
||||
|
||||
class EmptyObject {};
|
||||
if (header.getName() == "cc")
|
||||
return CcHeaderNode(header).createHeader();
|
||||
|
||||
static bool headerIsValid (const shared_ptr<belr::Grammar> &grammar, const string &input) {
|
||||
belr::Parser<shared_ptr<EmptyObject> > parser(grammar);
|
||||
parser.setHandler(
|
||||
"Header", belr::make_fn(make_shared<EmptyObject> )
|
||||
);
|
||||
if (header.getName() == "DateTime")
|
||||
return DateTimeHeaderNode(header).createHeader();
|
||||
|
||||
size_t parsedSize;
|
||||
shared_ptr<EmptyObject> node = parser.parseInput("Header", input, &parsedSize);
|
||||
return node && parsedSize == input.length();
|
||||
}
|
||||
if (header.getName() == "Subject")
|
||||
return SubjectHeaderNode(header).createHeader();
|
||||
|
||||
bool Cpim::Parser::headerNameIsValid (const string &headerName) const {
|
||||
L_D();
|
||||
return headerIsValid(d->grammar, headerName + ": value\r\n");
|
||||
}
|
||||
if (header.getName() == "NS")
|
||||
return NsHeaderNode(header).createHeader();
|
||||
|
||||
bool Cpim::Parser::headerValueIsValid (const string &headerValue) const {
|
||||
L_D();
|
||||
return headerIsValid(d->grammar, "key: " + headerValue + "\r\n");
|
||||
}
|
||||
if (header.getName() == "Require")
|
||||
return RequireHeaderNode(header).createHeader();
|
||||
|
||||
bool Cpim::Parser::headerParameterIsValid (const string &headerParameter) const {
|
||||
L_D();
|
||||
return headerIsValid(d->grammar, "key:;" + headerParameter + " value\r\n");
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
static bool coreHeaderIsValid (
|
||||
const shared_ptr<belr::Grammar> &grammar,
|
||||
const string &headerName,
|
||||
const string &headerValue,
|
||||
const string &headerParams = string()
|
||||
) {
|
||||
const string mainRule = headerName + "-header";
|
||||
|
||||
belr::Parser<shared_ptr<EmptyObject> > parser(grammar);
|
||||
parser.setHandler(
|
||||
mainRule, belr::make_fn(make_shared<EmptyObject> )
|
||||
);
|
||||
|
||||
const string input = headerName + ":" + headerParams + " " + headerValue;
|
||||
|
||||
size_t parsedSize;
|
||||
shared_ptr<EmptyObject> node = parser.parseInput(mainRule, input, &parsedSize);
|
||||
return node && parsedSize == input.length();
|
||||
}
|
||||
|
||||
template<>
|
||||
bool Cpim::Parser::coreHeaderIsValid<Cpim::FromHeader> (const string &headerValue) const {
|
||||
L_D();
|
||||
return LinphonePrivate::coreHeaderIsValid(d->grammar, "From", headerValue);
|
||||
}
|
||||
|
||||
template<>
|
||||
bool Cpim::Parser::coreHeaderIsValid<Cpim::ToHeader> (const string &headerValue) const {
|
||||
L_D();
|
||||
return LinphonePrivate::coreHeaderIsValid(d->grammar, "To", headerValue);
|
||||
}
|
||||
|
||||
template<>
|
||||
bool Cpim::Parser::coreHeaderIsValid<Cpim::CcHeader> (const string &headerValue) const {
|
||||
L_D();
|
||||
return LinphonePrivate::coreHeaderIsValid(d->grammar, "cc", headerValue);
|
||||
}
|
||||
|
||||
template<>
|
||||
bool Cpim::Parser::coreHeaderIsValid<Cpim::DateTimeHeader> (const string &headerValue) const {
|
||||
static const int daysInMonth[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
|
||||
|
||||
L_D();
|
||||
if (!LinphonePrivate::coreHeaderIsValid(d->grammar, "DateTime", headerValue))
|
||||
return false;
|
||||
|
||||
// Check date.
|
||||
const int year = Utils::stoi(headerValue.substr(0, 4));
|
||||
const bool isLeapYear = (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;
|
||||
|
||||
const int month = Utils::stoi(headerValue.substr(5, 2));
|
||||
if (month < 1 || month > 12)
|
||||
return false;
|
||||
|
||||
const int day = Utils::stoi(headerValue.substr(8, 2));
|
||||
if (day < 1 || (month == 2 && isLeapYear ? day > 29 : day > daysInMonth[month - 1]))
|
||||
return false;
|
||||
|
||||
// Check time.
|
||||
if (
|
||||
Utils::stoi(headerValue.substr(11, 2)) > 24 ||
|
||||
Utils::stoi(headerValue.substr(14, 2)) > 59 ||
|
||||
Utils::stoi(headerValue.substr(17, 2)) > 60
|
||||
)
|
||||
return false;
|
||||
|
||||
// Check num offset.
|
||||
if (headerValue.back() != 'Z') {
|
||||
size_t length = headerValue.length();
|
||||
if (
|
||||
Utils::stoi(headerValue.substr(length - 5, 2)) > 24 ||
|
||||
Utils::stoi(headerValue.substr(length - 2, 2)) > 59
|
||||
)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<>
|
||||
bool Cpim::Parser::coreHeaderIsValid<Cpim::SubjectHeader> (const string &headerValue) const {
|
||||
L_D();
|
||||
return LinphonePrivate::coreHeaderIsValid(d->grammar, "Subject", headerValue);
|
||||
}
|
||||
|
||||
template<>
|
||||
bool Cpim::Parser::coreHeaderIsValid<Cpim::NsHeader> (const string &headerValue) const {
|
||||
L_D();
|
||||
return LinphonePrivate::coreHeaderIsValid(d->grammar, "NS", headerValue);
|
||||
}
|
||||
|
||||
template<>
|
||||
bool Cpim::Parser::coreHeaderIsValid<Cpim::RequireHeader> (const string &headerValue) const {
|
||||
L_D();
|
||||
return LinphonePrivate::coreHeaderIsValid(d->grammar, "Require", headerValue);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
bool Cpim::Parser::subjectHeaderLanguageIsValid (const string &language) const {
|
||||
L_D();
|
||||
return LinphonePrivate::coreHeaderIsValid(d->grammar, "Subject", "SubjectValue", ";lang=" + language);
|
||||
return HeaderNode(header).createHeader();
|
||||
}
|
||||
|
||||
LINPHONE_END_NAMESPACE
|
||||
|
|
|
|||
|
|
@ -38,46 +38,12 @@ namespace Cpim {
|
|||
|
||||
std::shared_ptr<Header> cloneHeader (const Header &header);
|
||||
|
||||
bool headerNameIsValid (const std::string &headerName) const;
|
||||
bool headerValueIsValid (const std::string &headerValue) const;
|
||||
bool headerParameterIsValid (const std::string &headerParameter) const;
|
||||
|
||||
template<typename>
|
||||
bool coreHeaderIsValid (const std::string &headerValue) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool subjectHeaderLanguageIsValid (const std::string &language) const;
|
||||
|
||||
private:
|
||||
Parser ();
|
||||
|
||||
L_DECLARE_PRIVATE(Parser);
|
||||
L_DISABLE_COPY(Parser);
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
template<>
|
||||
bool Parser::coreHeaderIsValid<FromHeader>(const std::string &headerValue) const;
|
||||
|
||||
template<>
|
||||
bool Parser::coreHeaderIsValid<ToHeader>(const std::string &headerValue) const;
|
||||
|
||||
template<>
|
||||
bool Parser::coreHeaderIsValid<CcHeader>(const std::string &headerValue) const;
|
||||
|
||||
template<>
|
||||
bool Parser::coreHeaderIsValid<DateTimeHeader>(const std::string &headerValue) const;
|
||||
|
||||
template<>
|
||||
bool Parser::coreHeaderIsValid<SubjectHeader>(const std::string &headerValue) const;
|
||||
|
||||
template<>
|
||||
bool Parser::coreHeaderIsValid<NsHeader>(const std::string &headerValue) const;
|
||||
|
||||
template<>
|
||||
bool Parser::coreHeaderIsValid<RequireHeader>(const std::string &headerValue) const;
|
||||
}
|
||||
|
||||
LINPHONE_END_NAMESPACE
|
||||
|
|
|
|||
|
|
@ -1,7 +1,11 @@
|
|||
Message = Headers CRLF Headers CRLF [Headers CRLF]
|
||||
Message = Message-headers CRLF Content-headers CRLF
|
||||
|
||||
Headers = *Header
|
||||
Header = Header-name ":" Header-parameters SP Header-value CRLF
|
||||
Message-headers = 1*( Message-header CRLF )
|
||||
Message-header = From-header / To-header / DateTime-header / cc-header / Subject-header / NS-header / Require-header / Header
|
||||
|
||||
Content-headers = 1*( Header CRLF )
|
||||
|
||||
Header = Header-name ":" Header-parameters SP Header-value
|
||||
|
||||
Header-name = [ Name-prefix "." ] Name
|
||||
Name-prefix = Name
|
||||
|
|
@ -29,7 +33,7 @@ cc-header = %d99.99 ": " cc-header-value
|
|||
cc-header-value = [ Formal-name ] "<" URI ">"
|
||||
|
||||
Subject-header = %d83.117.98.106.101.99.116 ":" Subject-header-value
|
||||
Subject-header-value = [ ";" Lang-param ] SP *HEADERCHAR
|
||||
Subject-header-value = [ ";" Lang-param ] SP Header-value
|
||||
|
||||
NS-header = %d78.83 ": " NS-header-value
|
||||
NS-header-value = [ Name-prefix SP ] "<" URI ">"
|
||||
|
|
@ -134,7 +138,8 @@ time-minute = 2DIGIT
|
|||
time-second = 2DIGIT
|
||||
|
||||
time-secfrac = "." 1*DIGIT
|
||||
time-numoffset = ( "+" / "-" ) time-hour ":" time-minute
|
||||
time-sign = "+" / "-"
|
||||
time-numoffset = time-sign time-hour ":" time-minute
|
||||
time-offset = "Z" / time-numoffset
|
||||
|
||||
partial-time = time-hour ":" time-minute ":" time-second [ time-secfrac ]
|
||||
|
|
|
|||
|
|
@ -38,32 +38,30 @@ LINPHONE_BEGIN_NAMESPACE
|
|||
ChatMessageModifier::Result CpimChatMessageModifier::encode (const shared_ptr<ChatMessage> &message, int &errorCode) {
|
||||
Cpim::Message cpimMessage;
|
||||
|
||||
Cpim::FromHeader cpimFromHeader;
|
||||
cpimFromHeader.setValue(cpimAddressAsString(message->getFromAddress()));
|
||||
cpimMessage.addMessageHeader(cpimFromHeader);
|
||||
Cpim::ToHeader cpimToHeader;
|
||||
cpimToHeader.setValue(cpimAddressAsString(message->getToAddress()));
|
||||
cpimMessage.addMessageHeader(cpimToHeader);
|
||||
cpimMessage.addMessageHeader(
|
||||
Cpim::FromHeader(cpimAddressUri(message->getFromAddress()), cpimAddressDisplayName(message->getFromAddress()))
|
||||
);
|
||||
cpimMessage.addMessageHeader(
|
||||
Cpim::ToHeader(cpimAddressUri(message->getToAddress()), cpimAddressDisplayName(message->getToAddress()))
|
||||
);
|
||||
cpimMessage.addMessageHeader(
|
||||
Cpim::DateTimeHeader(message->getTime())
|
||||
);
|
||||
|
||||
if (message->getPrivate()->getPositiveDeliveryNotificationRequired()
|
||||
|| message->getPrivate()->getNegativeDeliveryNotificationRequired()
|
||||
|| message->getPrivate()->getDisplayNotificationRequired()
|
||||
) {
|
||||
const string imdnNamespace = "imdn";
|
||||
Cpim::NsHeader cpimNsHeader;
|
||||
cpimNsHeader.setValue(imdnNamespace + " <urn:ietf:params:imdn>");
|
||||
cpimMessage.addMessageHeader(cpimNsHeader);
|
||||
cpimMessage.addMessageHeader(Cpim::NsHeader("urn:ietf:params:imdn", imdnNamespace));
|
||||
|
||||
char token[13];
|
||||
belle_sip_random_token(token, sizeof(token));
|
||||
Cpim::GenericHeader cpimMessageIdHeader;
|
||||
cpimMessageIdHeader.setName("Message-ID"); // TODO: Replace by imdnNamespace + ".Message-ID");
|
||||
cpimMessageIdHeader.setValue(token);
|
||||
cpimMessage.addMessageHeader(cpimMessageIdHeader);
|
||||
cpimMessage.addMessageHeader(
|
||||
Cpim::GenericHeader("Message-ID", token) // TODO: Replace by imdnNamespace + ".Message-ID");
|
||||
);
|
||||
message->getPrivate()->setImdnMessageId(token);
|
||||
|
||||
Cpim::GenericHeader dispositionNotificationHeader;
|
||||
dispositionNotificationHeader.setName(imdnNamespace + ".Disposition-Notification");
|
||||
vector<string> dispositionNotificationValues;
|
||||
if (message->getPrivate()->getPositiveDeliveryNotificationRequired())
|
||||
dispositionNotificationValues.emplace_back("positive-delivery");
|
||||
|
|
@ -71,8 +69,12 @@ ChatMessageModifier::Result CpimChatMessageModifier::encode (const shared_ptr<Ch
|
|||
dispositionNotificationValues.emplace_back("negative-delivery");
|
||||
if (message->getPrivate()->getDisplayNotificationRequired())
|
||||
dispositionNotificationValues.emplace_back("display");
|
||||
dispositionNotificationHeader.setValue(Utils::join(dispositionNotificationValues, ", "));
|
||||
cpimMessage.addMessageHeader(dispositionNotificationHeader);
|
||||
cpimMessage.addMessageHeader(
|
||||
Cpim::GenericHeader(
|
||||
imdnNamespace + ".Disposition-Notification",
|
||||
Utils::join(dispositionNotificationValues, ", ")
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
const Content *content;
|
||||
|
|
@ -88,19 +90,16 @@ ChatMessageModifier::Result CpimChatMessageModifier::encode (const shared_ptr<Ch
|
|||
|
||||
const string contentBody = content->getBodyAsString();
|
||||
if (content->getContentDisposition().isValid()) {
|
||||
Cpim::GenericHeader contentDispositionHeader;
|
||||
contentDispositionHeader.setName("Content-Disposition");
|
||||
contentDispositionHeader.setValue(content->getContentDisposition().asString());
|
||||
cpimMessage.addContentHeader(contentDispositionHeader);
|
||||
cpimMessage.addContentHeader(
|
||||
Cpim::GenericHeader("Content-Disposition", content->getContentDisposition().asString())
|
||||
);
|
||||
}
|
||||
Cpim::GenericHeader contentTypeHeader;
|
||||
contentTypeHeader.setName("Content-Type");
|
||||
contentTypeHeader.setValue(content->getContentType().asString());
|
||||
cpimMessage.addContentHeader(contentTypeHeader);
|
||||
Cpim::GenericHeader contentLengthHeader;
|
||||
contentLengthHeader.setName("Content-Length");
|
||||
contentLengthHeader.setValue(to_string(contentBody.size()));
|
||||
cpimMessage.addContentHeader(contentLengthHeader);
|
||||
cpimMessage.addContentHeader(
|
||||
Cpim::GenericHeader("Content-Type", content->getContentType().asString())
|
||||
);
|
||||
cpimMessage.addContentHeader(
|
||||
Cpim::GenericHeader("Content-Length", to_string(contentBody.size()))
|
||||
);
|
||||
cpimMessage.setContent(contentBody);
|
||||
|
||||
Content newContent;
|
||||
|
|
@ -125,76 +124,70 @@ ChatMessageModifier::Result CpimChatMessageModifier::decode (const shared_ptr<Ch
|
|||
|
||||
const string contentBody = content->getBodyAsString();
|
||||
const shared_ptr<const Cpim::Message> cpimMessage = Cpim::Message::createFromString(contentBody);
|
||||
if (!cpimMessage) {
|
||||
if (!cpimMessage || !cpimMessage->getMessageHeader("From") || !cpimMessage->getMessageHeader("To")) {
|
||||
lError() << "[CPIM] Message is invalid: " << contentBody;
|
||||
errorCode = 500;
|
||||
return ChatMessageModifier::Result::Error;
|
||||
}
|
||||
|
||||
Content newContent;
|
||||
bool contentTypeFound = false;
|
||||
Cpim::Message::HeaderList l = cpimMessage->getContentHeaders();
|
||||
if (l) {
|
||||
for (const auto &header : *l.get()) {
|
||||
if (header->getName() == "Content-Disposition") {
|
||||
newContent.setContentDisposition(ContentDisposition(header->getValue()));
|
||||
} else if (header->getName() == "Content-Type") {
|
||||
contentTypeFound = true;
|
||||
newContent.setContentType(ContentType(header->getValue()));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!contentTypeFound) {
|
||||
auto contentTypeHeader = cpimMessage->getContentHeader("Content-Type");
|
||||
if (!contentTypeHeader) {
|
||||
lError() << "[CPIM] No Content-type for the content of the message";
|
||||
errorCode = 500;
|
||||
return ChatMessageModifier::Result::Error;
|
||||
}
|
||||
newContent.setContentType(ContentType(contentTypeHeader->getValue()));
|
||||
auto contentDispositionHeader = cpimMessage->getContentHeader("Content-Disposition");
|
||||
if (contentDispositionHeader)
|
||||
newContent.setContentDisposition(ContentDisposition(contentDispositionHeader->getValue()));
|
||||
newContent.setBody(cpimMessage->getContent());
|
||||
|
||||
message->getPrivate()->setPositiveDeliveryNotificationRequired(false);
|
||||
message->getPrivate()->setNegativeDeliveryNotificationRequired(false);
|
||||
message->getPrivate()->setDisplayNotificationRequired(false);
|
||||
|
||||
Address cpimFromAddress;
|
||||
Address cpimToAddress;
|
||||
l = cpimMessage->getMessageHeaders();
|
||||
if (l) {
|
||||
string imdnNamespace = "";
|
||||
for (const auto &header : *l.get()) {
|
||||
if (header->getName() == "NS") {
|
||||
string val = header->getValue();
|
||||
size_t startPos = 0;
|
||||
startPos = val.find("<", startPos);
|
||||
if (startPos == string::npos)
|
||||
break;
|
||||
size_t endPos = 0;
|
||||
endPos = val.find(">", startPos);
|
||||
if (endPos == string::npos)
|
||||
break;
|
||||
if (val.substr(startPos, endPos) == "<urn:ietf:params:imdn>")
|
||||
imdnNamespace = Utils::trim(val.substr(0, startPos));
|
||||
}
|
||||
}
|
||||
for (const auto &header : *l.get()) {
|
||||
if (header->getName() == "From")
|
||||
cpimFromAddress = Address(header->getValue());
|
||||
else if (header->getName() == "To")
|
||||
cpimToAddress = Address(header->getValue());
|
||||
else if ((header->getName() == "Message-ID") || (header->getName() == (imdnNamespace + ".Message-ID")))
|
||||
message->getPrivate()->setImdnMessageId(header->getValue());
|
||||
else if ((header->getName() == (imdnNamespace + ".Disposition-Notification"))) {
|
||||
vector<string> values = Utils::split(header->getValue(), ", ");
|
||||
for (const auto &value : values)
|
||||
if (value == "positive-delivery")
|
||||
message->getPrivate()->setPositiveDeliveryNotificationRequired(true);
|
||||
else if (value == "negative-delivery")
|
||||
message->getPrivate()->setNegativeDeliveryNotificationRequired(true);
|
||||
else if (value == "display")
|
||||
message->getPrivate()->setDisplayNotificationRequired(true);
|
||||
string imdnNamespace = "";
|
||||
auto messageHeaders = cpimMessage->getMessageHeaders();
|
||||
if (messageHeaders) {
|
||||
for (const auto &header : *messageHeaders.get()) {
|
||||
if (header->getName() != "NS")
|
||||
continue;
|
||||
auto nsHeader = static_pointer_cast<const Cpim::NsHeader>(header);
|
||||
if (nsHeader->getUri() == "urn:ietf:params:imdn") {
|
||||
imdnNamespace = nsHeader->getPrefixName();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto fromHeader = static_pointer_cast<const Cpim::FromHeader>(cpimMessage->getMessageHeader("From"));
|
||||
Address cpimFromAddress(fromHeader->getValue());
|
||||
auto toHeader = static_pointer_cast<const Cpim::ToHeader>(cpimMessage->getMessageHeader("To"));
|
||||
Address cpimToAddress(toHeader->getValue());
|
||||
auto dateTimeHeader = static_pointer_cast<const Cpim::DateTimeHeader>(cpimMessage->getMessageHeader("DateTime"));
|
||||
if (dateTimeHeader)
|
||||
message->getPrivate()->setTime(dateTimeHeader->getTime());
|
||||
|
||||
auto messageIdHeader = cpimMessage->getMessageHeader("Message-ID"); // TODO: For compatibility, to remove
|
||||
if (!imdnNamespace.empty()) {
|
||||
if (!messageIdHeader)
|
||||
messageIdHeader = cpimMessage->getMessageHeader("Message-ID", imdnNamespace);
|
||||
auto dispositionNotificationHeader = cpimMessage->getMessageHeader("Disposition-Notification", imdnNamespace);
|
||||
if (dispositionNotificationHeader) {
|
||||
vector<string> values = Utils::split(dispositionNotificationHeader->getValue(), ", ");
|
||||
for (const auto &value : values)
|
||||
if (value == "positive-delivery")
|
||||
message->getPrivate()->setPositiveDeliveryNotificationRequired(true);
|
||||
else if (value == "negative-delivery")
|
||||
message->getPrivate()->setNegativeDeliveryNotificationRequired(true);
|
||||
else if (value == "display")
|
||||
message->getPrivate()->setDisplayNotificationRequired(true);
|
||||
}
|
||||
}
|
||||
if (messageIdHeader)
|
||||
message->getPrivate()->setImdnMessageId(messageIdHeader->getValue());
|
||||
|
||||
// Modify the initial message since there was no error
|
||||
message->setInternalContent(newContent);
|
||||
if (cpimFromAddress.isValid())
|
||||
|
|
@ -203,12 +196,12 @@ ChatMessageModifier::Result CpimChatMessageModifier::decode (const shared_ptr<Ch
|
|||
return ChatMessageModifier::Result::Done;
|
||||
}
|
||||
|
||||
string CpimChatMessageModifier::cpimAddressAsString (const Address &addr) const {
|
||||
ostringstream os;
|
||||
if (!addr.getDisplayName().empty())
|
||||
os << addr.getDisplayName() << " ";
|
||||
os << "<" << addr.asStringUriOnly() << ">";
|
||||
return os.str();
|
||||
string CpimChatMessageModifier::cpimAddressDisplayName (const Address &addr) const {
|
||||
return addr.getDisplayName();
|
||||
}
|
||||
|
||||
string CpimChatMessageModifier::cpimAddressUri (const Address &addr) const {
|
||||
return addr.asStringUriOnly();
|
||||
}
|
||||
|
||||
LINPHONE_END_NAMESPACE
|
||||
|
|
|
|||
|
|
@ -34,7 +34,8 @@ public:
|
|||
Result decode (const std::shared_ptr<ChatMessage> &message, int &errorCode) override;
|
||||
|
||||
private:
|
||||
std::string cpimAddressAsString (const Address &addr) const;
|
||||
std::string cpimAddressDisplayName (const Address &addr) const;
|
||||
std::string cpimAddressUri (const Address &addr) const;
|
||||
};
|
||||
|
||||
LINPHONE_END_NAMESPACE
|
||||
|
|
|
|||
|
|
@ -44,6 +44,8 @@ private:
|
|||
// Misc helpers.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
static time_t getTmAsTimeT (const tm &t);
|
||||
|
||||
std::shared_ptr<AbstractChatRoom> findChatRoom (const ChatRoomId &chatRoomId) const;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -226,6 +226,12 @@ static string buildSqlEventFilter (
|
|||
// Misc helpers.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
time_t MainDbPrivate::getTmAsTimeT (const tm &t) {
|
||||
tm t2 = t;
|
||||
t2.tm_isdst = 0;
|
||||
return Utils::getTmAsTimeT(t2);
|
||||
}
|
||||
|
||||
shared_ptr<AbstractChatRoom> MainDbPrivate::findChatRoom (const ChatRoomId &chatRoomId) const {
|
||||
L_Q();
|
||||
shared_ptr<AbstractChatRoom> chatRoom = q->getCore()->findChatRoom(chatRoomId);
|
||||
|
|
@ -610,7 +616,7 @@ shared_ptr<EventLog> MainDbPrivate::selectConferenceChatMessageEvent (
|
|||
dChatMessage->forceFromAddress(IdentityAddress(row.get<string>(3)));
|
||||
dChatMessage->forceToAddress(IdentityAddress(row.get<string>(4)));
|
||||
|
||||
dChatMessage->setTime(Utils::getTmAsTimeT(row.get<tm>(5)));
|
||||
dChatMessage->setTime(MainDbPrivate::getTmAsTimeT(row.get<tm>(5)));
|
||||
dChatMessage->setImdnMessageId(row.get<string>(6));
|
||||
dChatMessage->setPositiveDeliveryNotificationRequired(bool(row.get<int>(14)));
|
||||
dChatMessage->setDisplayNotificationRequired(bool(row.get<int>(15)));
|
||||
|
|
@ -1976,7 +1982,7 @@ list<MainDb::ParticipantState> MainDb::getChatMessageParticipantsThatHaveDisplay
|
|||
|
||||
list<MainDb::ParticipantState> result;
|
||||
for (const auto &row : rows)
|
||||
result.emplace_back(IdentityAddress(row.get<string>(0)), ChatMessage::State::Displayed, Utils::getTmAsTimeT(row.get<tm>(1)));
|
||||
result.emplace_back(IdentityAddress(row.get<string>(0)), ChatMessage::State::Displayed, MainDbPrivate::getTmAsTimeT(row.get<tm>(1)));
|
||||
return result;
|
||||
};
|
||||
}
|
||||
|
|
@ -2029,7 +2035,7 @@ list<MainDb::ParticipantState> MainDb::getChatMessageParticipantsThatHaveReceive
|
|||
|
||||
list<MainDb::ParticipantState> result;
|
||||
for (const auto &row : rows)
|
||||
result.emplace_back(IdentityAddress(row.get<string>(0)), ChatMessage::State::DeliveredToUser, Utils::getTmAsTimeT(row.get<tm>(1)));
|
||||
result.emplace_back(IdentityAddress(row.get<string>(0)), ChatMessage::State::DeliveredToUser, MainDbPrivate::getTmAsTimeT(row.get<tm>(1)));
|
||||
return result;
|
||||
};
|
||||
}
|
||||
|
|
@ -2483,8 +2489,8 @@ list<shared_ptr<AbstractChatRoom>> MainDb::getChatRooms () const {
|
|||
continue; // Not fetched.
|
||||
|
||||
AbstractChatRoomPrivate *dChatRoom = chatRoom->getPrivate();
|
||||
dChatRoom->setCreationTime(Utils::getTmAsTimeT(creationTime));
|
||||
dChatRoom->setLastUpdateTime(Utils::getTmAsTimeT(lastUpdateTime));
|
||||
dChatRoom->setCreationTime(MainDbPrivate::getTmAsTimeT(creationTime));
|
||||
dChatRoom->setLastUpdateTime(MainDbPrivate::getTmAsTimeT(lastUpdateTime));
|
||||
|
||||
lInfo() << "Found chat room in DB: (peer=" <<
|
||||
chatRoomId.getPeerAddress().asString() << ", local=" << chatRoomId.getLocalAddress().asString() << ").";
|
||||
|
|
|
|||
|
|
@ -27,6 +27,10 @@
|
|||
|
||||
#include "linphone/utils/utils.h"
|
||||
|
||||
#include "logger/logger.h"
|
||||
|
||||
#include "private.h"
|
||||
|
||||
// =============================================================================
|
||||
|
||||
using namespace std;
|
||||
|
|
@ -184,12 +188,42 @@ string Utils::trim (const string &str) {
|
|||
// -----------------------------------------------------------------------------
|
||||
|
||||
tm Utils::getTimeTAsTm (time_t time) {
|
||||
tm result;
|
||||
return *gmtime_r(&time, &result);
|
||||
#ifdef _WIN32
|
||||
return *gmtime(&time);
|
||||
#else
|
||||
tm result;
|
||||
return *gmtime_r(&time, &result);
|
||||
#endif
|
||||
}
|
||||
|
||||
time_t Utils::getTmAsTimeT (const tm &time) {
|
||||
return timegm(&const_cast<tm &>(time));
|
||||
time_t result;
|
||||
|
||||
#if defined(LINPHONE_WINDOWS_UNIVERSAL) || defined(LINPHONE_MSC_VER_GREATER_19)
|
||||
long adjust_timezone;
|
||||
#else
|
||||
time_t adjust_timezone;
|
||||
#endif
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR
|
||||
result = timegm(&const_cast<tm &>(time));
|
||||
adjust_timezone = 0;
|
||||
#else
|
||||
result = mktime(&const_cast<tm &>(time));
|
||||
|
||||
#if defined(LINPHONE_WINDOWS_UNIVERSAL) || defined(LINPHONE_MSC_VER_GREATER_19)
|
||||
_get_timezone(&adjust_timezone);
|
||||
#else
|
||||
adjust_timezone = timezone;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (result == (time_t)-1) {
|
||||
lError() << "mktime failed: " << strerror(errno);
|
||||
return (time_t)-1;
|
||||
}
|
||||
|
||||
return result - (time_t)adjust_timezone;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ using namespace std;
|
|||
using namespace LinphonePrivate;
|
||||
|
||||
static void parse_minimal_message () {
|
||||
const string str = "Content-type: Message/CPIM\r\n"
|
||||
const string str = "Subject: the weather will be fine today\r\n"
|
||||
"\r\n"
|
||||
"Content-Type: text/plain; charset=utf-8\r\n"
|
||||
"\r\n";
|
||||
|
|
@ -54,13 +54,6 @@ static void parse_minimal_message () {
|
|||
|
||||
static void set_generic_header_name () {
|
||||
const list<pair<string, bool> > entries = {
|
||||
{ "toto", true },
|
||||
{ "george.abitbol", true },
|
||||
{ "tata/titi", false },
|
||||
{ "hey ho", false },
|
||||
{ " fail", false },
|
||||
{ "fail2 ", false },
|
||||
|
||||
// Reserved.
|
||||
{ "From", false },
|
||||
{ "To", false },
|
||||
|
|
@ -68,59 +61,19 @@ static void set_generic_header_name () {
|
|||
{ "DateTime", false },
|
||||
{ "Subject", false },
|
||||
{ "NS", false },
|
||||
{ "Require", false },
|
||||
|
||||
// Case sensitivity.
|
||||
{ "FROM", true },
|
||||
{ "to", true },
|
||||
{ "cC", true },
|
||||
{ "Datetime", true },
|
||||
{ "SuBject", true },
|
||||
{ "nS", true },
|
||||
{ "requirE", true }
|
||||
{ "Require", false }
|
||||
};
|
||||
|
||||
for (const auto &entry : entries) {
|
||||
Cpim::GenericHeader genericHeader;
|
||||
|
||||
const bool result = genericHeader.setName(entry.first);
|
||||
BC_ASSERT_EQUAL(result, entry.second, bool, "%d");
|
||||
Cpim::GenericHeader genericHeader(entry.first, "");
|
||||
|
||||
const string name = genericHeader.getName();
|
||||
|
||||
if (result)
|
||||
BC_ASSERT_STRING_EQUAL(name.c_str(), entry.first.c_str());
|
||||
else
|
||||
BC_ASSERT_STRING_EQUAL(name.c_str(), "");
|
||||
}
|
||||
}
|
||||
|
||||
static void set_generic_header_value () {
|
||||
const list<pair<string, bool> > entries = {
|
||||
{ "MyFeatures <mid:MessageFeatures@id.foo.com>", true },
|
||||
{ "2000-12-13T13:40:00-08:00", true },
|
||||
{ "2000-12-13T13:40:00-08:00", true },
|
||||
{ "text/xml; charset=utf-8", true },
|
||||
{ "text/xml; charset=ut\r\nf-8", false }
|
||||
};
|
||||
|
||||
for (const auto &entry : entries) {
|
||||
Cpim::GenericHeader genericHeader;
|
||||
|
||||
const bool result = genericHeader.setValue(entry.first);
|
||||
BC_ASSERT_EQUAL(result, entry.second, bool, "%d");
|
||||
|
||||
const string value = genericHeader.getValue();
|
||||
|
||||
if (result)
|
||||
BC_ASSERT_STRING_EQUAL(value.c_str(), entry.first.c_str());
|
||||
else
|
||||
BC_ASSERT_STRING_EQUAL(value.c_str(), "");
|
||||
BC_ASSERT_STRING_EQUAL(name.c_str(), "");
|
||||
}
|
||||
}
|
||||
|
||||
static void check_core_header_names () {
|
||||
const list<pair<shared_ptr<Cpim::CoreHeader>, string> > entries = {
|
||||
const list<pair<shared_ptr<Cpim::Header>, string> > entries = {
|
||||
{ make_shared<Cpim::FromHeader>(), "From" },
|
||||
{ make_shared<Cpim::ToHeader>(), "To" },
|
||||
{ make_shared<Cpim::CcHeader>(), "cc" },
|
||||
|
|
@ -136,118 +89,13 @@ static void check_core_header_names () {
|
|||
}
|
||||
}
|
||||
|
||||
static void set_core_header_values () {
|
||||
const list<pair<shared_ptr<Cpim::Header>, list<pair<string, bool> > > > entries = {
|
||||
{ make_shared<Cpim::FromHeader>(), {
|
||||
{ "Winnie the Pooh <im:pooh@100akerwood.com>", true },
|
||||
{ "<im:tigger@100akerwood.com>", true },
|
||||
{ "<im:tigger@100akerwood.com", false },
|
||||
{ "<im:tigger>", true },
|
||||
{ "toto", false }
|
||||
} },
|
||||
{ make_shared<Cpim::ToHeader>(), {
|
||||
{ "<im:tigger@100akerwood.com", false },
|
||||
{ "Winnie the Pooh <im:pooh@100akerwood.com>", true },
|
||||
{ "toto", false },
|
||||
{ "<im:tigger>", true },
|
||||
{ "<im:tigger@100akerwood.com>", true }
|
||||
} },
|
||||
{ make_shared<Cpim::CcHeader>(), {
|
||||
{ "<im:tigger@100akerwood.com>", true },
|
||||
{ "<im:tigger@100akerwood.com", false },
|
||||
{ "Winnie the Pooh <im:pooh@100akerwood.com>", true },
|
||||
{ "<im:tigger>", true },
|
||||
{ "toto", false }
|
||||
} },
|
||||
{ make_shared<Cpim::DateTimeHeader>(), {
|
||||
{ "abcd", false },
|
||||
{ "1985-04-12T23:20:50.52Z", true },
|
||||
{ "1996-12-19T16:39:57-08:00", true },
|
||||
{ "1990-12-31T23:59:60Z", true },
|
||||
{ "1990-12-31T15:59:60-08:00", true },
|
||||
{ "2001-02-29T10:10:10Z", false },
|
||||
{ "2000-02-29T10:10:10Z", true },
|
||||
{ "1937-01-01T12:00:27.87+00:20", true },
|
||||
{ "1937-01-01T12:00:27.87Z", true },
|
||||
{ "1956", false }
|
||||
} },
|
||||
{ make_shared<Cpim::SubjectHeader>(), {
|
||||
{ "Eeyore's feeling very depressed today", true },
|
||||
{ "🤣", true },
|
||||
{ "hello", true }
|
||||
} },
|
||||
{ make_shared<Cpim::NsHeader>(), {
|
||||
{ "MyAlias <mid:MessageFeatures@id.foo.com>", true },
|
||||
{ "What is this? - Barry Burton", false },
|
||||
{ "<mid:MessageFeatures@id.foo.com>", true },
|
||||
{ "<mid:MessageFeatures@id.foo.com", false }
|
||||
} },
|
||||
{ make_shared<Cpim::RequireHeader>(), {
|
||||
{ "MyAlias.VitalHeader", true },
|
||||
{ "MyAlias.VitalHeader,Test", true },
|
||||
{ "MyAlias.VitalHeader,🤣", false }
|
||||
} }
|
||||
};
|
||||
|
||||
for (const auto &entry : entries) {
|
||||
const shared_ptr<Cpim::Header> header = entry.first;
|
||||
string previousValue;
|
||||
|
||||
for (const auto &test : entry.second) {
|
||||
const bool result = header->setValue(test.first);
|
||||
BC_ASSERT_EQUAL(result, test.second, bool, "%d");
|
||||
|
||||
const string value = header->getValue();
|
||||
|
||||
if (result)
|
||||
BC_ASSERT_STRING_EQUAL(value.c_str(), test.first.c_str());
|
||||
else
|
||||
BC_ASSERT_STRING_EQUAL(value.c_str(), previousValue.c_str());
|
||||
|
||||
previousValue = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void check_subject_header_language () {
|
||||
Cpim::SubjectHeader subjectHeader;
|
||||
|
||||
// Check for not defined language.
|
||||
{
|
||||
const string language = subjectHeader.getLanguage();
|
||||
BC_ASSERT_STRING_EQUAL(language.c_str(), "");
|
||||
}
|
||||
|
||||
// Set valid language.
|
||||
{
|
||||
const string languageToSet = "fr";
|
||||
|
||||
BC_ASSERT_TRUE(subjectHeader.setLanguage(languageToSet));
|
||||
BC_ASSERT_TRUE(languageToSet == subjectHeader.getLanguage());
|
||||
|
||||
const string str = subjectHeader.asString();
|
||||
const string expected = "Subject:;lang=" + languageToSet + " \r\n";
|
||||
BC_ASSERT_STRING_EQUAL(str.c_str(), expected.c_str());
|
||||
}
|
||||
|
||||
// Set invalid language.
|
||||
{
|
||||
const string languageToSet = "fr--";
|
||||
BC_ASSERT_FALSE(subjectHeader.setLanguage(languageToSet));
|
||||
BC_ASSERT_FALSE(languageToSet == subjectHeader.getLanguage());
|
||||
BC_ASSERT_FALSE(subjectHeader.isValid());
|
||||
}
|
||||
}
|
||||
|
||||
static void parse_rfc_example () {
|
||||
const string body = "<body>"
|
||||
"Here is the text of my message."
|
||||
"</body>";
|
||||
|
||||
const string str = "Content-type: Message/CPIM\r\n"
|
||||
"\r\n"
|
||||
"From: MR SANDERS <im:piglet@100akerwood.com>\r\n"
|
||||
"To: Depressed Donkey <im:eeyore@100akerwood.com>\r\n"
|
||||
const string str = "From: \"MR SANDERS\"<im:piglet@100akerwood.com>\r\n"
|
||||
"To: \"Depressed Donkey\"<im:eeyore@100akerwood.com>\r\n"
|
||||
"DateTime: 2000-12-13T13:40:00-08:00\r\n"
|
||||
"Subject: the weather will be fine today\r\n"
|
||||
"Subject:;lang=fr beau temps prevu pour aujourd'hui\r\n"
|
||||
|
|
@ -268,6 +116,14 @@ static void parse_rfc_example () {
|
|||
|
||||
string content = message->getContent();
|
||||
BC_ASSERT_STRING_EQUAL(content.c_str(), body.c_str());
|
||||
|
||||
Cpim::Message::HeaderList list = message->getMessageHeaders();
|
||||
if (!BC_ASSERT_PTR_NOT_NULL(list)) return;
|
||||
BC_ASSERT_EQUAL(list->size(), 7, int, "%d");
|
||||
|
||||
list = message->getMessageHeaders("MyFeatures");
|
||||
if (!BC_ASSERT_PTR_NOT_NULL(list)) return;
|
||||
BC_ASSERT_EQUAL(list->size(), 2, int, "%d");
|
||||
}
|
||||
|
||||
static void parse_message_with_generic_header_parameters () {
|
||||
|
|
@ -275,9 +131,7 @@ static void parse_message_with_generic_header_parameters () {
|
|||
"Here is the text of my message."
|
||||
"</body>";
|
||||
|
||||
const string str = "Content-type: Message/CPIM\r\n"
|
||||
"\r\n"
|
||||
"From: MR SANDERS <im:piglet@100akerwood.com>\r\n"
|
||||
const string str = "From: \"MR SANDERS\"<im:piglet@100akerwood.com>\r\n"
|
||||
"Test:;aaa=bbb;yes=no CheckMe\r\n"
|
||||
"yaya: coucou\r\n"
|
||||
"yepee:;good=bad ugly\r\n"
|
||||
|
|
@ -298,81 +152,55 @@ static void parse_message_with_generic_header_parameters () {
|
|||
|
||||
static void build_message () {
|
||||
Cpim::Message message;
|
||||
if (!BC_ASSERT_FALSE(message.isValid()))
|
||||
return;
|
||||
|
||||
// Set CPIM headers.
|
||||
Cpim::GenericHeader cpimContentTypeHeader;
|
||||
if (!BC_ASSERT_TRUE(cpimContentTypeHeader.setName("Content-Type"))) return;
|
||||
if (!BC_ASSERT_TRUE(cpimContentTypeHeader.setValue("Message/CPIM"))) return;
|
||||
|
||||
if (!BC_ASSERT_TRUE(message.addCpimHeader(cpimContentTypeHeader))) return;
|
||||
|
||||
// Set message headers.
|
||||
Cpim::FromHeader fromHeader;
|
||||
if (!BC_ASSERT_TRUE(fromHeader.setValue("MR SANDERS <im:piglet@100akerwood.com>"))) return;
|
||||
Cpim::FromHeader fromHeader("im:piglet@100akerwood.com", "MR SANDERS");
|
||||
|
||||
Cpim::ToHeader toHeader;
|
||||
if (!BC_ASSERT_TRUE(toHeader.setValue("Depressed Donkey <im:eeyore@100akerwood.com>"))) return;
|
||||
Cpim::ToHeader toHeader("im:eeyore@100akerwood.com", "Depressed Donkey");
|
||||
|
||||
Cpim::DateTimeHeader dateTimeHeader;
|
||||
if (!BC_ASSERT_TRUE(dateTimeHeader.setValue("2000-12-13T13:40:00-08:00"))) return;
|
||||
// 976686000 is 2000-12-13T13:40:00-08:00
|
||||
Cpim::DateTimeHeader dateTimeHeader(976686000);
|
||||
BC_ASSERT_EQUAL(dateTimeHeader.getTime(), 976686000, int, "%d");
|
||||
|
||||
Cpim::SubjectHeader subjectHeader;
|
||||
if (!BC_ASSERT_TRUE(subjectHeader.setValue("the weather will be fine today"))) return;
|
||||
Cpim::SubjectHeader subjectHeader("the weather will be fine today");
|
||||
|
||||
Cpim::SubjectHeader subjectWithLanguageHeader;
|
||||
if (!BC_ASSERT_TRUE(subjectWithLanguageHeader.setValue("beau temps prevu pour aujourd'hui"))) return;
|
||||
if (!BC_ASSERT_TRUE(subjectWithLanguageHeader.setLanguage("fr"))) return;
|
||||
Cpim::SubjectHeader subjectWithLanguageHeader("beau temps prevu pour aujourd'hui", "fr");
|
||||
|
||||
Cpim::NsHeader nsHeader;
|
||||
if (!BC_ASSERT_TRUE(nsHeader.setValue("MyFeatures <mid:MessageFeatures@id.foo.com>"))) return;
|
||||
Cpim::NsHeader nsHeader("mid:MessageFeatures@id.foo.com", "MyFeatures");
|
||||
|
||||
Cpim::RequireHeader requireHeader;
|
||||
if (!BC_ASSERT_TRUE(requireHeader.setValue("MyFeatures.VitalMessageOption"))) return;
|
||||
Cpim::RequireHeader requireHeader("MyFeatures.VitalMessageOption");
|
||||
|
||||
Cpim::GenericHeader vitalMessageHeader;
|
||||
if (!BC_ASSERT_TRUE(vitalMessageHeader.setName("MyFeatures.VitalMessageOption"))) return;
|
||||
if (!BC_ASSERT_TRUE(vitalMessageHeader.setValue("Confirmation-requested"))) return;
|
||||
Cpim::GenericHeader vitalMessageHeader("MyFeatures.VitalMessageOption", "Confirmation-requested");
|
||||
|
||||
Cpim::GenericHeader wackyMessageHeader;
|
||||
if (!BC_ASSERT_TRUE(wackyMessageHeader.setName("MyFeatures.WackyMessageOption"))) return;
|
||||
if (!BC_ASSERT_TRUE(wackyMessageHeader.setValue("Use-silly-font"))) return;
|
||||
Cpim::GenericHeader wackyMessageHeader("MyFeatures.WackyMessageOption", "Use-silly-font");
|
||||
|
||||
if (!BC_ASSERT_TRUE(message.addMessageHeader(fromHeader))) return;
|
||||
if (!BC_ASSERT_TRUE(message.addMessageHeader(toHeader))) return;
|
||||
if (!BC_ASSERT_TRUE(message.addMessageHeader(dateTimeHeader))) return;
|
||||
if (!BC_ASSERT_TRUE(message.addMessageHeader(subjectHeader))) return;
|
||||
if (!BC_ASSERT_TRUE(message.addMessageHeader(subjectWithLanguageHeader))) return;
|
||||
if (!BC_ASSERT_TRUE(message.addMessageHeader(nsHeader))) return;
|
||||
if (!BC_ASSERT_TRUE(message.addMessageHeader(requireHeader))) return;
|
||||
if (!BC_ASSERT_TRUE(message.addMessageHeader(vitalMessageHeader))) return;
|
||||
if (!BC_ASSERT_TRUE(message.addMessageHeader(wackyMessageHeader))) return;
|
||||
message.addMessageHeader(fromHeader);
|
||||
message.addMessageHeader(toHeader);
|
||||
message.addMessageHeader(dateTimeHeader);
|
||||
message.addMessageHeader(subjectHeader);
|
||||
message.addMessageHeader(subjectWithLanguageHeader);
|
||||
message.addMessageHeader(nsHeader);
|
||||
message.addMessageHeader(requireHeader);
|
||||
message.addMessageHeader(vitalMessageHeader);
|
||||
message.addMessageHeader(wackyMessageHeader);
|
||||
|
||||
// Set Content headers.
|
||||
Cpim::GenericHeader contentTypeHeader;
|
||||
if (!BC_ASSERT_TRUE(contentTypeHeader.setName("Content-Type"))) return;
|
||||
if (!BC_ASSERT_TRUE( contentTypeHeader.setValue("text/xml; charset=utf-8"))) return;
|
||||
if (!BC_ASSERT_TRUE(message.addContentHeader(contentTypeHeader))) return;
|
||||
Cpim::GenericHeader contentTypeHeader("Content-Type", "text/xml; charset=utf-8");
|
||||
message.addContentHeader(contentTypeHeader);
|
||||
|
||||
Cpim::GenericHeader contentIdHeader;
|
||||
if (!BC_ASSERT_TRUE(contentIdHeader.setName("Content-ID"))) return;
|
||||
if (!BC_ASSERT_TRUE( contentIdHeader.setValue("<1234567890@foo.com>"))) return;
|
||||
if (!BC_ASSERT_TRUE(message.addContentHeader(contentIdHeader))) return;
|
||||
Cpim::GenericHeader contentIdHeader("Content-ID", "<1234567890@foo.com>");
|
||||
message.addContentHeader(contentIdHeader);
|
||||
|
||||
const string content = "<body>"
|
||||
"Here is the text of my message."
|
||||
"</body>";
|
||||
|
||||
if (!BC_ASSERT_TRUE(message.setContent(content))) return;
|
||||
if (!BC_ASSERT_TRUE(message.isValid())) return;
|
||||
|
||||
const string strMessage = message.asString();
|
||||
const string expectedMessage = "Content-Type: Message/CPIM\r\n"
|
||||
"\r\n"
|
||||
"From: MR SANDERS <im:piglet@100akerwood.com>\r\n"
|
||||
"To: Depressed Donkey <im:eeyore@100akerwood.com>\r\n"
|
||||
"DateTime: 2000-12-13T13:40:00-08:00\r\n"
|
||||
const string expectedMessage = "From: \"MR SANDERS\"<im:piglet@100akerwood.com>\r\n"
|
||||
"To: \"Depressed Donkey\"<im:eeyore@100akerwood.com>\r\n"
|
||||
"DateTime: 2000-12-13T05:40:00Z\r\n"
|
||||
"Subject: the weather will be fine today\r\n"
|
||||
"Subject:;lang=fr beau temps prevu pour aujourd'hui\r\n"
|
||||
"NS: MyFeatures <mid:MessageFeatures@id.foo.com>\r\n"
|
||||
|
|
@ -453,6 +281,9 @@ static void cpim_chat_message_modifier_base (bool useMultipart) {
|
|||
BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_content_type(pauline->stat.last_received_chat_message), expected.c_str());
|
||||
}
|
||||
|
||||
marieMessage.reset();
|
||||
marieRoom.reset();
|
||||
|
||||
linphone_im_encryption_engine_unref(marie_imee);
|
||||
linphone_im_encryption_engine_unref(pauline_imee);
|
||||
|
||||
|
|
@ -471,10 +302,7 @@ static void cpim_chat_message_modifier_with_multipart_body () {
|
|||
test_t cpim_tests[] = {
|
||||
TEST_NO_TAG("Parse minimal CPIM message", parse_minimal_message),
|
||||
TEST_NO_TAG("Set generic header name", set_generic_header_name),
|
||||
TEST_NO_TAG("Set generic header value", set_generic_header_value),
|
||||
TEST_NO_TAG("Check core header names", check_core_header_names),
|
||||
TEST_NO_TAG("Set core header values", set_core_header_values),
|
||||
TEST_NO_TAG("Check Subject header language", check_subject_header_language),
|
||||
TEST_NO_TAG("Parse RFC example", parse_rfc_example),
|
||||
TEST_NO_TAG("Parse Message with generic header parameters", parse_message_with_generic_header_parameters),
|
||||
TEST_NO_TAG("Build Message", build_message),
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue