Commit 4245244d authored by Andrea Schaefer's avatar Andrea Schaefer

Initial commit

parents
[default]
name=Default
runtime=host
config-opts=
run-opts=
prefix=/home/andrea/.cache/gnome-builder/install/purism-chatty/host
app-id=
postbuild=
prebuild=
default=true
[default.environment]
*.o
*.log
*~
build
arm
arm-build
This diff is collapsed.
# Chatty
XMPP and SMS messaging via libpurple and Modemmanager
## Build and install
### Install dependencies
``` bash
sudo apt install git cmake libpurple-dev libmxml-dev libxml2-dev libsqlite3-dev libgcrypt20-dev
```
### Build and install Lurch
``` bash
git clone https://github.com/gkdr/lurch/
cd lurch
git submodule update --init --recursive
make install-home
```
### Build purism-chatty
``` bash
meson build
ninja -C build
```
#!/usr/bin/env python3
from os import environ, path
from subprocess import call
prefix = environ.get('MESON_INSTALL_PREFIX', '/usr/local')
datadir = path.join(prefix, 'share')
destdir = environ.get('DESTDIR', '')
# Package managers set this so we don't need to run
if not destdir:
print('Updating icon cache...')
call(['gtk-update-icon-cache', '-qtf', path.join(datadir, 'icons', 'hicolor')])
print('Updating desktop database...')
call(['update-desktop-database', '-q', path.join(datadir, 'applications')])
print('Compiling GSettings schemas...')
call(['glib-compile-schemas', path.join(datadir, 'glib-2.0', 'schemas')])
desktop_file = i18n.merge_file(
input: 'sm.puri.Chatty.desktop.in',
output: 'sm.puri.Chatty.desktop',
type: 'desktop',
po_dir: '../po',
install: true,
install_dir: join_paths(get_option('datadir'), 'applications')
)
desktop_utils = find_program('desktop-file-validate', required: false)
if desktop_utils.found()
test('Validate desktop file', desktop_utils,
args: [desktop_file]
)
endif
appstream_file = i18n.merge_file(
input: 'sm.puri.Chatty.appdata.xml.in',
output: 'sm.puri.Chatty.appdata.xml',
po_dir: '../po',
install: true,
install_dir: join_paths(get_option('datadir'), 'appdata')
)
appstream_util = find_program('appstream-util', required: false)
if appstream_util.found()
test('Validate appstream file', appstream_util,
args: ['validate', appstream_file]
)
endif
install_data('sm.puri.Chatty.gschema.xml',
install_dir: join_paths(get_option('datadir'), 'glib-2.0/schemas')
)
compile_schemas = find_program('glib-compile-schemas', required: false)
if compile_schemas.found()
test('Validate schema file', compile_schemas,
args: ['--strict', '--dry-run', meson.current_source_dir()]
)
endif
<?xml version="1.0" encoding="UTF-8"?>
<component type="desktop">
<id>sm.puri.Chatty.desktop</id>
<metadata_license>CC0-1.0</metadata_license>
<project_license>GPL-3.0-or-later</project_license>
<description>
</description>
</component>
[Desktop Entry]
Name=purism-chatty
Exec=purism-chatty
Terminal=false
Type=Application
Categories=GTK;
StartupNotify=true
<?xml version="1.0" encoding="UTF-8"?>
<schemalist gettext-domain="purism-chatty">
<schema id="sm.puri.Chatty" path="/sm/puri/Chatty/">
</schema>
</schemalist>
project('chatty', 'c', version: '0.1.0',
meson_version: '>= 0.40.0',
)
i18n = import('i18n')
config_h = configuration_data()
config_h.set_quoted('GETTEXT_PACKAGE', 'purism-chatty')
config_h.set_quoted('LOCALEDIR', join_paths(get_option('prefix'), get_option('localedir')))
configure_file(
output: 'chatty-config.h',
configuration: config_h,
)
add_project_arguments([
'-I' + meson.build_root(),
], language: 'c')
subdir('data')
subdir('src')
subdir('po')
meson.add_install_script('build-aux/meson/postinstall.py')
data/sm.puri.Chatty.desktop.in
data/sm.puri.Chatty.appdata.xml.in
data/sm.puri.Chatty.gschema.xml
src/chatty-message-view-popover.ui
src/chatty-blist-view-popover.ui
src/chatty-new-chat-view-popover.ui
src/main.c
src/purism-chatty-window.c
i18n.gettext('purism-chatty', preset: 'glib')
{
"app-id" : "org.gnome.Purism-Chatty",
"runtime" : "org.gnome.Platform",
"runtime-version" : "master",
"sdk" : "org.gnome.Sdk",
"command" : "purism-chatty",
"finish-args" : [
"--share=network",
"--share=ipc",
"--socket=x11",
"--socket=wayland",
"--filesystem=xdg-run/dconf",
"--filesystem=~/.config/dconf:ro",
"--talk-name=ca.desrt.dconf",
"--env=DCONF_USER_CONFIG_DIR=.config/dconf"
],
"build-options" : {
"cflags" : "-O2 -g",
"cxxflags" : "-O2 -g",
"env" : {
"V" : "1"
}
},
"cleanup" : [
"/include",
"/lib/pkgconfig",
"/man",
"/share/doc",
"/share/gtk-doc",
"/share/man",
"/share/pkgconfig",
"*.la",
"*.a"
],
"modules" : [
{
"name" : "libpurple",
"config-opts" : [
"--disable-gtkui",
"--disable-consoleui",
"--disable-vv",
"--disable-idn",
"--disable-avahi",
"--disable-meanwhile",
"--disable-tcl",
"--disable-nm",
"--disable-perl"
],
"sources" : [
{
"type" : "archive",
"url" : "http://downloads.sourceforge.net/pidgin/pidgin-2.13.0.tar.bz2",
"sha256" : "2747150c6f711146bddd333c496870bfd55058bab22ffb7e4eb784018ec46d8f"
}
]
},
"modules" : [
{
"name" : "purism-chatty",
"buildsystem" : "meson",
"config-opts" : [
"--libdir=lib"
],
"builddir" : true,
"sources" : [
{
"type" : "git",
"url" : "https://source.puri.sm/Librem5/chatty.git"
}
]
}
]
}
/*
* Copyright (C) 2018 Purism SPC
*
* SPDX-License-Identifier: LGPL-2.1+
*/
#include <glib.h>
#include <glib-object.h>
#include <gtk/gtk.h>
#include <stdlib.h>
#include <string.h>
#include "purple.h"
#include "chatty-window.h"
#include "chatty-purple-init.h"
typedef struct
{
PurpleAccount *account;
char *username;
char *alias;
} ChattyAccountAddUserData;
static void
chatty_account_free_user_data (ChattyAccountAddUserData *data)
{
g_free (data->username);
g_free (data->alias);
g_free (data);
}
static void
cb_account_added (PurpleAccount *account,
gpointer user_data)
{
// TODO add account to liststore
}
static void
cb_account_removed (PurpleAccount *account,
gpointer user_data)
{
// TODO remove account from liststore
}
static void
cb_account_enabled_disabled (PurpleAccount *account,
gpointer user_data)
{
// TODO update account in liststore
}
static void
cb_dialog_response (GtkDialog *dialog,
gint response_id,
gpointer user_data)
{
ChattyAccountAddUserData *data = user_data;
if (response_id == GTK_RESPONSE_OK) {
PurpleConnection *gc = purple_account_get_connection (data->account);
if (g_list_find(purple_connections_get_all(), gc)) {
purple_blist_request_add_buddy (data->account,
data->username,
NULL,
data->alias);
}
chatty_account_free_user_data (data);
} else {
gtk_widget_destroy (GTK_WIDGET (dialog));
}
}
static char *
chatty_account_compile_info (PurpleAccount *account,
PurpleConnection *gc,
const char *remote_user,
const char *id,
const char *alias,
const char *msg)
{
if (msg != NULL && *msg == '\0') {
msg = NULL;
}
return g_strdup_printf("%s%s%s%s has made %s his or her buddy%s%s",
remote_user,
(alias != NULL ? " (" : ""),
(alias != NULL ? alias : ""),
(alias != NULL ? ")" : ""),
(id != NULL
? id
: (purple_connection_get_display_name (gc) != NULL
? purple_connection_get_display_name (gc)
: purple_account_get_username (account))),
(msg != NULL ? ": " : "."),
(msg != NULL ? msg : ""));
}
static void
chatty_account_notify_added (PurpleAccount *account,
const char *remote_user,
const char *id,
const char *alias,
const char *msg)
{
char *buffer;
GtkWidget *dialog;
PurpleConnection *gc;
chatty_data_t *chatty = chatty_get_data();
gc = purple_account_get_connection(account);
buffer = chatty_account_compile_info (account,
gc,
remote_user,
id,
alias,
msg);
dialog = gtk_dialog_new_with_buttons ("Add buddy to your list?",
GTK_WINDOW(chatty->main_window),
GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_INFO,
GTK_BUTTONS_OK,
buffer,
NULL);
gtk_widget_show_all (GTK_WIDGET(dialog));
g_free (buffer);
}
static void *
chatty_account_request_authorization (PurpleAccount *account,
const char *remote_user,
const char *id,
const char *alias,
const char *message,
gboolean on_list,
PurpleAccountRequestAuthorizationCb auth_cb,
PurpleAccountRequestAuthorizationCb deny_cb,
void *user_data)
{
printf ("chatty_account_request_authorization\n");
return NULL;
}
static void
chatty_account_request_close(void *ui_handle)
{
gtk_widget_destroy( GTK_WIDGET(ui_handle));
}
static void
chatty_account_request_add (PurpleAccount *account,
const char *remote_user,
const char *id,
const char *alias,
const char *msg)
{
char *buffer;
GtkWidget *dialog, *label, *content_area;
PurpleConnection *gc;
ChattyAccountAddUserData *data;
printf ("chatty_account_request_add\n");
chatty_data_t *chatty = chatty_get_data();
gc = purple_account_get_connection (account);
data = g_new0 (ChattyAccountAddUserData, 1);
data->account = account;
data->username = g_strdup (remote_user);
data->alias = g_strdup (alias);
buffer = chatty_account_compile_info (account,
gc,
remote_user,
id,
alias,
msg);
dialog = gtk_dialog_new_with_buttons ("Buddy request",
GTK_WINDOW(chatty->main_window),
GTK_DIALOG_DESTROY_WITH_PARENT,
"Add buddy to your list?",
GTK_BUTTONS_YES_NO,
NULL);
content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
label = gtk_label_new (buffer);
g_signal_connect_swapped (dialog,
"response",
G_CALLBACK (cb_dialog_response),
data);
gtk_container_add (GTK_CONTAINER (content_area), label);
gtk_widget_show_all (dialog);
g_free (buffer);
}
void
chatty_account_connect (const char *account_name,
const char *account_pwd)
{
chatty_data_t *chatty = chatty_get_data();
gtk_label_set_text (chatty->label_status, "connecting...");
chatty->account = purple_account_new (account_name, "prpl-jabber");
purple_account_set_password (chatty->account, account_pwd);
purple_accounts_add (chatty->account);
purple_account_set_enabled (chatty->account, UI_ID, TRUE);
}
// TODO even though the struct is properly registered
// to the libpurple core, it doesn't call
// the assigned functions
static PurpleAccountUiOps ui_ops =
{
chatty_account_notify_added,
NULL,
chatty_account_request_add,
chatty_account_request_authorization,
chatty_account_request_close,
NULL,
NULL,
NULL,
NULL
};
PurpleAccountUiOps *
chatty_accounts_get_ui_ops (void)
{
return &ui_ops;
}
void *
chatty_account_get_handle (void) {
static int handle;
return &handle;
}
void
chatty_account_init (void)
{
purple_signal_register (chatty_account_get_handle(), "account-modified",
purple_marshal_VOID__POINTER, NULL, 1,
purple_value_new (PURPLE_TYPE_SUBTYPE,
PURPLE_SUBTYPE_ACCOUNT));
purple_prefs_add_none (CHATTY_PREFS_ROOT "/accounts");
purple_signal_connect (purple_accounts_get_handle(),
"account-added",
chatty_account_get_handle(),
PURPLE_CALLBACK (cb_account_added),
NULL);
purple_signal_connect (purple_accounts_get_handle(),
"account-removed",
chatty_account_get_handle(),
PURPLE_CALLBACK (cb_account_removed),
NULL);
purple_signal_connect (purple_accounts_get_handle(),
"account-disabled",
chatty_account_get_handle(),
PURPLE_CALLBACK(cb_account_enabled_disabled),
GINT_TO_POINTER(FALSE));
purple_signal_connect (purple_accounts_get_handle(),
"account-enabled",
chatty_account_get_handle(),
PURPLE_CALLBACK(cb_account_enabled_disabled),
GINT_TO_POINTER(TRUE));
}
void
chatty_account_uninit (void)
{
purple_signals_disconnect_by_handle (chatty_account_get_handle());
purple_signals_unregister_by_instance (chatty_account_get_handle());
}
/*
* Copyright (C) 2018 Purism SPC
*
* SPDX-License-Identifier: LGPL-2.1+
*/
#ifndef __ACCOUNT_H_INCLUDE__
#define __ACCOUNT_H_INCLUDE__
PurpleAccountUiOps *chatty_accounts_get_ui_ops(void);
void chatty_account_init (void);
void chatty_account_uninit (void);
void chatty_account_connect (const char *account_name, const char *account_pwd);
#endif
This diff is collapsed.
/*
* Copyright (C) 2018 Purism SPC
*
* SPDX-License-Identifier: LGPL-2.1+
*/
#ifndef __BUDDY_LIST_H_INCLUDE__
#define __BUDDY_LIST_H_INCLUDE__
#include "purple.h"
typedef struct {
GtkBox *box;
GtkTreeView *treeview;
GtkListStore *treemodel;
GtkTreeViewColumn *text_column;
GtkScrolledWindow *scroll;
GdkPixbuf *empty_avatar;
PurpleBlistNode *selected_node;
guint *messaging_mode;
guint refresh_timer;
gpointer priv;
} ChattyBuddyList;
typedef enum {
CHATTY_BLIST_NODE_HAS_PENDING_MESSAGE = 1 << 0,
CHATTY_BLIST_CHAT_HAS_PENDING_MESSAGE_WITH_NICK = 1 << 1,
} ChattyBlistNodeFlags;
typedef struct _chatty_blist_node {
GtkTreeRowReference *row;
GtkTreeIter iter;
gboolean contact_expanded;
gboolean recent_signonoff;
gint recent_signonoff_timer;
struct {
PurpleConversation *conv;
time_t last_message;
ChattyBlistNodeFlags flags;
} conv;
} ChattyBlistNode;
enum
{
COLUMN_NODE,
COLUMN_AVATAR,
COLUMN_NAME,
COLUMN_TIME,
NUM_COLUMNS,
};
enum {
CHATTY_MSG_MODE_XMPP,
CHATTY_MSG_MODE_OMEMO,
CHATTY_MSG_MODE_SMS
} e_messaging_modes;
enum {
CHATTY_STATUS_ICON_LARGE,
CHATTY_STATUS_ICON_SMALL
} e_icon_size;
#define CHATTY_BLIST(list) ((ChattyBuddyList *)purple_blist_get_ui_data())
#define CHATTY_IS_CHATTY_BLIST(list) \
(purple_blist_get_ui_ops() == chatty_blist_get_ui_ops())
PurpleBlistUiOps *chatty_blist_get_ui_ops (void);
void chatty_blist_init (void);
void chatty_blist_uninit (void);
void chatty_blist_add_buddy (void);
#endif
/*
* Copyright (C) 2018 Purism SPC
*
* SPDX-License-Identifier: LGPL-2.1+
*/
#include "purple.h"
#include "chatty-window.h"
#include "chatty-connection.h"
static GHashTable *auto_reconns = NULL;
static void
cb_account_removed (PurpleAccount *account,
gpointer user_data)
{
g_hash_table_remove (auto_reconns, account);
}
static void
chatty_connection_connect_progress (PurpleConnection *gc,
const char *text,
size_t step,
size_t step_count)
{
// TODO initialize stuff, wait animation...
}
static void
chatty_connection_connected (PurpleConnection *gc)
{
PurpleAccount *account;
account = purple_connection_get_account (gc);
g_hash_table_remove(auto_reconns, account);
}
static void
chatty_connection_disconnected (PurpleConnection *gc)
{
}
static void
chatty_connection_network_connected (void)
{
}
static void
chatty_connection_network_disconnected (void)
{
chatty_data_t *chatty = chatty_get_data();
gtk_label_set_text (chatty->label_status, "Disconnected");
}
static void
chatty_connection_report_disconnect_reason (PurpleConnection *gc,
PurpleConnectionError reason,
const char *text)
{
gchar *label_text;
chatty_data_t *chatty = chatty_get_data();
PurpleAccount *account = purple_connection_get_account (gc);
label_text = g_strdup_printf ("Disconnected: \"%s\" (%s)\n >Error: %d\n >Reason: %s\n",
purple_account_get_username(account),
purple_account_get_protocol_id(account),
reason, text);