matrixmailer/src/matrix.rs

165 lines
No EOL
7 KiB
Rust

use matrix_sdk::{Client, ruma::{UserId, RoomId, events::{room::message::RoomMessageEventContent}}, Session, room::Room, config::SyncSettings};
use ruma::OwnedRoomAliasId;
use postbus::command::Mailbox;
use crate::config::{Mapping, Config};
pub async fn get_clients(config: &mut Config) -> Vec<Client> {
let mut clients: Vec<Client> = vec![];
let mut room_aliases_resolved = false;
// Try to build a matrix_sdk::Client object for each configured client
for conf in &mut config.clients {
let user_id = match UserId::parse(&conf.mxid) {
Ok(id) => id,
Err(_e) => continue,
};
let client = match Client::builder().user_id(&user_id).build().await {
Ok(c) => c,
Err(_e) => continue,
};
// Attempt to restore a previous login
if let Some(token) = &conf.access_token {
if let Some(dev_id) = &conf.device_id {
match client.restore_login(Session { access_token: token.to_string(), user_id: (&user_id).to_owned(), device_id: dev_id.as_str().into()}).await {
Ok(_) => (),
Err(_e) => continue,
};
}
}
// If login restoration did not work, log in using the password
if !client.logged_in().await {
match conf.password.len() {
0 => continue,
_ => match client.login(
user_id,
&conf.password,
(&conf).device_id.as_deref(),
Some("matrixmailer")
).await {
Ok(_) => (),
Err(_) => continue,
}
}
}
// If client is logged in, update the config to persist the session
if let Some(session) = client.session().await {
conf.access_token = Some(session.access_token);
conf.device_id = Some(session.device_id.to_string());
}
// If room aliases are supplied as room_id in the config file, resolve them and store the pairs properly
if !room_aliases_resolved && client.logged_in().await {
for mapping in &mut config.mappings {
if mapping.room_id.as_str().chars().nth(0).unwrap() == '#' || mapping.room_id.len() == 0 {
// TODO: Clean this up once matrix-rust-sdk 0.6.0 is available
let alias: OwnedRoomAliasId = match OwnedRoomAliasId::try_from(mapping.room_id.as_str()) {
Ok(a) => a,
Err(_e) => continue,
};
let resolve_request = matrix_sdk::ruma::api::client::alias::get_alias::v3::Request::new(&alias);
match client.send(resolve_request, None).await {
Ok(result) => {
let matrix_sdk::ruma::api::client::alias::get_alias::v3::Response{room_id, ..} = result;
mapping.room_alias = Some(mapping.room_id.clone());
mapping.room_id = room_id.to_string();
},
Err(_e) => (),
};
}let a = ruma::RoomAliasId::parse(&String::from("abc"));
}
room_aliases_resolved = true;
}
clients.push(client.clone());
}
clients
}
async fn client_from_mxid(mxid: &str, clients: &Vec<Client>) -> Option<Client> {
for client in clients {
if client.user_id().await.unwrap().as_str() == mxid {
return Some(client.to_owned());
}
}
None
}
pub async fn send(from_mail: &Option<Mailbox>, recipient: &Mailbox, plain_content: &str, html_content: &str, clients: &Vec<Client>, mappings: &Vec<Mapping>) {
for mapping in mappings {
let mut applies = true;
if let Some(from) = &mapping.from {
if let Some(mailbox) = from_mail {
if from != &format!("{}@{}", mailbox.local, mailbox.domain.0) {
applies = false;
}
}
}
if let Some(to) = &mapping.to {
if to != &format!("{}@{}", recipient.local, recipient.domain.0) {
applies = false;
}
}
if applies {
let local = &recipient.local;
let domain = &recipient.domain.0;
let sender_mxid = match &mapping.mxid_sender {
Some(s) => s.to_owned(),
None => {
format!("@{}:{}", local, domain)
},
};
if let Some(c) = client_from_mxid(&sender_mxid, clients).await {
if let Ok(roomid) = RoomId::parse(&mapping.room_id) {
match c.sync_once(SyncSettings::default()).await {
Ok(_) => (),
Err(_e) => (),
};
let room = match c.get_room(&roomid) {
Some(Room::Joined(room)) => room,
Some(Room::Invited(room)) => {
match room.accept_invitation().await {
Ok(_) => (),
Err(_e) => println!("Could not accept invitation"),
};
// Continuously check whether the room has been joined.
// Joins can be significantly delayed, depending on the room and the server
let mut joined = false;
let mut counter = 0;
while !joined && counter < 10{
match c.get_room(&roomid) {
Some(Room::Joined(_)) => joined = true,
_ => (),
}
match c.sync_once(SyncSettings::default()).await {
Ok(_) => (),
Err(_e) => (),
};
std::thread::sleep(std::time::Duration::from_millis(u64::pow(2, counter) * 100));
counter += 1;
}
if let Some(Room::Joined(joined)) = c.get_room(&roomid) {
joined
}
else {
println!("Joining room timed out.");
continue;
}
},
_ => {
println!("Room either left or unfound.");
continue;
}
};
match room.send(RoomMessageEventContent::text_html(plain_content, html_content), None).await {
Ok(_) => (),
Err(_e) => println!("Sending message failed"),
};
}
}
}
}
}