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

media-sharing: Generate, send and receive image thumbnails

parent 007ba433
......@@ -47,6 +47,7 @@
#include "gloox-extensions/reference.h"
#include "gloox-extensions/sims.h"
#include "gloox-extensions/jinglefile.h"
#include "gloox-extensions/bitsofbinarydata.h"
// Kaidan
#include "MessageModel.h"
#include "Notifications.h"
......@@ -124,35 +125,8 @@ void MessageHandler::handleMessage(const gloox::Message &stanza, gloox::MessageS
msg.message = body;
msg.type = MessageType::MessageText; // only text, no media
//
// Get media sharing (SIMS) information
//
const gloox::Reference *ref = message->findExtension
<gloox::Reference>(gloox::EXT_REFERENCES);
if (ref && ref->getEmbeddedSIMS()) {
gloox::SIMS *sims = ref->getEmbeddedSIMS();
gloox::StringList sources = sims->sources();
for (auto &source : sources) {
if (source.rfind("https://", 0) == 0 ||
source.rfind("http://", 0) == 0) {
msg.mediaUrl = QString::fromStdString(source);
break;
}
}
gloox::Jingle::File *file = sims->file();
if (file && file->valid()) {
msg.message = QString::fromStdString(file->desc());
msg.mediaSize = file->size();
msg.mediaContentType = QString::fromStdString(file->mediaType());
msg.mediaLastModified = stringToQDateTime(file->date()).toTime_t();
QMimeType mimeType = QMimeDatabase().mimeTypeForName(msg.mediaContentType);
msg.type = getMessageType(mimeType);
for (gloox::Hash &hash : file->hashes())
msg.mediaHashes.append(QString::fromStdString(hash.tag()->xml()));
}
}
// handle media sharing (SIMS) content
handleMediaSharing(const_cast<gloox::Message*>(message), &msg);
//
// If it is a delayed delivery (containing a timestamp), use its timestamp
......@@ -203,6 +177,59 @@ void MessageHandler::handleMessage(const gloox::Message &stanza, gloox::MessageS
handleReceiptMessage(message, isCarbonMessage);
}
void MessageHandler::handleMediaSharing(const gloox::Message *message,
MessageModel::Message *msg)
{
//
// Get media sharing (SIMS) information
//
const gloox::Reference *ref = message->findExtension
<gloox::Reference>(gloox::EXT_REFERENCES);
if (ref && ref->getEmbeddedSIMS()) {
gloox::SIMS *sims = ref->getEmbeddedSIMS();
gloox::StringList sources = sims->sources();
for (auto &source : sources) {
if (source.rfind("https://", 0) == 0 ||
source.rfind("http://", 0) == 0) {
msg->mediaUrl = QString::fromStdString(source);
break;
}
}
gloox::Jingle::File *file = sims->file();
if (file && file->valid()) {
msg->message = QString::fromStdString(file->desc());
msg->mediaSize = file->size();
msg->mediaContentType = QString::fromStdString(file->mediaType());
msg->mediaLastModified = stringToQDateTime(file->date()).toTime_t();
QMimeType mimeType = QMimeDatabase().mimeTypeForName(msg->mediaContentType);
msg->type = getMessageType(mimeType);
for (gloox::Hash &hash : file->hashes())
msg->mediaHashes.append(QString::fromStdString(hash.tag()->xml()));
// extract thumbnail
const gloox::Jingle::Thumb *thumb = file->thumb();
if (thumb && thumb->valid()) {
// check if uri is valid (it is a BoB content id [cid])
std::string uri = thumb->uri();
if (uri.rfind("cid:", 0) == 0) {
const gloox::BitsOfBinaryData *thumbData = message->
findExtension<gloox::BitsOfBinaryData>(gloox::EXT_BITSOFBINARY);
// check if thumbnail uri matches the attached data uri
if (thumbData && thumb->uri() == uri.substr(4, uri.length() - 4)) {
// save media thumbnail
msg->mediaThumb = QByteArray::fromBase64(
QByteArray::fromStdString(thumbData->data())
);
}
}
}
}
}
}
void MessageHandler::handleReceiptMessage(const gloox::Message *message,
bool isCarbonMessage)
{
......
......@@ -65,6 +65,12 @@ public:
virtual void handleMessage(const gloox::Message &message, gloox::MessageSession *session = 0);
/**
* Handles and processes media sharing content of messages
*/
void handleMediaSharing(const gloox::Message *message,
MessageModel::Message *msg);
/**
* Handles a message with a possible receipt or receipt request
*/
......
......@@ -33,16 +33,21 @@
#include "MessageHandler.h"
// gloox
#include <gloox/message.h>
#include <gloox/base64.h>
#include "gloox-extensions/httpuploadmanager.h"
#include "gloox-extensions/reference.h"
#include "gloox-extensions/sims.h"
#include "gloox-extensions/processinghints.h"
#include "gloox-extensions/jinglefile.h"
#include "gloox-extensions/hash.h"
#include "gloox-extensions/thumb.h"
#include "gloox-extensions/bitsofbinarydata.h"
// Qt
#include <QMimeDatabase>
#include <QMimeType>
#include <QDateTime>
#include <QBuffer>
#include <QImage>
#include <QDebug>
UploadHandler::UploadHandler(gloox::Client *client, MessageHandler *msgHandler,
......@@ -61,7 +66,6 @@ void UploadHandler::uploadFile(QString jid, QString filePath, QString message)
QMimeDatabase mimeDb;
QMimeType mimeType = mimeDb.mimeTypeForFile(filePath);
QString mimeTypeStr = mimeType.name();
qDebug() << filePath;
int id = manager->uploadFile(filePath.toStdString(), true,
mimeTypeStr.toStdString());
......@@ -75,10 +79,11 @@ void UploadHandler::uploadFile(QString jid, QString filePath, QString message)
meta.jid = jid;
meta.msgId = client->getID();
meta.message = message;
meta.filePath = filePath;
meta.type = msgHandler->getMessageType(mimeType);
mediaShares[id] = meta;
MessageType type = msgHandler->getMessageType(mimeType);
msgHandler->addMessageToDb(
jid, message, QString::fromStdString(meta.msgId),
MessageType::MessageFile, filePath
......@@ -91,6 +96,8 @@ void UploadHandler::handleUploadFailed(int id, gloox::HttpUploadError error,
const std::string &stamp)
{
qDebug() << "[client] A file upload has failed.";
// the media meta isn't needed anymore, so delete it
mediaShares.remove(id);
}
void UploadHandler::handleUploadFinished(int id, std::string &name,
......@@ -105,7 +112,6 @@ void UploadHandler::handleUploadFinished(int id, std::string &name,
msg.mediaContentType = QString::fromStdString(contentType);
msg.mediaSize = size;
// TODO: generate thumbnail
// TODO: lastModified / date
// Hashes
......@@ -120,10 +126,30 @@ void UploadHandler::handleUploadFinished(int id, std::string &name,
// last modified date
std::string date = "";
// thumbnail
QSize thumbSize = generateMediaThumb(mediaShares[id].filePath,
mediaShares[id].type, &msg.mediaThumb);
gloox::Jingle::Thumb *thumb = nullptr;
gloox::BitsOfBinaryData *thumbBob = nullptr;
if (!msg.mediaThumb.isEmpty()) {
// encode to base64
std::string thumbData = gloox::Base64::encode64(
std::string(msg.mediaThumb.constData(), msg.mediaThumb.length())
);
// create BoB content identifier
std::string thumbCid = gloox::BitsOfBinaryData::generateContentId(thumbData);
// create BoB data object
thumbBob = new gloox::BitsOfBinaryData(thumbData, thumbCid, "image/jpeg");
// create thumb object (links to BoB data)
thumb = new gloox::Jingle::Thumb(
"cid:" + thumbCid, thumbSize.width(), thumbSize.height(), "image/jpeg"
);
}
// file meta information
gloox::Jingle::File *fileInfo = new gloox::Jingle::File(
name, size, hashes, contentType, date,
mediaShares[id].message.toStdString()
mediaShares[id].message.toStdString(), thumb
);
// list of sources for the file (TODO: jingle as fallback)
......@@ -144,6 +170,8 @@ void UploadHandler::handleUploadFinished(int id, std::string &name,
gloox::Message message(gloox::Message::Chat, to.bareJID(), msgBody);
message.setID(mediaShares[id].msgId);
message.addExtension((gloox::StanzaExtension*) simsRef);
if (thumbBob)
message.addExtension(thumbBob); // thumbnail BoB data
client->send(message);
......@@ -173,3 +201,25 @@ void UploadHandler::handleUploadServiceAdded(const gloox::JID &jid,
void UploadHandler::handleFileSizeLimitChanged(unsigned long maxFileSize)
{
}
QSize UploadHandler::generateMediaThumb(QString &filePath, MessageType type,
QByteArray *bytes)
{
if (type != MessageType::MessageImage)
return QSize(0, 0);
// results should be about 1-3 kB large
int finalSize = 40;
QImage img(filePath);
// Qt::FastTransformation is used because quality doesn't matter at this
// size; you won't be able to really see a large difference
img = img.scaled(finalSize, finalSize, Qt::KeepAspectRatio, Qt::FastTransformation);
// save image to byte array
QBuffer buffer(bytes);
buffer.open(QIODevice::WriteOnly);
img.save(&buffer, "JPEG", 90);
return img.size();
}
......@@ -37,6 +37,11 @@
// Qt
#include <QObject>
#include <QMap>
#include <QSize>
// Kaidan
#include "Enums.h"
using namespace Enums;
namespace gloox {
class Client;
......@@ -133,10 +138,18 @@ protected:
const std::string &stamp = gloox::EmptyString);
private:
/**
* Generates a media thumbnail (currently only image thumbs)
*/
QSize generateMediaThumb(QString &filePath, MessageType type,
QByteArray *bytes);
struct MediaSharingMeta {
QString jid;
std::string msgId;
QString message;
QString filePath;
MessageType type;
};
gloox::Client *client;
......
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