// This file is part of Hexchat Plugin API Bindings for Rust
// Copyright (C) 2022 Soni L.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
// Based on hexchat's plugin.c
//
/* X-Chat
* Copyright (C) 2002 Peter Zelezny.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
//! Internal mock test framework.
//!
//! This API is not stable. Do not rely on this API to be stable.
use std::cell::Cell;
use std::cell::RefCell;
use std::ffi::CStr;
use std::ffi::CString;
use std::marker::PhantomData;
use std::marker::PhantomPinned;
use std::pin::Pin;
use std::ptr;
use libc::c_char;
#[repr(C)]
struct MockPlugin {
// NOTE: MUST be first thing in the struct.
methods: crate::internals::Ph,
filename: *const c_char,
plugin_name: *const c_char,
plugin_desc: *const c_char,
plugin_vers: *const c_char,
free_strings: bool,
env: *const PluginEnvironment,
_pin: PhantomPinned,
}
enum MockCallback {
HookCommand {
help: Option<Box<str>>,
f: unsafe extern "C" fn(word: *const *const libc::c_char, word_eol: *const *const libc::c_char, user_data: *mut libc::c_void) -> libc::c_int,
},
HookServer {
f: unsafe extern "C" fn(word: *const *const libc::c_char, word_eol: *const *const libc::c_char, user_data: *mut libc::c_void) -> libc::c_int,
},
HookServerAttrs {
f: unsafe extern "C" fn(word: *const *const libc::c_char, word_eol: *const *const libc::c_char, attrs: *const crate::internals::HexchatEventAttrs, user_data: *mut libc::c_void) -> libc::c_int,
},
HookPrint {
f: unsafe extern "C" fn(word: *const *const libc::c_char, user_data: *mut libc::c_void) -> libc::c_int,
},
HookPrintAttrs {
f: unsafe extern "C" fn(word: *const *const libc::c_char, attrs: *const crate::internals::HexchatEventAttrs, user_data: *mut libc::c_void) -> libc::c_int
},
HookTimer {
tag: libc::c_int,
f: unsafe extern "C" fn(user_data: *mut libc::c_void) -> libc::c_int,
},
HookFd {
tag: libc::c_int,
f: unsafe extern "C" fn(fd: libc::c_int, flags: libc::c_int, user_data: *mut libc::c_void) -> libc::c_int
},
HookDeleted,
}
// This MockHook is deliberately incompatible with hexchat's own hook struct.
struct MockHook<'hook, 'env> {
pl: &MockPlugin<'env>,
cb: RefCell<MockCallback>,
name: Option<Box<str>>,
pri_or_fd: libc::c_int,
userdata: *mut libc::c_void,
}
pub struct PluginEnvironment<'env> {
plugins: Option<Vec<Pin<Box<MockPluginOpaque<'env>>>>>,
hooks: Option<Vec<Pin<Box<MockHookOpaque<'env>>>>>,
depth: usize,
}
unsafe extern "C" fn hexchat_hook_command(
ph: *mut crate::internals::HexchatPlugin,
name: *const libc::c_char,
pri: libc::c_int,
/* CALLBACK */
callback: unsafe extern "C" fn(word: *const *const libc::c_char, word_eol: *const *const libc::c_char, user_data: *mut libc::c_void) -> libc::c_int,
help_text: *const libc::c_char,
userdata: *mut libc::c_void
) -> *const crate::internals::HexchatHook {
let ph = ph as *mut MockPlugin;
todo!();
}
unsafe extern "C" fn hexchat_hook_server(ph: *mut crate::internals::HexchatPlugin,
name: *const libc::c_char,
pri: libc::c_int,
/* CALLBACK */
callback: unsafe extern "C" fn(word: *const *const libc::c_char, word_eol: *const *const libc::c_char, user_data: *mut libc::c_void) -> libc::c_int,
userdata: *mut libc::c_void) -> *const crate::internals::HexchatHook {
todo!();
}
unsafe extern "C" fn hexchat_hook_print(ph: *mut crate::internals::HexchatPlugin,
name: *const libc::c_char,
pri: libc::c_int,
/* CALLBACK */
callback: unsafe extern "C" fn(word: *const *const libc::c_char, user_data: *mut libc::c_void) -> libc::c_int,
userdata: *mut libc::c_void) -> *const crate::internals::HexchatHook {
todo!();
}
unsafe extern "C" fn hexchat_hook_timer(ph: *mut crate::internals::HexchatPlugin,
timeout: libc::c_int,
/* CALLBACK */
callback: unsafe extern "C" fn(user_data: *mut libc::c_void) -> libc::c_int,
userdata: *mut libc::c_void) -> *const crate::internals::HexchatHook {
todo!();
}
unsafe extern "C" fn hexchat_hook_fd(ph: *mut crate::internals::HexchatPlugin,
fd: libc::c_int,
flags: libc::c_int,
/* CALLBACK */
callback: unsafe extern "C" fn(fd: libc::c_int, flags: libc::c_int, user_data: *mut libc::c_void) -> libc::c_int,
userdata: *mut libc::c_void) -> *const crate::internals::HexchatHook {
todo!();
}
unsafe extern "C" fn hexchat_unhook(ph: *mut crate::internals::HexchatPlugin,
hook: *const crate::internals::HexchatHook) -> *const libc::c_void {
todo!();
}
unsafe extern "C" fn hexchat_print(ph: *mut crate::internals::HexchatPlugin,
text: *const libc::c_char) {
todo!();
}
pub unsafe extern "C" fn hexchat_printf(ph: *mut crate::internals::HexchatPlugin,
format: *const libc::c_char, ...) {
unimplemented!();
}
unsafe extern "C" fn hexchat_command(ph: *mut crate::internals::HexchatPlugin,
command: *const libc::c_char) {
todo!();
}
unsafe extern "C" fn hexchat_commandf(ph: *mut crate::internals::HexchatPlugin,
format: *const libc::c_char, ...) {
unimplemented!();
}
unsafe extern "C" fn hexchat_nickcmp(ph: *mut crate::internals::HexchatPlugin,
s1: *const libc::c_char,
s2: *const libc::c_char) -> libc::c_int {
todo!();
}
unsafe extern "C" fn hexchat_set_context(ph: *mut crate::internals::HexchatPlugin,
ctx: *const crate::internals::HexchatContext) -> libc::c_int {
todo!();
}
unsafe extern "C" fn hexchat_find_context(ph: *mut crate::internals::HexchatPlugin,
servname: *const libc::c_char,
channel: *const libc::c_char) -> *const crate::internals::HexchatContext {
todo!();
}
unsafe extern "C" fn hexchat_get_context(ph: *mut crate::internals::HexchatPlugin) -> *const crate::internals::HexchatContext {
todo!();
}
unsafe extern "C" fn hexchat_get_info(ph: *mut crate::internals::HexchatPlugin,
id: *const libc::c_char) -> *const libc::c_char {
todo!();
}
unsafe extern "C" fn hexchat_get_prefs(ph: *mut crate::internals::HexchatPlugin,
name: *const libc::c_char,
string: *mut *const libc::c_char,
integer: *mut libc::c_int) -> libc::c_int {
todo!();
}
unsafe extern "C" fn hexchat_list_get(ph: *mut crate::internals::HexchatPlugin,
name: *const libc::c_char) -> *mut crate::internals::HexchatList {
todo!();
}
unsafe extern "C" fn hexchat_list_free(ph: *mut crate::internals::HexchatPlugin,
xlist: *const crate::internals::HexchatList) {
todo!();
}
unsafe extern "C" fn hexchat_list_fields(ph: *mut crate::internals::HexchatPlugin,
name: *const libc::c_char) -> *const *const libc::c_char {
todo!();
}
unsafe extern "C" fn hexchat_list_next(ph: *mut crate::internals::HexchatPlugin,
xlist: *const crate::internals::HexchatList) -> libc::c_int {
todo!();
}
unsafe extern "C" fn hexchat_list_str(ph: *mut crate::internals::HexchatPlugin,
xlist: *const crate::internals::HexchatList,
name: *const libc::c_char) -> *const libc::c_char {
todo!();
}
unsafe extern "C" fn hexchat_list_int(ph: *mut crate::internals::HexchatPlugin,
xlist: *const crate::internals::HexchatList,
name: *const libc::c_char) -> libc::c_int {
todo!();
}
unsafe extern "C" fn hexchat_plugingui_add(ph: *mut crate::internals::HexchatPlugin,
filename: *const libc::c_char,
name: *const libc::c_char,
desc: *const libc::c_char,
version: *const libc::c_char,
reserved: *mut char) -> *const crate::internals::PluginGuiHandle {
todo!();
}
unsafe extern "C" fn hexchat_plugingui_remove(ph: *mut crate::internals::HexchatPlugin,
handle: *const crate::internals::PluginGuiHandle) {
todo!();
}
unsafe extern "C" fn hexchat_emit_print(ph: *mut crate::internals::HexchatPlugin,
event_name: *const libc::c_char, ...) -> libc::c_int {
todo!();
}
unsafe extern "C" fn hexchat_read_fd(ph: *mut crate::internals::HexchatPlugin,
src: *const libc::c_void,
buf: *mut char,
len: *mut libc::c_int) -> libc::c_int {
todo!();
}
unsafe extern "C" fn hexchat_list_time(ph: *mut crate::internals::HexchatPlugin,
xlist: *const crate::internals::HexchatList,
name: *const libc::c_char) -> libc::time_t {
todo!();
}
unsafe extern "C" fn hexchat_gettext(ph: *mut crate::internals::HexchatPlugin,
msgid: *const libc::c_char) -> *const libc::c_char {
todo!();
}
unsafe extern "C" fn hexchat_send_modes(ph: *mut crate::internals::HexchatPlugin,
targets: *mut *const libc::c_char,
ntargets: libc::c_int,
modes_per_line: libc::c_int,
sign: libc::c_char,
mode: libc::c_char) {
todo!();
}
unsafe extern "C" fn hexchat_strip(ph: *mut crate::internals::HexchatPlugin,
string: *const libc::c_char,
len: libc::c_int,
flags: libc::c_int) -> *const libc::c_char {
todo!();
}
unsafe extern "C" fn hexchat_free(ph: *mut crate::internals::HexchatPlugin,
ptr: *const libc::c_void) {
todo!();
}
unsafe extern "C" fn hexchat_pluginpref_set_str(ph: *mut crate::internals::HexchatPlugin,
var: *const libc::c_char,
value: *const libc::c_char) -> libc::c_int {
todo!();
}
unsafe extern "C" fn hexchat_pluginpref_get_str(ph: *mut crate::internals::HexchatPlugin,
var: *const libc::c_char,
dest: *mut char) -> libc::c_int {
todo!();
}
unsafe extern "C" fn hexchat_pluginpref_set_int(ph: *mut crate::internals::HexchatPlugin,
var: *const libc::c_char,
value: libc::c_int) -> libc::c_int {
todo!();
}
unsafe extern "C" fn hexchat_pluginpref_get_int(ph: *mut crate::internals::HexchatPlugin,
var: *const libc::c_char) -> libc::c_int {
todo!();
}
unsafe extern "C" fn hexchat_pluginpref_delete(ph: *mut crate::internals::HexchatPlugin,
var: *const libc::c_char) -> libc::c_int {
todo!();
}
unsafe extern "C" fn hexchat_pluginpref_list(ph: *mut crate::internals::HexchatPlugin,
dest: *mut char) -> libc::c_int {
todo!();
}
unsafe extern "C" fn hexchat_hook_server_attrs(ph: *mut crate::internals::HexchatPlugin,
name: *const libc::c_char,
pri: libc::c_int,
/* CALLBACK */
callback: unsafe extern "C" fn(word: *const *const libc::c_char, word_eol: *const *const libc::c_char, attrs: *const crate::internals::HexchatEventAttrs, user_data: *mut libc::c_void) -> libc::c_int,
userdata: *mut libc::c_void) -> *const crate::internals::HexchatHook {
todo!();
}
unsafe extern "C" fn hexchat_hook_print_attrs(ph: *mut crate::internals::HexchatPlugin,
name: *const libc::c_char,
pri: libc::c_int,
/* CALLBACK */
callback: unsafe extern "C" fn(word: *const *const libc::c_char, attrs: *const crate::internals::HexchatEventAttrs, user_data: *mut libc::c_void) -> libc::c_int,
userdata: *mut libc::c_void) -> *const crate::internals::HexchatHook {
todo!();
}
unsafe extern "C" fn hexchat_emit_print_attrs(ph: *mut crate::internals::HexchatPlugin, attrs: *const crate::internals::HexchatEventAttrs,
event_name: *const libc::c_char, ...) -> libc::c_int {
todo!();
}
unsafe extern "C" fn hexchat_event_attrs_create(ph: *mut crate::internals::HexchatPlugin) -> *mut crate::internals::HexchatEventAttrs {
todo!();
}
unsafe extern "C" fn hexchat_event_attrs_free(ph: *mut crate::internals::HexchatPlugin,
attrs: *mut crate::internals::HexchatEventAttrs) {
todo!();
}
impl PluginEnvironment {
pub fn new() -> Pin<Box<Self>> {
Box::pin(Self {
plugins: Default::default(),
hooks: Default::default(),
depth: Default::default(),
_pin: PhantomPinned,
})
}
}
impl MockPlugin {
pub fn new<T: for<'ph> crate::Plugin<'ph> + Default>(
env: Pin<&PluginEnvironment>,
filename: CString,
arg: Option<&CStr>,
) -> Option<Pin<Box<MockPlugin>>> {
let filename = filename.into_raw();
let mut plug = Box::pin(MockPlugin {
methods: crate::internals::Ph {
hexchat_hook_command,
hexchat_hook_server,
hexchat_hook_print,
hexchat_hook_timer,
hexchat_hook_fd,
hexchat_unhook,
hexchat_print,
userdata: hexchat_printf as *mut libc::c_void,
hexchat_command,
hexchat_commandf_do_not_use: hexchat_commandf,
hexchat_nickcmp,
hexchat_set_context,
hexchat_find_context,
hexchat_get_context,
hexchat_get_info,
hexchat_get_prefs,
hexchat_list_get,
hexchat_list_free,
hexchat_list_fields,
hexchat_list_next,
hexchat_list_str,
hexchat_list_int,
hexchat_plugingui_add,
hexchat_plugingui_remove,
hexchat_emit_print,
hexchat_read_fd,
hexchat_list_time,
hexchat_gettext,
hexchat_send_modes,
hexchat_strip,
hexchat_free,
hexchat_pluginpref_set_str,
hexchat_pluginpref_get_str,
hexchat_pluginpref_set_int,
hexchat_pluginpref_get_int,
hexchat_pluginpref_delete,
hexchat_pluginpref_list,
hexchat_hook_server_attrs,
hexchat_hook_print_attrs,
hexchat_emit_print_attrs,
hexchat_event_attrs_create,
hexchat_event_attrs_free,
},
filename: filename,
plugin_name: filename,
plugin_desc: ptr::null(),
plugin_vers: ptr::null(),
free_strings: false,
env: &*env,
_pin: PhantomPinned,
});
if unsafe {
let ptr: *mut MockPlugin = &mut *plug;
crate::hexchat_plugin_init::<'_, T>(
crate::LtPhPtr {
ph: ptr as *mut crate::internals::Ph,
_lt: PhantomData,
},
ptr::addr_of_mut!((*ptr).plugin_name),
ptr::addr_of_mut!((*ptr).plugin_desc),
ptr::addr_of_mut!((*ptr).plugin_vers),
arg.map(|arg| arg.as_ptr()).unwrap_or(ptr::null()),
) != 0
} {
Some(plug)
} else {
None
}
}
}