Vendor in a purple-sys wrapper

This code comes from https://github.com/Flared/purple-icq/tree/master/src/purple

It is GPL-3 licensed
This commit is contained in:
2021-04-10 14:25:19 +01:00
parent 6237b9421d
commit dedd12c66a
21 changed files with 2788 additions and 0 deletions

View File

@@ -0,0 +1,297 @@
use super::super::{prpl, Account, Connection, Plugin, PurpleMessageFlags, StrHashTable};
use super::traits;
use crate::purple::ffi::{IntoGlibPtr, ToGlibContainerFromIterator};
use glib::translate::{ToGlibContainerFromSlice, ToGlibPtr};
use log::{debug, error};
use std::ffi::CStr;
use std::os::raw::{c_char, c_void};
use std::panic::catch_unwind;
use std::ptr::NonNull;
pub extern "C" fn actions(
_: *mut purple_sys::PurplePlugin,
_: *mut c_void,
) -> *mut glib_sys::GList {
std::ptr::null_mut()
}
pub extern "C" fn load<P: traits::LoadHandler>(plugin_ptr: *mut purple_sys::PurplePlugin) -> i32 {
match catch_unwind(|| {
debug!("load");
let mut plugin = unsafe { Plugin::from_raw(plugin_ptr) };
let prpl_plugin = unsafe { plugin.extra::<P>() };
prpl_plugin.load(&plugin) as i32
}) {
Ok(r) => r,
Err(_) => 0,
}
}
pub extern "C" fn login<P: traits::LoginHandler>(account_ptr: *mut purple_sys::PurpleAccount) {
if let Err(error) = catch_unwind(|| {
debug!("login");
let mut account = unsafe { Account::from_raw(account_ptr) };
let mut plugin = account
.get_connection()
.expect("No connection found for account")
.get_protocol_plugin()
.expect("No plugin found for connection");
let prpl_plugin = unsafe { plugin.extra::<P>() };
prpl_plugin.login(&mut account);
}) {
error!("Failure in login: {:?}", error)
};
}
pub extern "C" fn get_cb_alias<P: traits::GetChatBuddyAlias>(
connection_ptr: *mut purple_sys::PurpleConnection,
id: i32,
c_who: *const c_char,
) -> *mut c_char {
match catch_unwind(|| {
debug!("get_cb_alias");
let mut connection = unsafe { Connection::from_raw(connection_ptr).unwrap() };
let mut plugin = connection
.get_protocol_plugin()
.expect("No plugin found for connection");
let prpl_plugin = unsafe { plugin.extra::<P>() };
let who = unsafe { CStr::from_ptr(c_who).to_str().unwrap() };
prpl_plugin
.get_cb_alias(&mut connection, id, who)
.as_ref()
.map(ToGlibPtr::to_glib_full)
.unwrap_or_else(std::ptr::null_mut)
}) {
Ok(r) => r,
Err(error) => {
error!("Failure in get_cb_alias: {:?}", error);
std::ptr::null_mut()
}
}
}
pub extern "C" fn chat_info<P: traits::ChatInfoHandler>(
connection_ptr: *mut purple_sys::PurpleConnection,
) -> *mut glib_sys::GList {
match catch_unwind(|| {
debug!("chat_info");
let mut connection = unsafe { Connection::from_raw(connection_ptr).unwrap() };
let mut plugin = connection
.get_protocol_plugin()
.expect("No plugin found for connection");
let prpl_plugin = unsafe { plugin.extra::<P>() };
ToGlibContainerFromSlice::to_glib_full_from_slice(
&prpl_plugin
.chat_info(&mut connection)
.into_iter()
.map(|x| x.into())
.collect::<Vec<prpl::ProtoChatEntry>>(),
)
}) {
Ok(r) => r,
Err(error) => {
error!("Failure in chat_info: {:?}", error);
std::ptr::null_mut()
}
}
}
pub extern "C" fn close<P: traits::CloseHandler>(
connection_ptr: *mut purple_sys::PurpleConnection,
) {
if let Err(error) = catch_unwind(|| {
debug!("close");
let mut connection = unsafe { Connection::from_raw(connection_ptr).unwrap() };
let mut plugin = connection
.get_protocol_plugin()
.expect("No plugin found for connection");
let prpl_plugin = unsafe { plugin.extra::<P>() };
prpl_plugin.close(&mut connection)
}) {
error!("Failure in close: {:?}", error)
}
}
pub extern "C" fn list_icon<P: traits::ListIconHandler>(
account_ptr: *mut purple_sys::PurpleAccount,
_: *mut purple_sys::PurpleBuddy,
) -> *const c_char {
match catch_unwind(|| {
debug!("list_icon");
let mut account = unsafe { Account::from_raw(account_ptr) };
P::list_icon(&mut account).as_ptr()
}) {
Ok(r) => r,
Err(error) => {
error!("Failure in list_icon: {:?}", error);
std::ptr::null_mut()
}
}
}
pub extern "C" fn status_types<P: traits::StatusTypeHandler>(
account_ptr: *mut purple_sys::PurpleAccount,
) -> *mut glib_sys::GList {
match catch_unwind(|| {
debug!("status_types");
let mut account = unsafe { Account::from_raw(account_ptr) };
ToGlibContainerFromIterator::into_glib_full_from_iter(P::status_types(&mut account))
}) {
Ok(r) => r,
Err(error) => {
error!("Failure in status_types: {:?}", error);
std::ptr::null_mut()
}
}
}
pub extern "C" fn join_chat<P: traits::JoinChatHandler>(
connection_ptr: *mut purple_sys::PurpleConnection,
components: *mut glib_sys::GHashTable,
) {
if let Err(error) = catch_unwind(|| {
debug!("join_chat");
let mut connection = unsafe { Connection::from_raw(connection_ptr).unwrap() };
let mut plugin = connection
.get_protocol_plugin()
.expect("No plugin found for connection");
let prpl_plugin = unsafe { plugin.extra::<P>() };
let mut data = unsafe { StrHashTable::from_ptr(components) };
prpl_plugin.join_chat(&mut connection, data.as_mut())
}) {
error!("Failure in join_chat: {:?}", error)
}
}
pub extern "C" fn chat_leave<P: traits::ChatLeaveHandler>(
connection_ptr: *mut purple_sys::PurpleConnection,
id: i32,
) {
if let Err(error) = catch_unwind(|| {
debug!("chat_leave");
let mut connection = unsafe { Connection::from_raw(connection_ptr).unwrap() };
let mut plugin = connection
.get_protocol_plugin()
.expect("No plugin found for connection");
let prpl_plugin = unsafe { plugin.extra::<P>() };
prpl_plugin.chat_leave(&mut connection, id)
}) {
error!("Failure in chat_leave: {:?}", error)
}
}
pub extern "C" fn convo_closed<P: traits::ConvoClosedHandler>(
connection_ptr: *mut purple_sys::PurpleConnection,
c_who: *const c_char,
) {
if let Err(error) = catch_unwind(|| {
debug!("convo_closed");
let mut connection = unsafe { Connection::from_raw(connection_ptr).unwrap() };
let mut plugin = connection
.get_protocol_plugin()
.expect("No plugin found for connection");
let prpl_plugin = unsafe { plugin.extra::<P>() };
let who = NonNull::new(c_who as *mut _)
.map(|p| unsafe { CStr::from_ptr(p.as_ptr()).to_str().unwrap() });
prpl_plugin.convo_closed(&mut connection, who)
}) {
error!("Failure in convo_closed: {:?}", error)
}
}
pub extern "C" fn get_chat_name<P: traits::GetChatNameHandler>(
data: *mut glib_sys::GHashTable,
) -> *mut c_char {
match catch_unwind(|| {
debug!("get_chat_name");
let mut data = unsafe { StrHashTable::from_ptr(data) };
let name = P::get_chat_name(data.as_mut());
name.to_glib_full()
}) {
Ok(r) => r,
Err(error) => {
error!("Failure in get_chat_name: {:?}", error);
std::ptr::null_mut()
}
}
}
pub extern "C" fn chat_info_defaults<P: traits::ChatInfoDefaultsHandler>(
connection_ptr: *mut purple_sys::PurpleConnection,
c_chat_name: *const c_char,
) -> *mut glib_sys::GHashTable {
match catch_unwind(|| {
debug!("chat_info_defaults_handler");
let mut connection = unsafe { Connection::from_raw(connection_ptr).unwrap() };
let mut plugin = connection
.get_protocol_plugin()
.expect("No plugin found for connection");
let prpl_plugin = unsafe { plugin.extra::<P>() };
let chat_name = NonNull::new(c_chat_name as *mut _)
.map(|p| unsafe { CStr::from_ptr(p.as_ptr()).to_string_lossy() });
prpl_plugin
.chat_info_defaults(&mut connection, chat_name.as_deref())
.into_glib_full()
}) {
Ok(r) => r,
Err(error) => {
error!("Failure in chat_info_defaults: {:?}", error);
std::ptr::null_mut()
}
}
}
pub extern "C" fn roomlist_get_list_handler(
_: *mut purple_sys::PurpleConnection,
) -> *mut purple_sys::PurpleRoomlist {
println!("roomlist_get_list_handler");
std::ptr::null_mut()
}
pub extern "C" fn chat_send<P: traits::ChatSendHandler>(
connection_ptr: *mut purple_sys::PurpleConnection,
id: i32,
c_message: *const c_char,
flags: PurpleMessageFlags,
) -> i32 {
match catch_unwind(|| {
debug!("convo_closed");
let mut connection = unsafe { Connection::from_raw(connection_ptr).unwrap() };
let mut plugin = connection
.get_protocol_plugin()
.expect("No plugin found for connection");
let prpl_plugin = unsafe { plugin.extra::<P>() };
let message = unsafe { CStr::from_ptr(c_message).to_str().unwrap() };
prpl_plugin.chat_send(&mut connection, id, message, flags)
}) {
Ok(r) => r,
Err(error) => {
error!("Failure in convo_closed: {:?}", error);
-1
}
}
}
pub extern "C" fn send_im<P: traits::SendIMHandler>(
connection_ptr: *mut purple_sys::PurpleConnection,
c_who: *const c_char,
c_message: *const c_char,
flags: PurpleMessageFlags,
) -> i32 {
match catch_unwind(|| {
debug!("convo_closed");
let mut connection = unsafe { Connection::from_raw(connection_ptr).unwrap() };
let mut plugin = connection
.get_protocol_plugin()
.expect("No plugin found for connection");
let prpl_plugin = unsafe { plugin.extra::<P>() };
let who = unsafe { CStr::from_ptr(c_who).to_str().unwrap() };
let message = unsafe { CStr::from_ptr(c_message).to_str().unwrap() };
prpl_plugin.send_im(&mut connection, who, message, flags)
}) {
Ok(r) => r,
Err(error) => {
error!("Failure in convo_closed: {:?}", error);
-1
}
}
}

View File

@@ -0,0 +1,2 @@
pub mod entrypoints;
pub mod traits;

View File

@@ -0,0 +1,116 @@
use super::super::{
prpl, Account, Connection, Conversation, Plugin, PurpleMessageFlags, StatusType, StrHashTable,
};
use std::ffi::CStr;
pub trait LoadHandler {
fn load(&mut self, plugin: &Plugin) -> bool;
}
pub trait LoginHandler {
fn login(&mut self, account: &mut Account);
}
pub trait CloseHandler {
fn close(&mut self, connection: &mut Connection);
}
pub trait StatusTypeHandler {
fn status_types(account: &mut Account) -> Vec<StatusType>;
}
pub trait ListIconHandler {
fn list_icon(account: &mut Account) -> &'static CStr;
}
pub trait ChatInfoHandler {
fn chat_info(&mut self, connection: &mut Connection) -> Vec<prpl::ChatEntry>;
}
pub trait ChatInfoDefaultsHandler {
fn chat_info_defaults(
&mut self,
connection: &mut Connection,
chat_name: Option<&str>,
) -> StrHashTable;
}
pub trait JoinChatHandler {
fn join_chat(&mut self, connection: &mut Connection, data: Option<&mut StrHashTable>);
}
pub trait ChatLeaveHandler {
fn chat_leave(&mut self, connection: &mut Connection, id: i32);
}
pub trait ConvoClosedHandler {
fn convo_closed(&mut self, connection: &mut Connection, who: Option<&str>);
}
pub trait GetChatBuddyAlias {
fn get_cb_alias(&mut self, connection: &mut Connection, id: i32, who: &str) -> Option<String>;
}
pub trait GetChatNameHandler {
fn get_chat_name(data: Option<&mut StrHashTable>) -> Option<String>;
}
pub trait SendIMHandler {
fn send_im(
&mut self,
connection: &mut Connection,
who: &str,
message: &str,
flags: PurpleMessageFlags,
) -> i32;
}
pub trait ChatSendHandler {
fn chat_send(
&mut self,
connection: &mut Connection,
id: i32,
message: &str,
flags: PurpleMessageFlags,
) -> i32;
}
pub trait InputHandler {
fn input(&mut self, fd: i32, cond: crate::purple::PurpleInputCondition);
fn enable_input(&mut self, fd: i32, cond: crate::purple::PurpleInputCondition) -> u32
where
Self: 'static,
{
let self_ptr: *mut Self = self;
crate::purple::input_add(fd, cond, move |fd, cond| {
let this = unsafe { &mut *self_ptr };
this.input(fd, cond);
})
}
fn disable_input(&self, input_handle: u32) -> bool {
unsafe { purple_sys::purple_input_remove(input_handle) != 0 }
}
}
pub trait CommandHandler {
fn command(
&mut self,
conversation: &mut Conversation,
command: &str,
args: &[&str],
) -> purple_sys::PurpleCmdRet;
fn enable_command(&mut self, cmd: &str, args: &str, help_text: &str) -> purple_sys::PurpleCmdId
where
Self: 'static,
{
let self_ptr: *mut Self = self;
crate::purple::register_cmd(cmd, args, help_text, move |conversation, cmd, args| {
let this = unsafe { &mut *self_ptr };
this.command(conversation, cmd, args)
})
}
fn disable_command(&self, command_id: purple_sys::PurpleCmdId) {
unsafe { purple_sys::purple_cmd_unregister(command_id) }
}
}