Add some more code from pidgin-icq
This commit is contained in:
136
src/chat_info.rs
Normal file
136
src/chat_info.rs
Normal file
@@ -0,0 +1,136 @@
|
||||
// This is a copy of https://github.com/Flared/purple-icq/blob/master/src/chat_info.rs
|
||||
|
||||
use super::purple;
|
||||
use lazy_static::lazy_static;
|
||||
use std::ffi::CString;
|
||||
|
||||
lazy_static! {
|
||||
pub static ref SN: CString = CString::new("sn").unwrap();
|
||||
pub static ref SN_NAME: CString = CString::new("Chat ID").unwrap();
|
||||
pub static ref STAMP: CString = CString::new("stamp").unwrap();
|
||||
pub static ref TITLE: CString = CString::new("title").unwrap();
|
||||
pub static ref GROUP: CString = CString::new("group").unwrap();
|
||||
pub static ref STATE: CString = CString::new("state").unwrap();
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct MemberRole(String);
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct PartialChatInfo {
|
||||
pub sn: String,
|
||||
pub title: String,
|
||||
pub group: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct ChatInfo {
|
||||
pub stamp: Option<String>,
|
||||
pub group: Option<String>,
|
||||
pub sn: String,
|
||||
pub title: String,
|
||||
pub about: Option<String>,
|
||||
pub members_version: String,
|
||||
pub info_version: String,
|
||||
pub members: Vec<ChatMember>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ChatMember {
|
||||
pub sn: String,
|
||||
pub friendly_name: Option<String>,
|
||||
pub role: MemberRole,
|
||||
pub last_seen: Option<u64>,
|
||||
pub first_name: Option<String>,
|
||||
pub last_name: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ChatInfoVersion {
|
||||
pub members_version: String,
|
||||
pub info_version: String,
|
||||
}
|
||||
|
||||
impl MemberRole {
|
||||
pub fn as_flags(&self) -> purple::PurpleConvChatBuddyFlags {
|
||||
match self.0.as_str() {
|
||||
"admin" => purple::PurpleConvChatBuddyFlags::PURPLE_CBFLAGS_OP,
|
||||
"readonly" => purple::PurpleConvChatBuddyFlags::PURPLE_CBFLAGS_NONE,
|
||||
_ => purple::PurpleConvChatBuddyFlags::PURPLE_CBFLAGS_VOICE,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialChatInfo {
|
||||
pub fn from_hashtable(table: &purple::StrHashTable) -> Option<Self> {
|
||||
Some(Self {
|
||||
group: table.lookup(&GROUP).map(Into::into),
|
||||
sn: table.lookup(&SN)?.into(),
|
||||
title: table.lookup(&TITLE)?.into(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn as_hashtable(&self) -> purple::StrHashTable {
|
||||
let mut table = purple::StrHashTable::default();
|
||||
table.insert(&SN, &self.sn);
|
||||
if let Some(group) = &self.group {
|
||||
table.insert(&GROUP, &group);
|
||||
}
|
||||
table.insert(&TITLE, &self.title);
|
||||
table
|
||||
}
|
||||
}
|
||||
|
||||
impl ChatInfo {
|
||||
pub fn as_partial(&self) -> PartialChatInfo {
|
||||
PartialChatInfo {
|
||||
sn: self.sn.clone(),
|
||||
title: self.title.clone(),
|
||||
group: self.group.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn need_update(&self, new_version: &ChatInfoVersion) -> bool {
|
||||
self.members_version < new_version.members_version
|
||||
|| self.info_version < new_version.info_version
|
||||
}
|
||||
}
|
||||
/*
|
||||
impl From<icq::client::GetChatInfoResponseData> for ChatInfo {
|
||||
fn from(info: icq::client::GetChatInfoResponseData) -> Self {
|
||||
Self {
|
||||
sn: info.sn,
|
||||
stamp: Some(info.stamp),
|
||||
title: info.name,
|
||||
members_version: info.members_version,
|
||||
info_version: info.info_version,
|
||||
about: info.about,
|
||||
members: info
|
||||
.members
|
||||
.into_iter()
|
||||
.map(|m| ChatMember {
|
||||
sn: m.sn,
|
||||
role: MemberRole(m.role),
|
||||
last_seen: m.user_state.last_seen.and_then(|t| match t {
|
||||
0 => None,
|
||||
t => Some(t),
|
||||
}),
|
||||
friendly_name: m.friendly,
|
||||
first_name: m.anketa.first_name,
|
||||
last_name: m.anketa.last_name,
|
||||
})
|
||||
.collect(),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<icq::client::events::HistDlgStateMChatState> for ChatInfoVersion {
|
||||
fn from(info: icq::client::events::HistDlgStateMChatState) -> Self {
|
||||
Self {
|
||||
members_version: info.members_version,
|
||||
info_version: info.info_version,
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
121
src/logging.rs
Normal file
121
src/logging.rs
Normal file
@@ -0,0 +1,121 @@
|
||||
// This is a copy of https://github.com/Flared/purple-icq/blob/master/src/logging.rs
|
||||
|
||||
//use crate::messages::{FdSender, SystemMessage};
|
||||
use crate::purple;
|
||||
use std::cell::RefCell;
|
||||
use std::sync::Mutex;
|
||||
|
||||
std::thread_local! {
|
||||
pub static LOGGER: RefCell<Option<Box<dyn log::Log>>> = RefCell::new(None);
|
||||
}
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
static ref PURPLE_BUFFER: Mutex<Vec<(String, log::Level, String)>> = Default::default();
|
||||
}
|
||||
|
||||
static TLS_LOGGER: ThreadLocalLogger = ThreadLocalLogger;
|
||||
|
||||
pub struct ThreadLocalLogger;
|
||||
|
||||
impl log::Log for ThreadLocalLogger {
|
||||
fn enabled(&self, _metadata: &log::Metadata) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn log(&self, record: &log::Record) {
|
||||
LOGGER.with(|cell| {
|
||||
if let Some(ref logger) = cell.borrow().as_ref() {
|
||||
logger.log(record);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn flush(&self) {
|
||||
LOGGER.with(|cell| {
|
||||
if let Some(ref logger) = cell.borrow().as_ref() {
|
||||
logger.flush()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PurpleDebugLogger;
|
||||
|
||||
impl log::Log for PurpleDebugLogger {
|
||||
fn enabled(&self, metadata: &log::Metadata) -> bool {
|
||||
metadata.level() < log::Level::Debug
|
||||
}
|
||||
|
||||
fn log(&self, record: &log::Record) {
|
||||
let purple_level = match record.level() {
|
||||
log::Level::Error => purple::PurpleDebugLevel::PURPLE_DEBUG_ERROR,
|
||||
log::Level::Warn => purple::PurpleDebugLevel::PURPLE_DEBUG_WARNING,
|
||||
log::Level::Info => purple::PurpleDebugLevel::PURPLE_DEBUG_INFO,
|
||||
_ => purple::PurpleDebugLevel::PURPLE_DEBUG_MISC,
|
||||
};
|
||||
|
||||
let target = if !record.target().is_empty() {
|
||||
record.target()
|
||||
} else {
|
||||
record.module_path().unwrap_or_default()
|
||||
};
|
||||
let line = format!("[{}] {}\n", target, record.args());
|
||||
purple::debug(purple_level, "", &line);
|
||||
}
|
||||
|
||||
fn flush(&self) {
|
||||
let buffer = {
|
||||
match PURPLE_BUFFER.lock() {
|
||||
Ok(mut buffer) => buffer.split_off(0),
|
||||
Err(_) => return,
|
||||
}
|
||||
};
|
||||
for (target, level, message) in buffer {
|
||||
log::log!(target: &target, level, "{}", message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
pub struct RemoteLogger(pub FdSender<SystemMessage>);
|
||||
|
||||
impl log::Log for RemoteLogger {
|
||||
fn enabled(&self, metadata: &log::Metadata) -> bool {
|
||||
metadata.level() < log::Level::Debug
|
||||
}
|
||||
|
||||
fn log(&self, record: &log::Record) {
|
||||
let target = if !record.target().is_empty() {
|
||||
record.target()
|
||||
} else {
|
||||
record.module_path().unwrap_or_default()
|
||||
};
|
||||
|
||||
if let Ok(mut buffer) = PURPLE_BUFFER.lock() {
|
||||
buffer.push((target.into(), record.level(), record.args().to_string()));
|
||||
}
|
||||
}
|
||||
|
||||
fn flush(&self) {
|
||||
self.0.clone().try_send(SystemMessage::FlushLogs);
|
||||
}
|
||||
}
|
||||
*/
|
||||
pub fn init(level: log::LevelFilter) -> Result<(), log::SetLoggerError> {
|
||||
log::set_logger(&TLS_LOGGER).map(|()| log::set_max_level(level))
|
||||
}
|
||||
|
||||
pub fn set_thread_logger<T>(logger: T)
|
||||
where
|
||||
T: log::Log + 'static,
|
||||
{
|
||||
LOGGER.with(|cell| *cell.borrow_mut() = Some(Box::new(logger)))
|
||||
}
|
||||
|
||||
pub fn flush() {
|
||||
LOGGER.with(|cell| {
|
||||
if let Some(ref logger) = cell.borrow().as_ref() {
|
||||
logger.flush();
|
||||
}
|
||||
})
|
||||
}
|
Reference in New Issue
Block a user