mirror of
https://github.com/profanity-im/profanity.git
synced 2024-09-01 19:24:15 -04:00
Merge pull request #1714 from MarcoPolo-PasTonMolo/feature/avatar-set
Add `/avatar set` command to publish avatar
This commit is contained in:
commit
010ed78b32
@ -26,7 +26,8 @@ RUN pacman -Syu --noconfirm && pacman -S --needed --noconfirm \
|
||||
pkg-config \
|
||||
python \
|
||||
wget \
|
||||
sqlite
|
||||
sqlite \
|
||||
gdk-pixbuf2
|
||||
|
||||
RUN mkdir -p /usr/src/{stabber,profanity}
|
||||
|
||||
|
@ -27,7 +27,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
pkg-config \
|
||||
python3-dev \
|
||||
python-dev-is-python3 \
|
||||
libsqlite3-dev
|
||||
libsqlite3-dev \
|
||||
libgdk-pixbuf-2.0-dev
|
||||
|
||||
RUN mkdir -p /usr/src/{stabber,libstrophe,profanity}
|
||||
WORKDIR /usr/src
|
||||
|
@ -34,7 +34,8 @@ RUN dnf install -y \
|
||||
python3-devel \
|
||||
readline-devel \
|
||||
openssl-devel \
|
||||
sqlite-devel
|
||||
sqlite-devel \
|
||||
gdk-pixbuf2-devel
|
||||
|
||||
# https://github.com/openSUSE/docker-containers-build/issues/26
|
||||
ENV LANG en_US.UTF-8
|
||||
|
@ -34,7 +34,8 @@ RUN zypper --non-interactive in --no-recommends \
|
||||
python38 \
|
||||
python38-devel \
|
||||
readline-devel \
|
||||
sqlite3-devel
|
||||
sqlite3-devel \
|
||||
gdk-pixbuf-devel
|
||||
|
||||
# https://github.com/openSUSE/docker-containers-build/issues/26
|
||||
ENV LANG en_US.UTF-8
|
||||
|
@ -28,7 +28,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
pkg-config \
|
||||
python3-dev \
|
||||
python-dev-is-python3 \
|
||||
libsqlite3-dev
|
||||
libsqlite3-dev \
|
||||
libgdk-pixbuf-2.0-dev
|
||||
|
||||
RUN mkdir -p /usr/src/{stabber,libstrophe,profanity}
|
||||
WORKDIR /usr/src
|
||||
|
@ -44,7 +44,7 @@ case $(uname | tr '[:upper:]' '[:lower:]') in
|
||||
tests=(
|
||||
"--enable-notifications --enable-icons-and-clipboard --enable-otr --enable-pgp
|
||||
--enable-omemo --enable-plugins --enable-c-plugins
|
||||
--enable-python-plugins --with-xscreensaver"
|
||||
--enable-python-plugins --with-xscreensaver --enable-gdk-pixbuf"
|
||||
"--disable-notifications --disable-icons-and-clipboard --disable-otr --disable-pgp
|
||||
--disable-omemo --disable-plugins --disable-c-plugins
|
||||
--disable-python-plugins --without-xscreensaver"
|
||||
@ -60,6 +60,7 @@ case $(uname | tr '[:upper:]' '[:lower:]') in
|
||||
"--disable-c-plugins"
|
||||
"--disable-c-plugins --disable-python-plugins"
|
||||
"--without-xscreensaver"
|
||||
"--disable-gdk-pixbuf"
|
||||
"")
|
||||
;;
|
||||
darwin*)
|
||||
|
11
configure.ac
11
configure.ac
@ -65,6 +65,8 @@ AC_ARG_WITH([themes],
|
||||
[AS_HELP_STRING([--with-themes[[=PATH]]], [install themes (default yes)])])
|
||||
AC_ARG_ENABLE([icons-and-clipboard],
|
||||
[AS_HELP_STRING([--enable-icons-and-clipboard], [enable GTK tray icons and clipboard paste support])])
|
||||
AC_ARG_ENABLE([gdk-pixbuf],
|
||||
[AS_HELP_STRING([--enable-gdk-pixbuf], [enable GDK Pixbuf support to scale avatars before uploading])])
|
||||
|
||||
# Required dependencies
|
||||
|
||||
@ -306,6 +308,15 @@ if test "x$enable_otr" != xno; then
|
||||
AM_COND_IF([BUILD_OTR], [AC_DEFINE([HAVE_LIBOTR], [1], [Have libotr])])
|
||||
fi
|
||||
|
||||
dnl feature: pixbuf / used for scaling avatars before uploading via `/avatar set`
|
||||
AS_IF([test "x$enable_pixbuf" != xno],
|
||||
[PKG_CHECK_MODULES([gdk_pixbuf], [gdk-pixbuf-2.0 >= 2.4],
|
||||
[AC_DEFINE([HAVE_PIXBUF], [1], [gdk-pixbuf module])
|
||||
LIBS="$gdk_pixbuf_LIBS $LIBS" CFLAGS="$gdk_pixbuf_CFLAGS $CFLAGS"],
|
||||
[AS_IF([test "x$enable_pixbuf" = xyes],
|
||||
[AC_MSG_ERROR([gdk-pixbuf-2.0 >= 2.4 is required to scale avatars before uploading])],
|
||||
[AC_MSG_NOTICE([gdk-pixbuf-2.0 >= 2.4 not found, GDK Pixbuf support not enabled])])])])
|
||||
|
||||
dnl feature: omemo
|
||||
AM_CONDITIONAL([BUILD_OMEMO], [false])
|
||||
if test "x$enable_omemo" != xno; then
|
||||
|
@ -1057,6 +1057,7 @@ cmd_ac_init(void)
|
||||
autocomplete_add(correction_ac, "char");
|
||||
|
||||
avatar_ac = autocomplete_new();
|
||||
autocomplete_add(avatar_ac, "set");
|
||||
autocomplete_add(avatar_ac, "get");
|
||||
autocomplete_add(avatar_ac, "open");
|
||||
|
||||
@ -4101,6 +4102,11 @@ _avatar_autocomplete(ProfWin* window, const char* const input, gboolean previous
|
||||
|
||||
jabber_conn_status_t conn_status = connection_get_status();
|
||||
if (conn_status == JABBER_CONNECTED) {
|
||||
result = cmd_ac_complete_filepath(input, "/avatar set", previous);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result = autocomplete_param_with_func(input, "/avatar get", roster_barejid_autocomplete, previous, NULL);
|
||||
if (result) {
|
||||
return result;
|
||||
|
@ -2443,16 +2443,20 @@ static struct cmd_t command_defs[] = {
|
||||
CMD_TAGS(
|
||||
CMD_TAG_CHAT)
|
||||
CMD_SYN(
|
||||
"/avatar set <path>",
|
||||
"/avatar get <barejid>",
|
||||
"/avatar open <barejid>")
|
||||
CMD_DESC(
|
||||
"Upload avatar for oneself (XEP-0084). "
|
||||
"Download avatar (XEP-0084) for a certain contact. "
|
||||
"If nothing happens after using this command the user either doesn't have an avatar set at all "
|
||||
"or doesn't use XEP-0084 to publish it.")
|
||||
CMD_ARGS(
|
||||
{ "set <path>", "Set avatar to the image at <path>." },
|
||||
{ "get <barejid>", "Download the avatar. barejid is the JID to download avatar from." },
|
||||
{ "open <barejid>", "Download avatar and open it with command." })
|
||||
CMD_EXAMPLES(
|
||||
"/avatar set ~/images/avatar.png",
|
||||
"/avatar get thor@valhalla.edda",
|
||||
"/avatar open freyja@vanaheimr.edda") },
|
||||
|
||||
|
@ -9195,7 +9195,15 @@ cmd_avatar(ProfWin* window, const char* const command, gchar** args)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (g_strcmp0(args[0], "get") == 0) {
|
||||
if (g_strcmp0(args[0], "set") == 0) {
|
||||
#ifdef HAVE_PIXBUF
|
||||
if (avatar_set(args[1])) {
|
||||
cons_show("Avatar updated successfully");
|
||||
}
|
||||
#else
|
||||
cons_show("Profanity has not been built with GDK Pixbuf support enabled which is needed to scale the avatar when uploading.");
|
||||
#endif
|
||||
} else if (g_strcmp0(args[0], "get") == 0) {
|
||||
avatar_get_by_nick(args[1], false);
|
||||
} else if (g_strcmp0(args[0], "open") == 0) {
|
||||
avatar_get_by_nick(args[1], true);
|
||||
|
@ -173,6 +173,12 @@ main(int argc, char** argv)
|
||||
g_print("GTK icons/clipboard: Disabled\n");
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_PIXBUF
|
||||
g_print("GDK Pixbuf: Enabled\n");
|
||||
#else
|
||||
g_print("GDK Pixbuf: Disabled\n");
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -8,3 +8,9 @@ avatar_get_by_nick(const char* nick)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
avatar_set(const char* path)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user