Verified Commit ceec478c authored by Linus Jahn's avatar Linus Jahn 🔌 Committed by Linus Jahn
Browse files

Reimplement file stanza extension from XEP-0234: Jingle File Upload (#239)

The file stanza extension from Jingle File Upload is now also used for other
protocols as XEP-0385: Stateless Inline Media Sharing (SIMS). Unfortunately,
the original implementation was only usable in a full Jingle File Upload
request. Thus, this new implementation was required. It would be preferable that
this implementation is also used in the normal Jingle session, later.
parent ce69fb39
......@@ -38,7 +38,8 @@ SOURCES += \
src/gloox-extensions/reference.cpp \
src/gloox-extensions/processinghints.cpp \
src/gloox-extensions/thumb.cpp \
src/gloox-extensions/hash.cpp
src/gloox-extensions/hash.cpp \
src/gloox-extensions/jinglefile.cpp
HEADERS += \
src/Database.h \
......@@ -78,7 +79,8 @@ HEADERS += \
src/gloox-extensions/reference.h \
src/gloox-extensions/processinghints.h \
src/gloox-extensions/thumb.h \
src/gloox-extensions/hash.h
src/gloox-extensions/hash.h \
src/gloox-extensions/jinglefile.h
android: INCLUDEPATH += $$PWD/3rdparty/gloox/include
......
......@@ -42,4 +42,5 @@ set(KAIDAN_SOURCES
${CURDIR}/gloox-extensions/processinghints.cpp
${CURDIR}/gloox-extensions/hash.cpp
${CURDIR}/gloox-extensions/thumb.cpp
${CURDIR}/gloox-extensions/jinglefile.cpp
)
......@@ -113,6 +113,13 @@ namespace gloox {
static const std::string XMLNS_THUMBS = "urn:xmpp:thumbs:1";
static const int EXT_THUMBS = 4277;
//
// XEP-0234: Jingle File Transfer
//
static const std::string XMLNS_JINGLE_FILE_TRANSFER_5 = "urn:xmpp:jingle:apps:file-transfer:5";
static const int EXT_JINGLE_FILE = 4275;
}
#endif // GLOOXEXTS_H__
/*
* Kaidan - A user-friendly XMPP client for every device!
*
* Copyright (C) 2018 Kaidan developers and contributors
* (see the LICENSE file for a full list of copyright authors)
*
* Kaidan is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* In addition, as a special exception, the author of Kaidan gives
* permission to link the code of its release with the OpenSSL
* project's "OpenSSL" library (or with modified versions of it that
* use the same license as the "OpenSSL" library), and distribute the
* linked executables. You must obey the GNU General Public License in
* all respects for all of the code used other than "OpenSSL". If you
* modify this file, you may extend this exception to your version of
* the file, but you are not obligated to do so. If you do not wish to
* do so, delete this exception statement from your version.
*
* Kaidan is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Kaidan. If not, see <http://www.gnu.org/licenses/>.
*/
#include "jinglefile.h"
#include "gloox-extensions.h"
#include <gloox/util.h>
using namespace gloox;
using namespace gloox::Jingle;
File::File(const std::string& name, long size, HashList hashes,
const std::string& mediaType, const std::string& date,
const std::string& desc, const Thumb* thumb, long offset, long length)
: StanzaExtension(EXT_JINGLE_FILE), m_name(name), m_size(size),
m_hashes(hashes), m_mediaType(mediaType), m_date(date), m_desc(desc),
m_thumb(thumb), m_offset(offset), m_length(length), m_valid(true)
{
}
File::File(const Tag* tag)
: StanzaExtension(EXT_JINGLE_FILE), m_valid(false), m_size(-1),
m_offset(-1), m_length(-1)
{
if (tag->name() == "file")
m_valid = true;
if (tag->hasChild("name"))
m_name = tag->findChild("name")->cdata();
if (tag->hasChild("media-type"))
m_mediaType = tag->findChild("media-type")->cdata();
if (tag->hasChild("desc"))
m_desc = tag->findChild("desc")->cdata();
if (tag->hasChild("date"))
m_date = tag->findChild("date")->cdata();
if (tag->hasChild("size")) {
try {
// conversion can cause invalid_argument / out_of_range exception
m_size = std::stol(tag->findChild("size")->cdata());
} catch (std::invalid_argument &e) {
// Couldn't parse size: input probably doesn't contain valid number
} catch (std::out_of_range &e) {
// Couldn't parse size: is out of range of an unsigned long
}
}
if (tag->hasChild("range")) {
Tag* range = tag->findChild("range");
if (range->hasAttribute("offset")) {
try {
// conversion can cause invalid_argument / out_of_range exception
m_offset = std::stol(tag->findAttribute("offset"));
} catch (std::invalid_argument &e) {
// Couldn't parse size: input probably doesn't contain valid number
} catch (std::out_of_range &e) {
// Couldn't parse size: is out of range of an unsigned long
}
}
if (range->hasAttribute("length")) {
try {
// conversion can cause invalid_argument / out_of_range exception
m_length = std::stol(tag->findAttribute("length"));
} catch (std::invalid_argument &e) {
// Couldn't parse size: input probably doesn't contain valid number
} catch (std::out_of_range &e) {
// Couldn't parse size: is out of range of an unsigned long
}
}
}
// a list of all children of type hash
TagList hashes = tag->findChildren("hash");
hashes.splice(hashes.end(), tag->findChildren("hash-used"));
for (Tag* hash : hashes) {
if (hash->xmlns() == XMLNS_HASHES_2) {
Hash hashObj(hash);
if (hashObj.valid())
m_hashes.emplace_back(hashObj);
}
}
m_thumb = new Thumb(tag->findChild("thumb", XMLNS, XMLNS_THUMBS));
}
Tag* File::tag() const
{
// is *always* including the XMLNS acceptable? (only needed for non-jingle usages)
Tag* tag = new Tag("file", XMLNS, XMLNS_JINGLE_FILE_TRANSFER_5);
if (!m_name.empty()) {
Tag* name = new Tag("name");
name->addCData(m_name);
tag->addChild(name);
}
if (!m_mediaType.empty()) {
Tag* mediaType = new Tag("media-type");
mediaType->addCData(m_mediaType);
tag->addChild(mediaType);
}
if (!m_desc.empty()) {
Tag* desc = new Tag("desc");
desc->addCData(m_desc);
tag->addChild(desc);
}
if (!m_date.empty()) {
Tag* date = new Tag("date");
date->addCData(m_date);
tag->addChild(date);
}
if (m_size > 0) {
Tag* size = new Tag("size");
size->addCData(util::long2string(m_size));
tag->addChild(size);
}
if (m_offset > 0) {
Tag* range = new Tag("range");
range->addAttribute("offset", m_offset);
if (m_length > 0)
range->addAttribute("length", m_length);
tag->addChild(range);
}
if (!m_hashes.empty()) {
for (Hash hash : m_hashes)
tag->addChild(hash.tag());
}
if (m_thumb && m_thumb->valid())
tag->addChild(m_thumb->tag());
return tag;
}
const std::string& File::filterString() const
{
static const std::string filter = "file";
return filter;
}
/*
* Kaidan - A user-friendly XMPP client for every device!
*
* Copyright (C) 2018 Kaidan developers and contributors
* (see the LICENSE file for a full list of copyright authors)
*
* Kaidan is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* In addition, as a special exception, the author of Kaidan gives
* permission to link the code of its release with the OpenSSL
* project's "OpenSSL" library (or with modified versions of it that
* use the same license as the "OpenSSL" library), and distribute the
* linked executables. You must obey the GNU General Public License in
* all respects for all of the code used other than "OpenSSL". If you
* modify this file, you may extend this exception to your version of
* the file, but you are not obligated to do so. If you do not wish to
* do so, delete this exception statement from your version.
*
* Kaidan is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Kaidan. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef JINGLEFILE_H__
#define JINGLEFILE_H__
#include <gloox/stanzaextension.h>
#include <gloox/tag.h>
#include "hash.h"
#include "thumb.h"
#include <string>
#include <list>
namespace gloox {
namespace Jingle {
/**
* @class JingleFile An implementation of the file StanzaExtension of
* Jingle File Transfer (@xep{0234}).
*
* XEP Version: 0.18
*
* @author Linus Jahn <lnj@kaidan.im>
* @since 1.0.21
*/
class GLOOX_API File : public gloox::StanzaExtension
{
public:
typedef std::list<Hash> HashList;
/**
* Default constructor
*
* @param name The file's name.
* @param size The filesize in Bytes (use negative values to disable).
* @param hashes A list of Hashes.
* @param mediaType The file's MIME-type.
* @param date The file's last modification date
* @param desc A description.
* @param thumb A possible thumbnail for the content
* @param offset An offset for partial transfers (use negative values
* to disable).
* @param length The length from the offset used for a partial
* file transfer.
*/
File(const std::string& name = EmptyString, long size = -1,
HashList hashes = std::list<Hash>(),
const std::string& mediaType = EmptyString,
const std::string& date = EmptyString,
const std::string& desc = EmptyString,
const Thumb* thumb = nullptr,
long offset = -1, long length = -1);
/**
* Construct from XML Tag
*/
File(const Tag *tag);
/**
* Clone the StanzaExtension
*/
virtual StanzaExtension* clone() const
{
return new File(*this);
}
/**
* Get the XML tag
*/
virtual Tag* tag() const;
/**
* Create a new instance
*/
virtual StanzaExtension* newInstance(const Tag* tag) const
{
return new File(tag);
}
/**
* Returns the filter string for filtering by the client
*/
virtual const std::string& filterString() const;
/**
* Returns if the StanzaExtension is valid
*/
bool valid() const
{
return m_valid;
}
/**
* Get the file name
*/
std::string name() const
{
return m_name;
}
/**
* Get the file size
*/
long size() const
{
return m_size;
}
/**
* Get the media type (MIME-type)
*/
std::string mediaType() const
{
return m_mediaType;
}
/**
* Get the last modification date
*/
std::string date() const
{
return m_date;
}
/**
* Get the file description
*/
std::string desc() const
{
return m_desc;
}
/**
* Get the offset for a partial file transfer
*/
long rangeOffset() const
{
return m_offset;
}
/**
* Get the length from the offset for a partial file transfer
*/
long rangeLength() const
{
return m_length;
}
/**
* Get the list of hashes
*/
HashList hashes() const
{
return m_hashes;
}
/**
* Get a possible thumbnail/preview image
*/
const Thumb* thumb() const
{
return m_thumb;
}
private:
bool m_valid;
std::string m_name;
long m_size;
HashList m_hashes;
std::string m_mediaType;
std::string m_desc;
std::string m_date;
const Thumb* m_thumb;
long m_offset;
long m_length;
};
}
}
#endif // JINGLEFILE_H__
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment