Merge pull request #1714 from MarcoPolo-PasTonMolo/feature/avatar-set

Add `/avatar set` command to publish avatar
This commit is contained in:
Michael Vetter
2022-05-30 18:01:50 +02:00
committed by GitHub
16 changed files with 220 additions and 7 deletions

View File

@@ -36,6 +36,9 @@
#include "config.h"
#include <glib.h>
#ifdef HAVE_PIXBUF
#include <gdk-pixbuf-2.0/gdk-pixbuf/gdk-pixbuf.h>
#endif
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
@@ -59,6 +62,7 @@ typedef struct avatar_metadata
static GHashTable* looking_for = NULL; // contains nicks/barejids from who we want to get the avatar
static GHashTable* shall_open = NULL; // contains a list of nicks that shall not just downloaded but also opened
const int MAX_PIXEL = 192; // max pixel width/height for an avatar
static void _avatar_request_item_by_id(const char* jid, avatar_metadata* data);
static int _avatar_metadata_handler(xmpp_stanza_t* const stanza, void* const userdata);
@@ -92,6 +96,60 @@ avatar_pep_subscribe(void)
shall_open = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
}
#ifdef HAVE_PIXBUF
gboolean
avatar_set(const char* path)
{
char* expanded_path = get_expanded_path(path);
GError* err = NULL;
GdkPixbuf* pixbuf = gdk_pixbuf_new_from_file(expanded_path, &err);
if (pixbuf == NULL) {
cons_show_error("An error occurred while opening %s: %s.", expanded_path, err ? err->message : "No error message given");
return FALSE;
}
free(expanded_path);
// Scale img
int w = gdk_pixbuf_get_width(pixbuf);
int h = gdk_pixbuf_get_height(pixbuf);
if (w >= h && w > MAX_PIXEL) {
int dest_height = (int)((float)MAX_PIXEL / w * h);
GdkPixbuf* new_pixbuf = gdk_pixbuf_scale_simple(pixbuf, MAX_PIXEL, dest_height, GDK_INTERP_BILINEAR);
g_object_unref(pixbuf);
pixbuf = new_pixbuf;
} else if (h > w && w > MAX_PIXEL) {
int dest_width = (int)((float)MAX_PIXEL / h * w);
GdkPixbuf* new_pixbuf = gdk_pixbuf_scale_simple(pixbuf, dest_width, MAX_PIXEL, GDK_INTERP_BILINEAR);
g_object_unref(pixbuf);
pixbuf = new_pixbuf;
}
gchar* img_data;
gsize len = -1;
if (!gdk_pixbuf_save_to_buffer(pixbuf, &img_data, &len, "png", &err, NULL)) {
cons_show_error("Unable to scale and convert avatar.");
return FALSE;
}
xmpp_ctx_t* const ctx = connection_get_ctx();
xmpp_stanza_t* iq = stanza_create_avatar_data_publish_iq(ctx, img_data, len);
iq_send_stanza(iq);
xmpp_stanza_release(iq);
iq = stanza_create_avatar_metadata_publish_iq(ctx, img_data, len, gdk_pixbuf_get_height(pixbuf), gdk_pixbuf_get_width(pixbuf));
free(img_data);
g_object_unref(pixbuf);
iq_send_stanza(iq);
xmpp_stanza_release(iq);
return TRUE;
}
#endif
gboolean
avatar_get_by_nick(const char* nick, gboolean open)
{

View File

@@ -40,5 +40,8 @@
void avatar_pep_subscribe(void);
gboolean avatar_get_by_nick(const char* nick, gboolean open);
#ifdef HAVE_PIXBUF
gboolean avatar_set(const char* path);
#endif
#endif

View File

@@ -2586,6 +2586,107 @@ stanza_create_avatar_retrieve_data_request(xmpp_ctx_t* ctx, const char* stanza_i
return iq;
}
xmpp_stanza_t*
stanza_create_avatar_data_publish_iq(xmpp_ctx_t* ctx, const char* img_data, gsize len)
{
char* id = connection_create_stanza_id();
xmpp_stanza_t* iq = xmpp_iq_new(ctx, STANZA_TYPE_SET, id);
free(id);
xmpp_stanza_set_attribute(iq, STANZA_ATTR_FROM, connection_get_fulljid());
xmpp_stanza_t* pubsub = xmpp_stanza_new(ctx);
xmpp_stanza_set_name(pubsub, STANZA_NAME_PUBSUB);
xmpp_stanza_set_ns(pubsub, STANZA_NS_PUBSUB);
xmpp_stanza_t* publish = xmpp_stanza_new(ctx);
xmpp_stanza_set_name(publish, STANZA_NAME_PUBLISH);
xmpp_stanza_set_attribute(publish, STANZA_ATTR_NODE, STANZA_NS_USER_AVATAR_DATA);
xmpp_stanza_t* item = xmpp_stanza_new(ctx);
xmpp_stanza_set_name(item, STANZA_NAME_ITEM);
char* sha1 = xmpp_sha1(ctx, (guchar*)img_data, len);
xmpp_stanza_set_attribute(item, "id", sha1);
xmpp_free(ctx, sha1);
xmpp_stanza_t* data = xmpp_stanza_new(ctx);
xmpp_stanza_set_name(data, STANZA_NAME_DATA);
xmpp_stanza_set_ns(data, STANZA_NS_USER_AVATAR_DATA);
xmpp_stanza_t* text = xmpp_stanza_new(ctx);
gchar* base64 = g_base64_encode((guchar*)img_data, len);
xmpp_stanza_set_text(text, base64);
free(base64);
xmpp_stanza_add_child(data, text);
xmpp_stanza_add_child(item, data);
xmpp_stanza_add_child(publish, item);
xmpp_stanza_add_child(pubsub, publish);
xmpp_stanza_add_child(iq, pubsub);
xmpp_stanza_release(text);
xmpp_stanza_release(data);
xmpp_stanza_release(item);
xmpp_stanza_release(publish);
xmpp_stanza_release(pubsub);
return iq;
}
xmpp_stanza_t*
stanza_create_avatar_metadata_publish_iq(xmpp_ctx_t* ctx, const char* img_data, gsize len, int height, int width)
{
char* id = id = connection_create_stanza_id();
xmpp_stanza_t* iq = xmpp_iq_new(ctx, STANZA_TYPE_SET, id);
free(id);
xmpp_stanza_set_attribute(iq, STANZA_ATTR_FROM, connection_get_fulljid());
xmpp_stanza_t* pubsub = xmpp_stanza_new(ctx);
xmpp_stanza_set_name(pubsub, STANZA_NAME_PUBSUB);
xmpp_stanza_set_ns(pubsub, STANZA_NS_PUBSUB);
xmpp_stanza_t* publish = xmpp_stanza_new(ctx);
xmpp_stanza_set_name(publish, STANZA_NAME_PUBLISH);
xmpp_stanza_set_attribute(publish, STANZA_ATTR_NODE, STANZA_NS_USER_AVATAR_METADATA);
xmpp_stanza_t* item = xmpp_stanza_new(ctx);
xmpp_stanza_set_name(item, STANZA_NAME_ITEM);
char* sha1 = xmpp_sha1(ctx, (guchar*)img_data, len);
xmpp_stanza_set_attribute(item, "id", sha1);
xmpp_stanza_t* metadata = xmpp_stanza_new(ctx);
xmpp_stanza_set_name(metadata, STANZA_NAME_METADATA);
xmpp_stanza_set_ns(metadata, STANZA_NS_USER_AVATAR_METADATA);
xmpp_stanza_t* info = xmpp_stanza_new(ctx);
xmpp_stanza_set_name(info, STANZA_NAME_INFO);
xmpp_stanza_set_attribute(info, "id", sha1);
xmpp_free(ctx, sha1);
char* bytes = g_strdup_printf("%lu", len);
char* h = g_strdup_printf("%d", height);
char* w = g_strdup_printf("%d", width);
xmpp_stanza_set_attribute(info, "bytes", bytes);
xmpp_stanza_set_attribute(info, "type", "img/png");
xmpp_stanza_set_attribute(info, "height", h);
xmpp_stanza_set_attribute(info, "width", w);
g_free(bytes);
g_free(h);
g_free(w);
xmpp_stanza_add_child(metadata, info);
xmpp_stanza_add_child(item, metadata);
xmpp_stanza_add_child(publish, item);
xmpp_stanza_add_child(pubsub, publish);
xmpp_stanza_add_child(iq, pubsub);
xmpp_stanza_release(info);
xmpp_stanza_release(metadata);
xmpp_stanza_release(item);
xmpp_stanza_release(publish);
xmpp_stanza_release(pubsub);
return iq;
}
xmpp_stanza_t*
stanza_attach_correction(xmpp_ctx_t* ctx, xmpp_stanza_t* stanza, const char* const replace_id)
{

View File

@@ -62,6 +62,8 @@
#define STANZA_NAME_PUBLIC_KEYS_LIST "public-keys-list"
#define STANZA_NAME_PUBKEY_METADATA "pubkey-metadata"
#define STANZA_NAME_DATA "data"
#define STANZA_NAME_METADATA "metadata"
#define STANZA_NAME_INFO "info"
#define STANZA_NAME_SHOW "show"
#define STANZA_NAME_STATUS "status"
#define STANZA_NAME_IQ "iq"
@@ -409,6 +411,8 @@ XMPPCaps* stanza_parse_caps(xmpp_stanza_t* const stanza);
void stanza_free_caps(XMPPCaps* caps);
xmpp_stanza_t* stanza_create_avatar_retrieve_data_request(xmpp_ctx_t* ctx, const char* stanza_id, const char* const item_id, const char* const jid);
xmpp_stanza_t* stanza_create_avatar_data_publish_iq(xmpp_ctx_t* ctx, const char* img_data, gsize len);
xmpp_stanza_t* stanza_create_avatar_metadata_publish_iq(xmpp_ctx_t* ctx, const char* img_data, gsize len, int height, int width);
xmpp_stanza_t* stanza_create_mam_iq(xmpp_ctx_t* ctx, const char* const jid, const char* const startdate, const char* const lastid);
xmpp_stanza_t* stanza_change_password(xmpp_ctx_t* ctx, const char* const user, const char* const password);
xmpp_stanza_t* stanza_register_new_account(xmpp_ctx_t* ctx, const char* const user, const char* const password);