Commit 7cb54acf authored by Evangelos Ribeiro Tzaras's avatar Evangelos Ribeiro Tzaras
Browse files

chatty Debian release 0.3.2-1

Merge tag 'debian/0.3.2-1' into rel_0.3.2-1
parents d169e873 0be1b325
......@@ -49,13 +49,6 @@ Please go to the git page where you'll find information on how to build and use
This can be skipped if encrypted messaging is not needed.
### Build and install the 'purple-matrix' plugin
Please go to the git page where you'll find information on how to build and install the
[Matrix messenger plugin](https://github.com/matrix-org/purple-matrix)
This can be skipped if Matrix messaging is not needed.
### Build and install the 'purple-telegram' plugin
Please go to the git page where you'll find information on how to build and install the
[Telegram messenger plugin](https://github.com/majn/telegram-purple)
......@@ -74,6 +67,12 @@ meson build
ninja -C build
```
### Enabling Matrix support (optional)
To enable matrix support, run the following:
```bash
gsettings set sm.puri.Chatty experimental-features true
```
## Running from the source tree
To run Chatty from source tree (without installing) do:
......@@ -115,6 +114,13 @@ If you don't have an XMPP account yet and want to subscribe to a service then pl
- XEP-0313: Message Archive Management
- XEP-0363: HTTP File Upload
## Known issues
- chatty crashes in OMEMO encrypted chats. This is due to a symbol conflict between
libolm3 and libaxc. A work around is done in [PureOS][3]. A proper fix would
be to not export those symbols from libolm at all.
[0]: http://software.pureos.net/search_pkg?term=libhandy-1-dev
[1]: https://packages.debian.org/search?keywords=libhandy-1-dev
[2]: https://source.puri.sm/Librem5/libhandy
[3]: https://source.puri.sm/Librem5/debs/olm/-/merge_requests/2
chatty (0.3.2-1) experimental; urgency=medium
* New upstream version 0.3.2
-- Evangelos Ribeiro Tzaras <devrtz-debian@fortysixandtwo.eu> Tue, 29 Jun 2021 18:57:19 +0200
chatty (0.3.1-1pureos1) byzantium; urgency=medium
* Upload to byzantium
......
project(
'chatty', 'c', 'cpp',
version: '0.3.1',
version: '0.3.2',
meson_version: '>= 0.46.0',
)
......@@ -28,11 +28,12 @@ else
endif
configure_file(
output: 'chatty-config.h',
output: 'config.h',
configuration: config_h,
)
add_project_arguments([
'-I' + meson.build_root(),
'-DHAVE_CONFIG_H',
'-DGLIB_DISABLE_DEPRECATION_WARNINGS',
'-DG_LOG_USE_STRUCTURED',
], language: 'c')
......
......@@ -12,8 +12,6 @@ src/chatty-contact-provider.c
src/chatty-contact-provider.h
src/chatty-history.c
src/chatty-history.h
src/chatty-icons.c
src/chatty-icons.h
src/chatty-fp-row.c
src/chatty-fp-row.h
src/chatty-list-row.c
......@@ -43,6 +41,8 @@ src/dialogs/chatty-new-chat-dialog.c
src/dialogs/chatty-new-chat-dialog.h
src/dialogs/chatty-new-muc-dialog.c
src/dialogs/chatty-new-muc-dialog.h
src/dialogs/chatty-pp-account-details.c
src/dialogs/chatty-pp-account-details.h
src/dialogs/chatty-settings-dialog.c
src/dialogs/chatty-settings-dialog.h
src/main.c
......@@ -58,6 +58,7 @@ src/ui/chatty-dialog-new-chat.ui
src/ui/chatty-info-dialog.ui
src/ui/chatty-fp-row.ui
src/ui/chatty-list-row.ui
src/ui/chatty-pp-account-details.ui
src/ui/chatty-settings-dialog.ui
src/ui/chatty-window.ui
src/users/chatty-account.c
......
This diff is collapsed.
......@@ -23,10 +23,13 @@
#define G_LOG_DOMAIN "chatty-application"
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <glib/gi18n.h>
#include <handy.h>
#include "chatty-config.h"
#include "chatty-window.h"
#include "chatty-utils.h"
#include "users/chatty-pp-account.h"
......@@ -209,6 +212,7 @@ application_open_chat (ChattyApplication *self,
}
chatty_window_open_chat (CHATTY_WINDOW (self->main_window), chat);
gtk_window_present (GTK_WINDOW (self->main_window));
}
static gboolean
......@@ -445,17 +449,6 @@ chatty_application_new (void)
NULL);
}
ChattyWindow *
chatty_application_get_main_window (ChattyApplication *self)
{
g_return_val_if_fail (CHATTY_IS_APPLICATION (self), NULL);
if (self->main_window)
return CHATTY_WINDOW (self->main_window);
return NULL;
}
/**
* chatty_application_get_active_chat:
* @self: A #ChattyApplication
......@@ -470,14 +463,9 @@ chatty_application_get_main_window (ChattyApplication *self)
ChattyChat *
chatty_application_get_active_chat (ChattyApplication *self)
{
GtkWidget *widget = NULL;
g_return_val_if_fail (CHATTY_IS_APPLICATION (self), NULL);
if (self->main_window)
widget = gtk_window_get_focus (GTK_WINDOW (self->main_window));
if (self->main_window && widget && gtk_widget_has_focus (widget))
return chatty_window_get_active_chat (CHATTY_WINDOW (self->main_window));
return NULL;
......
......@@ -35,7 +35,6 @@ G_BEGIN_DECLS
G_DECLARE_FINAL_TYPE (ChattyApplication, chatty_application, CHATTY, APPLICATION, GtkApplication)
ChattyApplication *chatty_application_new (void);
ChattyWindow *chatty_application_get_main_window (ChattyApplication *self);
ChattyChat *chatty_application_get_active_chat (ChattyApplication *self);
G_END_DECLS
......@@ -15,9 +15,8 @@
#include "chatty-chat.h"
#include "chatty-pp-chat.h"
#include "chatty-history.h"
#include "chatty-icons.h"
#include "chatty-manager.h"
#include "chatty-utils.h"
#include "chatty-enums.h"
#include "chatty-window.h"
#include "matrix/chatty-ma-chat.h"
#include "users/chatty-contact.h"
......@@ -286,61 +285,6 @@ chat_view_message_row_new (ChattyMessage *message,
return GTK_WIDGET (row);
}
static void
messages_items_changed_cb (ChattyChatView *self,
guint position,
guint removed,
guint added)
{
ChattyMessage *next_msg, *msg;
GtkListBoxRow *row, *next_row;
GtkListBox *list;
time_t next_time, time;
g_assert (CHATTY_IS_CHAT_VIEW (self));
if (added == 0)
return;
list = GTK_LIST_BOX (self->message_list);
/* Hide duplicate author labels in group chats */
if (!chatty_chat_is_im (self->chat) ||
CHATTY_IS_MA_CHAT (self->chat)) {
for (gint i = position; i < position + added; i++) {
next_row = gtk_list_box_get_row_at_index (list, i + 1);
if (!next_row)
break;
row = gtk_list_box_get_row_at_index (list, i);
msg = chatty_message_row_get_item (CHATTY_MESSAGE_ROW (row));
next_msg = chatty_message_row_get_item (CHATTY_MESSAGE_ROW (next_row));
if (chatty_message_user_matches (msg, next_msg))
chatty_message_row_hide_user_detail (CHATTY_MESSAGE_ROW (next_row));
}
}
for (gint i = position; i < position + added; i++) {
next_row = gtk_list_box_get_row_at_index (list, i + 1);
if (!next_row)
break;
row = gtk_list_box_get_row_at_index (list, i);
msg = chatty_message_row_get_item (CHATTY_MESSAGE_ROW (row));
time = chatty_message_get_time (msg);
next_msg = chatty_message_row_get_item (CHATTY_MESSAGE_ROW (next_row));
next_time = chatty_message_get_time (next_msg);
/* Hide footer of the previous message if both have same time (in minutes) */
if (time / 60 == next_time / 60)
chatty_message_row_hide_footer (CHATTY_MESSAGE_ROW (row));
}
}
static void
chat_encrypt_changed_cb (ChattyChatView *self)
{
......@@ -492,7 +436,7 @@ chat_view_send_message_button_clicked_cb (ChattyChatView *self)
protocol == CHATTY_PROTOCOL_TELEGRAM)
escaped = purple_markup_escape_text (message, -1);
msg = chatty_message_new (NULL, NULL, escaped ? escaped : message,
msg = chatty_message_new (NULL, escaped ? escaped : message,
NULL, time (NULL),
escaped ? CHATTY_MESSAGE_HTML_ESCAPED : CHATTY_MESSAGE_TEXT,
CHATTY_DIRECTION_OUT, 0);
......@@ -610,6 +554,30 @@ chat_view_adjustment_changed_cb (GtkAdjustment *adjustment,
chat_view_adjustment_value_changed_cb (self);
}
static void
chat_view_update_header_func (ChattyMessageRow *row,
ChattyMessageRow *before,
gpointer user_data)
{
ChattyMessage *a, *b;
time_t a_time, b_time;
if (!before || !row)
return;
a = chatty_message_row_get_item (before);
b = chatty_message_row_get_item (row);
a_time = chatty_message_get_time (a);
b_time = chatty_message_get_time (b);
if (chatty_message_user_matches (a, b))
chatty_message_row_hide_user_detail (row);
/* Hide footer of the previous message if both have same time (in minutes) */
if (a_time / 60 == b_time / 60)
chatty_message_row_hide_footer (before);
}
static void
chat_view_get_files_cb (GObject *object,
GAsyncResult *result,
......@@ -765,6 +733,9 @@ chatty_chat_view_init (ChattyChatView *self)
self);
g_signal_connect_after (G_OBJECT (self), "file-requested",
G_CALLBACK (chat_view_file_requested_cb), self);
gtk_list_box_set_header_func (GTK_LIST_BOX (self->message_list),
(GtkListBoxUpdateHeaderFunc)chat_view_update_header_func,
NULL, NULL);
}
GtkWidget *
......@@ -796,13 +767,12 @@ void
chatty_chat_view_set_chat (ChattyChatView *self,
ChattyChat *chat)
{
GListModel *messages;
g_return_if_fail (CHATTY_IS_CHAT_VIEW (self));
g_return_if_fail (CHATTY_IS_CHAT (chat));
g_return_if_fail (!chat || CHATTY_IS_CHAT (chat));
if (self->chat && chat != self->chat) {
g_signal_handlers_disconnect_by_func (chatty_chat_get_messages (self->chat),
messages_items_changed_cb,
self);
g_signal_handlers_disconnect_by_func (self->chat,
chat_encrypt_changed_cb,
self);
......@@ -819,14 +789,14 @@ chatty_chat_view_set_chat (ChattyChatView *self,
if (!chat)
return;
messages = chatty_chat_get_messages (chat);
if (g_list_model_get_n_items (messages) <= 3)
chatty_chat_load_past_messages (chat, -1);
gtk_list_box_bind_model (GTK_LIST_BOX (self->message_list),
chatty_chat_get_messages (self->chat),
(GtkListBoxCreateWidgetFunc)chat_view_message_row_new,
self, NULL);
g_signal_connect_swapped (chatty_chat_get_messages (self->chat),
"items-changed",
G_CALLBACK (messages_items_changed_cb),
self);
g_signal_connect_swapped (self->chat, "notify::encrypt",
G_CALLBACK (chat_encrypt_changed_cb),
self);
......
......@@ -17,12 +17,6 @@
G_BEGIN_DECLS
typedef enum {
ADD_MESSAGE_ON_BOTTOM,
ADD_MESSAGE_ON_TOP,
} e_msg_pos;
#define CHATTY_TYPE_CHAT_VIEW (chatty_chat_view_get_type ())
G_DECLARE_FINAL_TYPE (ChattyChatView, chatty_chat_view, CHATTY, CHAT_VIEW, GtkBox)
......
......@@ -148,3 +148,10 @@ typedef enum
CHATTY_ITEM_ARCHIVED,
CHATTY_ITEM_BLOCKED,
} ChattyItemState;
typedef enum
{
CHATTY_SMS_RECEIPT_NONE = -1,
CHATTY_SMS_RECEIPT_MM_ACKN = 0,
CHATTY_SMS_RECEIPT_SMSC_ACKN,
} e_sms_receipt_states;
......@@ -105,6 +105,8 @@ struct _ChattyHistory
typedef void (*ChattyCallback) (ChattyHistory *self,
GTask *task);
static int add_file_info (ChattyHistory *self,
ChattyFileInfo *file);
G_DEFINE_TYPE (ChattyHistory, chatty_history, G_TYPE_OBJECT)
......@@ -626,6 +628,7 @@ static int
insert_or_ignore_user (ChattyHistory *self,
ChattyProtocol protocol,
const char *who,
const char *alias,
GTask *task)
{
g_autofree char *phone = NULL;
......@@ -643,11 +646,15 @@ insert_or_ignore_user (ChattyHistory *self,
}
sqlite3_prepare_v2 (self->db,
"INSERT OR IGNORE INTO users(username,type) "
"VALUES(?,?);",
"INSERT OR IGNORE INTO users(username,type,alias) "
"VALUES(?1,?2,?3) "
"ON CONFLICT(username,type) "
"DO UPDATE SET alias=coalesce(?3,alias)",
-1, &stmt, NULL);
history_bind_text (stmt, 1, phone ? phone : who, "binding when adding phone number");
history_bind_int (stmt, 2, history_protocol_to_type_value (protocol), "binding when adding phone number");
if (alias && who && !g_str_equal (who, alias))
history_bind_text (stmt, 3, alias, "binding when adding phone number");
sqlite3_step (stmt);
sqlite3_finalize (stmt);
......@@ -752,7 +759,8 @@ insert_or_ignore_thread (ChattyHistory *self,
{
sqlite3_stmt *stmt;
int user_id, account_id;
int status, id = 0;
int status, file_id, id = 0;
ChattyFileInfo *file;
g_assert (CHATTY_IS_HISTORY (self));
g_assert (G_IS_TASK (task));
......@@ -762,6 +770,7 @@ insert_or_ignore_thread (ChattyHistory *self,
user_id = insert_or_ignore_user (self,
chatty_item_get_protocols (CHATTY_ITEM (chat)),
chatty_chat_get_username (chat),
NULL,
task);
if (!user_id) {
const char *who;
......@@ -784,11 +793,14 @@ insert_or_ignore_thread (ChattyHistory *self,
if (!account_id)
return 0;
file = chatty_item_get_avatar_file (CHATTY_ITEM (chat));
file_id = add_file_info (self, file);
sqlite3_prepare_v2 (self->db,
"INSERT INTO threads(name,alias,account_id,type,visibility,encrypted) "
"VALUES(?1,?2,?3,?4,?5,?6) "
"INSERT INTO threads(name,alias,account_id,type,visibility,encrypted,avatar_id) "
"VALUES(?1,?2,?3,?4,?5,?6,?7) "
"ON CONFLICT(name,account_id,type) "
"DO UPDATE SET alias=?2, visibility=?5, encrypted=?6",
"DO UPDATE SET alias=?2, visibility=?5, encrypted=?6, avatar_id=?7",
-1, &stmt, NULL);
history_bind_text (stmt, 1, chatty_chat_get_chat_name (chat), "binding when adding thread");
history_bind_text (stmt, 2, chatty_item_get_name (CHATTY_ITEM (chat)), "binding when adding thread");
......@@ -799,6 +811,9 @@ insert_or_ignore_thread (ChattyHistory *self,
"binding when adding thread");
history_bind_int (stmt, 6, chatty_chat_get_encryption (chat) == CHATTY_ENCRYPTION_ENABLED,
"binding when adding thread");
if (file_id)
history_bind_int (stmt, 7, file_id, "binding when adding thread");
sqlite3_step (stmt);
sqlite3_finalize (stmt);
......@@ -1844,8 +1859,8 @@ get_messages_before_time (ChattyHistory *self,
skip = FALSE;
status = sqlite3_prepare_v2 (self->db,
/* 0 1 2 3 4 5 */
"SELECT DISTINCT time,direction,body,uid,users.username,body_type,"
/* 0 1 2 3 4 5 */
"SELECT DISTINCT time,direction,body,uid,coalesce(users.alias,users.username),body_type,"
/* 6 7 8 9 10 11 */
"files.name,files.url,files.path,mime_type.name,files.size,files.status,"
"coalesce(video.width,image.width)," /* 12 */
......@@ -1864,6 +1879,7 @@ get_messages_before_time (ChattyHistory *self,
"LEFT JOIN image ON body_type=9 AND files.id=image.file_id "
"LEFT JOIN video ON body_type=10 AND files.id=video.file_id "
"LEFT JOIN audio ON body_type=11 AND files.id=audio.file_id "
"LEFT JOIN files AS p_files ON messages.preview_id=p_files.id "
"LEFT JOIN mime_type AS p_mime_type ON p_files.mime_type_id=p_mime_type.id "
"LEFT JOIN image AS p_image ON p_files.id=p_image.file_id "
......@@ -1942,9 +1958,18 @@ get_messages_before_time (ChattyHistory *self,
who = (const char *)sqlite3_column_text (stmt, 4);
status = sqlite3_column_int (stmt, 24);
message = chatty_message_new (NULL, who, msg, uid, time_stamp, type,
history_direction_from_value (direction),
history_msg_status_from_value (status));
{
g_autoptr(ChattyContact) contact = NULL;
contact = g_object_new (CHATTY_TYPE_CONTACT, NULL);
chatty_contact_set_name (contact, who);
chatty_contact_set_value (contact, who);
message = chatty_message_new (CHATTY_ITEM (contact), msg, uid, time_stamp, type,
history_direction_from_value (direction),
history_msg_status_from_value (status));
}
chatty_message_set_files (message, g_list_append (NULL, file));
chatty_message_set_preview (message, preview);
g_ptr_array_insert (messages, 0, message);
......@@ -2109,7 +2134,7 @@ history_add_message (ChattyHistory *self,
ChattyMessage *message;
ChattyChat *chat;
sqlite3_stmt *stmt;
const char *who, *uid, *msg;
const char *who, *uid, *msg, *alias;
ChattyMsgDirection direction;
ChattyMsgType type;
int thread_id = 0, sender_id = 0, file_id = 0, preview_id = 0;
......@@ -2139,20 +2164,19 @@ history_add_message (ChattyHistory *self,
direction = chatty_message_get_msg_direction (message);
dir = history_direction_to_value (direction);
type = chatty_message_get_msg_type (message);
alias = chatty_message_get_user_alias (message);
/* TODO: check if this is good */
if (!who || !*who) {
if (direction == CHATTY_DIRECTION_OUT)
who = chatty_chat_get_username (chat);
else if (direction == CHATTY_DIRECTION_IN && chatty_chat_is_im (chat))
who = chatty_chat_get_chat_name (chat);
}
if (direction == CHATTY_DIRECTION_OUT)
who = chatty_chat_get_username (chat);
if ((!who || !*who) && direction == CHATTY_DIRECTION_IN && chatty_chat_is_im (chat))
who = chatty_chat_get_chat_name (chat);
thread_id = insert_or_ignore_thread (self, chat, task);
if (!thread_id)
return;
sender_id = insert_or_ignore_user (self, chatty_item_get_protocols (CHATTY_ITEM (chat)), who, task);
sender_id = insert_or_ignore_user (self, chatty_item_get_protocols (CHATTY_ITEM (chat)), who, alias, task);
if (sender_id && direction == CHATTY_DIRECTION_IN) {
sqlite3_prepare_v2 (self->db,
......@@ -2249,10 +2273,13 @@ history_get_chats (ChattyHistory *self,
protocol = PROTOCOL_MATRIX;
sqlite3_prepare_v2 (self->db,
"SELECT threads.id,threads.name,threads.alias,threads.encrypted FROM threads "
"SELECT threads.id,threads.name,threads.alias,threads.encrypted,"
"files.url,files.path "
"FROM threads "
"INNER JOIN accounts ON accounts.id=threads.account_id "
"INNER JOIN users ON users.id=accounts.user_id "
"AND users.username=? AND accounts.protocol=? "
"LEFT JOIN files ON threads.avatar_id=files.id "
"WHERE visibility=" STRING(THREAD_VISIBILITY_VISIBLE),
-1, &stmt, NULL);
history_bind_text (stmt, 1, user_id, "binding when getting threads");
......@@ -2260,6 +2287,7 @@ history_get_chats (ChattyHistory *self,
while (sqlite3_step (stmt) == SQLITE_ROW) {
g_autoptr(GPtrArray) messages = NULL;
ChattyFileInfo *file = NULL;
const char *name, *alias;
ChattyChat *chat;
int thread_id;
......@@ -2272,7 +2300,13 @@ history_get_chats (ChattyHistory *self,
alias = (const char *)sqlite3_column_text (stmt, 2);
encrypted = sqlite3_column_int (stmt, 3);
chat = (gpointer)chatty_ma_chat_new (name, alias);
if (sqlite3_column_text (stmt, 4)) {
file = g_new0 (ChattyFileInfo, 1);
file->url = g_strdup ((const char *)sqlite3_column_text (stmt, 4));
file->path = g_strdup ((const char *)sqlite3_column_text (stmt, 5));
}
chat = (gpointer)chatty_ma_chat_new (name, alias, file);
chatty_chat_set_encryption (CHATTY_CHAT (chat), encrypted);
messages = get_messages_before_time (self, chat, NULL, thread_id, INT_MAX, 1);
chatty_ma_chat_add_messages (CHATTY_MA_CHAT (chat), messages);
......
/*
* Copyright (C) 2018 Purism SPC
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#define G_LOG_DOMAIN "chatty-icons"
#include <glib.h>
#include <gtk/gtk.h>
#include "chatty-icons.h"
GdkPixbuf *
chatty_icon_pixbuf_from_data (const guchar *buf,
gsize count)
{
GdkPixbuf *pixbuf;
g_autoptr(GdkPixbufLoader) loader = NULL;
g_autoptr(GError) error = NULL;
loader = gdk_pixbuf_loader_new ();
if (!gdk_pixbuf_loader_write (loader, buf, count, &error)) {
g_debug ("%s: pixbuf_loder_write failed: %s", __func__, error->message);
return NULL;
}
if (!gdk_pixbuf_loader_close (loader, &error)) {
g_debug ("%s: pixbuf_loder_close failed: %s", __func__, error->message);
return NULL;
}
pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
if (!pixbuf) {
g_debug ("%s: pixbuf creation failed", __func__);
return NULL;
}
return g_object_ref (pixbuf);
}
GdkPixbuf *
chatty_icon_get_buddy_icon (PurpleBlistNode *node)
{
gsize len;
const guchar *data = NULL;
GdkPixbuf *buf = NULL;
PurpleBuddyIcon *icon = NULL;
PurpleStoredImage *custom_img;
if (!node || !PURPLE_BLIST_NODE_IS_CHAT (node))
return NULL;
custom_img = purple_buddy_icons_node_find_custom_icon (node);
if (custom_img) {
data = purple_imgstore_get_data (custom_img);
len = purple_imgstore_get_size (custom_img);
}
purple_imgstore_unref (custom_img);
if (data != NULL) {
buf = chatty_icon_pixbuf_from_data (data, len);
purple_buddy_icon_unref (icon);
return buf;
}
return NULL;
}
/*
* Copyright (C) 2018 Purism SPC
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#ifndef __ICON_H_INCLUDE__
#define __ICON_H_INCLUDE__
#include "purple.h"
GdkPixbuf *chatty_icon_pixbuf_from_data (const guchar *buf, gsize count);
GdkPixbuf *chatty_icon_get_buddy_icon (PurpleBlistNode *node);
#endif