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:
297
src/purple/handlers/entrypoints.rs
Normal file
297
src/purple/handlers/entrypoints.rs
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
2
src/purple/handlers/mod.rs
Normal file
2
src/purple/handlers/mod.rs
Normal file
@@ -0,0 +1,2 @@
|
||||
pub mod entrypoints;
|
||||
pub mod traits;
|
116
src/purple/handlers/traits.rs
Normal file
116
src/purple/handlers/traits.rs
Normal 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) }
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user