mum_cli/
state.rs

1pub mod channel;
2pub mod server;
3pub mod user;
4
5use crate::audio::{sound_effects::NotificationEvents, AudioInput, AudioOutput};
6use crate::error::StateError;
7use crate::network::tcp::{DisconnectedReason, TcpEvent, TcpEventData};
8use crate::network::{ConnectionInfo, VoiceStreamType};
9use crate::notifications;
10use crate::state::server::{ConnectingServer, Server};
11use crate::state::user::User;
12
13use chrono::NaiveDateTime;
14use log::*;
15use mumble_protocol::control::{msgs, ControlPacket};
16use mumble_protocol::ping::PongPacket;
17use mumble_protocol::voice::Serverbound;
18use mumlib::command::{
19    ChannelTarget, Command, CommandResponse, MessageTarget, MumbleEvent, MumbleEventKind,
20};
21use mumlib::config::Config;
22use mumlib::Error;
23use std::fmt::Debug;
24use std::iter;
25use std::net::{SocketAddr, ToSocketAddrs};
26use std::sync::{Arc, RwLock};
27use tokio::sync::{mpsc, watch};
28
29macro_rules! at {
30    ( $( $event:expr => $generator:expr ),+ $(,)? ) => {
31        ExecutionContext::TcpEventCallback(vec![
32            $( ($event, Box::new($generator)), )+
33        ])
34    };
35}
36
37macro_rules! now {
38    ($data:expr) => {
39        ExecutionContext::Now(Box::new(move || Box::new(iter::once($data))))
40    };
41}
42
43type Responses = Box<dyn Iterator<Item = mumlib::error::Result<Option<CommandResponse>>>>;
44
45type TcpEventCallback = Box<dyn FnOnce(TcpEventData<'_>) -> Responses>;
46type TcpEventSubscriberCallback = Box<
47    dyn FnMut(
48        TcpEventData<'_>,
49        &mut mpsc::UnboundedSender<mumlib::error::Result<Option<CommandResponse>>>,
50    ) -> bool,
51>;
52
53//TODO give me a better name
54pub enum ExecutionContext {
55    TcpEventCallback(Vec<(TcpEvent, TcpEventCallback)>),
56    TcpEventSubscriber(TcpEvent, TcpEventSubscriberCallback),
57    Now(Box<dyn FnOnce() -> Responses>),
58    Ping(
59        Box<dyn FnOnce() -> mumlib::error::Result<SocketAddr>>,
60        Box<
61            dyn FnOnce(Option<PongPacket>) -> mumlib::error::Result<Option<CommandResponse>> + Send,
62        >,
63    ),
64}
65
66impl Debug for ExecutionContext {
67    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
68        f.debug_tuple(match self {
69            ExecutionContext::TcpEventCallback(_) => "TcpEventCallback",
70            ExecutionContext::TcpEventSubscriber(_, _) => "TcpEventSubscriber",
71            ExecutionContext::Now(_) => "Now",
72            ExecutionContext::Ping(_, _) => "Ping",
73        })
74        .finish()
75    }
76}
77
78#[derive(Clone, Copy, Debug, Eq, PartialEq)]
79pub enum StatePhase {
80    Disconnected,
81    Connecting,
82    Connected(VoiceStreamType),
83}
84
85#[derive(Debug)]
86pub struct State {
87    config: Config,
88    server: Server,
89    audio_input: AudioInput,
90    audio_output: AudioOutput,
91    message_buffer: Vec<(NaiveDateTime, String, u32)>,
92
93    phase_watcher: (watch::Sender<StatePhase>, watch::Receiver<StatePhase>),
94
95    events: Vec<MumbleEvent>,
96}
97
98impl State {
99    pub fn new() -> Result<Self, StateError> {
100        let config = mumlib::config::read_cfg(&mumlib::config::default_cfg_path())?;
101        let phase_watcher = watch::channel(StatePhase::Disconnected);
102        let audio_input = AudioInput::new(
103            config
104                .audio
105                .as_ref()
106                .and_then(|audio| audio.input_volume)
107                .unwrap_or(1.0),
108            config
109                .audio
110                .as_ref()
111                .and_then(|audio| audio.disable_noise_gate)
112                .unwrap_or(false),
113            phase_watcher.1.clone(),
114        )
115        .map_err(StateError::AudioError)?;
116        let audio_output = AudioOutput::new(
117            config
118                .audio
119                .as_ref()
120                .and_then(|audio| audio.output_volume)
121                .unwrap_or(1.0),
122        )
123        .map_err(StateError::AudioError)?;
124        let mut state = Self {
125            config,
126            server: Server::Disconnected,
127            audio_input,
128            audio_output,
129            message_buffer: Vec::new(),
130            phase_watcher,
131            events: Vec::new(),
132        };
133        state.reload_config();
134        Ok(state)
135    }
136
137    pub fn user_state(&mut self, msg: msgs::UserState) {
138        match &mut self.server {
139            Server::Connecting(sb) => sb.user_state(msg),
140            Server::Connected(s) => {
141                let mut events = Vec::new();
142                let to_channel = msg.get_channel_id();
143                let this_channel = s.users_channel(s.session_id());
144                let this_channel_name = s
145                    .channels()
146                    .get(&this_channel)
147                    .map(|c| c.name())
148                    .unwrap_or("<unnamed channel>")
149                    .to_owned();
150
151                if msg.get_session() != s.session_id() {
152                    if let Some(user) = s.users().get(&msg.get_session()) {
153                        // we're updating a user
154                        let from_channel = user.channel();
155                        if from_channel != to_channel {
156                            if from_channel == this_channel {
157                                // User moved from our channel to somewhere else
158                                if let Some(channel) = s.channels().get(&to_channel) {
159                                    notifications::send(format!(
160                                        "{} moved to channel {}",
161                                        user.name(),
162                                        channel.name(),
163                                    ));
164                                    events.push(MumbleEventKind::UserLeftChannel(
165                                        user.name().to_owned(),
166                                        channel.name().to_owned(),
167                                    ));
168                                }
169                                self.audio_output
170                                    .play_effect(NotificationEvents::UserLeftChannel);
171                            } else if to_channel == this_channel {
172                                // User moved from somewhere else to our channel
173                                if let Some(channel) = s.channels().get(&from_channel) {
174                                    notifications::send(format!(
175                                        "{} moved to your channel from {}",
176                                        user.name(),
177                                        channel.name(),
178                                    ));
179                                    events.push(MumbleEventKind::UserJoinedChannel(
180                                        user.name().to_owned(),
181                                        channel.name().to_owned(),
182                                    ));
183                                }
184                                self.audio_output
185                                    .play_effect(NotificationEvents::UserJoinedChannel);
186                            }
187                        }
188
189                        let mute = (msg.has_self_mute() && user.self_mute() != msg.get_self_mute())
190                            .then(|| msg.get_self_mute());
191                        let deaf = (msg.has_self_deaf() && user.self_deaf() != msg.get_self_deaf())
192                            .then(|| msg.get_self_deaf());
193
194                        //send notification if a user muted/unmuted
195                        if mute != None || deaf != None {
196                            let mut s = user.name().to_owned();
197                            if let Some(mute) = mute {
198                                s += if mute { " muted" } else { " unmuted" };
199                            }
200                            if mute.is_some() && deaf.is_some() {
201                                s += " and";
202                            }
203                            if let Some(deaf) = deaf {
204                                s += if deaf { " deafened" } else { " undeafened" };
205                            }
206                            s += " themselves";
207                            notifications::send(s.clone());
208                            events.push(MumbleEventKind::UserMuteStateChanged(s));
209                        }
210                    } else {
211                        // the user is new
212                        if this_channel == to_channel {
213                            notifications::send(format!(
214                                "{} connected and joined {}",
215                                msg.get_name(),
216                                this_channel_name,
217                            ));
218                            events.push(MumbleEventKind::UserConnected(
219                                msg.get_name().to_string(),
220                                this_channel_name,
221                            ));
222                            self.audio_output
223                                .play_effect(NotificationEvents::UserConnected);
224                        }
225                    }
226                }
227
228                s.user_state(msg);
229                for event in events {
230                    self.push_event(event);
231                }
232            }
233            Server::Disconnected => warn!("Tried to parse a user state while disconnected"),
234        }
235    }
236
237    pub fn remove_user(&mut self, msg: msgs::UserRemove) {
238        match &mut self.server {
239            Server::Disconnected => warn!("Tried to remove user while disconnected"),
240            Server::Connecting(sb) => sb.user_remove(msg),
241            Server::Connected(s) => {
242                let mut events = Vec::new();
243                let this_channel = s.users_channel(s.session_id());
244                let other_channel = s.users_channel(msg.get_session());
245                if this_channel == other_channel {
246                    let channel_name = s
247                        .channels()
248                        .get(&this_channel)
249                        .map(|c| c.name())
250                        .unwrap_or("<unnamed channel>")
251                        .to_owned();
252                    let user_name = s
253                        .users()
254                        .get(&msg.get_session())
255                        .map(|u| u.name())
256                        .unwrap_or("<unknown user>")
257                        .to_owned();
258                    notifications::send(format!("{} disconnected", user_name));
259                    events.push(MumbleEventKind::UserDisconnected(user_name, channel_name));
260                    self.audio_output
261                        .play_effect(NotificationEvents::UserDisconnected);
262                }
263
264                s.user_remove(msg);
265                for event in events {
266                    self.push_event(event);
267                }
268            }
269        }
270    }
271
272    pub fn reload_config(&mut self) {
273        match mumlib::config::read_cfg(&mumlib::config::default_cfg_path()) {
274            Ok(config) => {
275                self.config = config;
276            }
277            Err(e) => error!("Couldn't read config: {}", e),
278        }
279        if let Some(input_volume) = self
280            .config
281            .audio
282            .as_ref()
283            .and_then(|audio| audio.input_volume)
284        {
285            self.audio_input.set_volume(input_volume);
286        }
287        if let Some(output_volume) = self
288            .config
289            .audio
290            .as_ref()
291            .and_then(|audio| audio.output_volume)
292        {
293            self.audio_output.set_volume(output_volume);
294        }
295        if let Some(sound_effects) = self
296            .config
297            .audio
298            .as_ref()
299            .and_then(|audio| audio.sound_effects.as_ref())
300        {
301            self.audio_output.load_sound_effects(sound_effects);
302        }
303    }
304
305    pub fn register_message(&mut self, msg: (String, u32)) {
306        self.message_buffer
307            .push((chrono::Local::now().naive_local(), msg.0, msg.1));
308    }
309
310    pub fn broadcast_phase(&self, phase: StatePhase) {
311        self.phase_watcher.0.send(phase).unwrap();
312    }
313
314    pub fn initialized(&self) {
315        self.broadcast_phase(StatePhase::Connected(VoiceStreamType::Tcp));
316        self.audio_output
317            .play_effect(NotificationEvents::ServerConnect);
318    }
319
320    /// Store a new event
321    pub fn push_event(&mut self, kind: MumbleEventKind) {
322        self.events.push(MumbleEvent {
323            timestamp: chrono::Local::now().naive_local(),
324            kind,
325        });
326    }
327
328    pub fn audio_input(&self) -> &AudioInput {
329        &self.audio_input
330    }
331
332    pub fn audio_output(&self) -> &AudioOutput {
333        &self.audio_output
334    }
335
336    pub fn phase_receiver(&self) -> watch::Receiver<StatePhase> {
337        self.phase_watcher.1.clone()
338    }
339
340    pub(crate) fn server(&self) -> &Server {
341        &self.server
342    }
343
344    pub(crate) fn server_mut(&mut self) -> &mut Server {
345        &mut self.server
346    }
347
348    pub fn username(&self) -> Option<&str> {
349        match self.server() {
350            Server::Disconnected => None,
351            Server::Connecting(sb) => Some(sb.username()),
352            Server::Connected(s) => Some(s.username()),
353        }
354    }
355
356    pub fn password(&self) -> Option<&str> {
357        match self.server() {
358            Server::Disconnected => None,
359            Server::Connecting(sb) => sb.password(),
360            Server::Connected(_) => None,
361        }
362    }
363
364    /// Gets the username of a user with id `user` connected to the same server that we are connected to.
365    /// If we are connected to the server but the user with the id doesn't exist, the string "Unknown user {id}"
366    /// is returned instead. If we aren't connected to a server, None is returned instead.
367    fn get_user_name(&self, user: u32) -> Option<String> {
368        match &self.server {
369            Server::Disconnected => None,
370            Server::Connecting(_) => None,
371            Server::Connected(s) => Some(
372                s.users()
373                    .get(&user)
374                    .map(User::name)
375                    .map(ToOwned::to_owned)
376                    .unwrap_or(format!("Unknown user {}", user)),
377            ),
378        }
379    }
380}
381
382pub fn handle_command(
383    og_state: Arc<RwLock<State>>,
384    command: Command,
385    packet_sender: &mut mpsc::UnboundedSender<ControlPacket<Serverbound>>,
386    connection_info_sender: &mut watch::Sender<Option<ConnectionInfo>>,
387) -> ExecutionContext {
388    // re-borrow to please borrowck
389    let mut state = &mut *og_state.write().unwrap();
390    match command {
391        Command::ChannelJoin { channel_identifier } => {
392            if let Server::Connected(s) = state.server() {
393                let id = match s.channel_name(&channel_identifier) {
394                    Ok((id, _)) => id,
395                    Err(e) => {
396                        return now!(Err(Error::ChannelIdentifierError(channel_identifier, e)))
397                    }
398                };
399
400                let mut msg = msgs::UserState::new();
401                msg.set_session(s.session_id());
402                msg.set_channel_id(id);
403                packet_sender.send(msg.into()).unwrap();
404                now!(Ok(None))
405            } else {
406                now!(Err(Error::Disconnected))
407            }
408        }
409        Command::ChannelList => {
410            if let Server::Connected(s) = state.server() {
411                let list = channel::into_channel(s.channels(), s.users());
412                now!(Ok(Some(CommandResponse::ChannelList { channels: list })))
413            } else {
414                now!(Err(Error::Disconnected))
415            }
416        }
417        Command::ConfigReload => {
418            state.reload_config();
419            now!(Ok(None))
420        }
421        Command::DeafenSelf(toggle) => {
422            if let Server::Connected(server) = &mut state.server {
423                let audio_output = &mut state.audio_output;
424                let action = match (toggle, server.muted(), server.deafened()) {
425                    (Some(false), false, false) => None,
426                    (Some(false), false, true) => Some((false, false)),
427                    (Some(false), true, false) => None,
428                    (Some(false), true, true) => Some((true, false)),
429                    (Some(true), false, false) => Some((false, true)),
430                    (Some(true), false, true) => None,
431                    (Some(true), true, false) => Some((true, true)),
432                    (Some(true), true, true) => None,
433                    (None, false, false) => Some((false, true)),
434                    (None, false, true) => Some((false, false)),
435                    (None, true, false) => Some((true, true)),
436                    (None, true, true) => Some((true, false)),
437                };
438
439                let mut new_deaf = None;
440                if let Some((mute, deafen)) = action {
441                    if server.deafened() != deafen {
442                        audio_output.play_effect(if deafen {
443                            NotificationEvents::Deafen
444                        } else {
445                            NotificationEvents::Undeafen
446                        });
447                    } else if server.muted() != mute {
448                        audio_output.play_effect(if mute {
449                            NotificationEvents::Mute
450                        } else {
451                            NotificationEvents::Unmute
452                        });
453                    }
454                    let mut msg = msgs::UserState::new();
455                    if server.muted() != mute {
456                        msg.set_self_mute(mute);
457                    } else if !mute && !deafen && server.deafened() {
458                        msg.set_self_mute(false);
459                    }
460                    if server.deafened() != deafen {
461                        msg.set_self_deaf(deafen);
462                        new_deaf = Some(deafen);
463                    }
464                    server.set_muted(mute);
465                    server.set_deafened(deafen);
466                    packet_sender.send(msg.into()).unwrap();
467                }
468
469                now!(Ok(
470                    new_deaf.map(|b| CommandResponse::DeafenStatus { is_deafened: b })
471                ))
472            } else {
473                now!(Err(Error::Disconnected))
474            }
475        }
476        Command::Events { block } => {
477            if block {
478                warn!("Blocking event list is unimplemented");
479                now!(Err(Error::Unimplemented))
480            } else {
481                let events: Vec<_> = state
482                    .events
483                    .iter()
484                    .map(|event| {
485                        Ok(Some(CommandResponse::Event {
486                            event: event.clone(),
487                        }))
488                    })
489                    .collect();
490                ExecutionContext::Now(Box::new(move || Box::new(events.into_iter())))
491            }
492        }
493        Command::InputVolumeSet(volume) => {
494            state.audio_input.set_volume(volume);
495            now!(Ok(None))
496        }
497        Command::MuteOther(username, toggle) => {
498            if let Server::Connected(s) = state.server_mut() {
499                let id = s
500                    .users_mut()
501                    .iter_mut()
502                    .find(|(_, user)| user.name() == username);
503
504                let (id, user) = match id {
505                    Some(id) => (*id.0, id.1),
506                    None => return now!(Err(Error::InvalidUsername(username))),
507                };
508
509                let action = match toggle {
510                    Some(state) => {
511                        if user.suppressed() != state {
512                            Some(state)
513                        } else {
514                            None
515                        }
516                    }
517                    None => Some(!user.suppressed()),
518                };
519
520                if let Some(action) = action {
521                    user.set_suppressed(action);
522                    state.audio_output.set_mute(id, action);
523                }
524
525                now!(Ok(None))
526            } else {
527                now!(Err(Error::Disconnected))
528            }
529        }
530        Command::MuteSelf(toggle) => {
531            if let Server::Connected(server) = &mut state.server {
532                let audio_output = &mut state.audio_output;
533                let action = match (toggle, server.muted(), server.deafened()) {
534                    (Some(false), false, false) => None,
535                    (Some(false), false, true) => Some((false, false)),
536                    (Some(false), true, false) => Some((false, false)),
537                    (Some(false), true, true) => Some((false, false)),
538                    (Some(true), false, false) => Some((true, false)),
539                    (Some(true), false, true) => None,
540                    (Some(true), true, false) => None,
541                    (Some(true), true, true) => None,
542                    (None, false, false) => Some((true, false)),
543                    (None, false, true) => Some((false, false)),
544                    (None, true, false) => Some((false, false)),
545                    (None, true, true) => Some((false, false)),
546                };
547
548                let mut new_mute = None;
549                if let Some((mute, deafen)) = action {
550                    if server.deafened() != deafen {
551                        audio_output.play_effect(if deafen {
552                            NotificationEvents::Deafen
553                        } else {
554                            NotificationEvents::Undeafen
555                        });
556                    } else if server.muted() != mute {
557                        audio_output.play_effect(if mute {
558                            NotificationEvents::Mute
559                        } else {
560                            NotificationEvents::Unmute
561                        });
562                    }
563                    let mut msg = msgs::UserState::new();
564                    if server.muted() != mute {
565                        msg.set_self_mute(mute);
566                        new_mute = Some(mute)
567                    } else if !mute && !deafen && server.deafened() {
568                        msg.set_self_mute(false);
569                        new_mute = Some(false)
570                    }
571                    if server.deafened() != deafen {
572                        msg.set_self_deaf(deafen);
573                    }
574                    server.set_muted(mute);
575                    server.set_deafened(deafen);
576                    packet_sender.send(msg.into()).unwrap();
577                }
578
579                now!(Ok(
580                    new_mute.map(|b| CommandResponse::MuteStatus { is_muted: b })
581                ))
582            } else {
583                now!(Err(Error::Disconnected))
584            }
585        }
586        Command::OutputVolumeSet(volume) => {
587            state.audio_output.set_volume(volume);
588            now!(Ok(None))
589        }
590        Command::Ping => {
591            now!(Ok(Some(CommandResponse::Pong)))
592        }
593        Command::ServerConnect {
594            host,
595            port,
596            username,
597            password,
598            accept_invalid_cert,
599        } => {
600            if let Server::Disconnected = state.server() {
601                let server =
602                    ConnectingServer::new(format!("{}:{}", host, port), username, password);
603                state.server = Server::Connecting(server);
604                state.phase_watcher.0.send(StatePhase::Connecting).unwrap();
605
606                let socket_addr = match (host.as_ref(), port)
607                    .to_socket_addrs()
608                    .map(|mut e| e.next())
609                {
610                    Ok(Some(v)) => v,
611                    _ => {
612                        warn!("Error parsing server addr");
613                        return now!(Err(Error::InvalidServerAddr(host, port)));
614                    }
615                };
616                connection_info_sender
617                    .send(Some(ConnectionInfo::new(
618                        socket_addr,
619                        host,
620                        accept_invalid_cert,
621                    )))
622                    .unwrap();
623                let state = Arc::clone(&og_state);
624                at!(
625                    TcpEvent::Connected => move |res| {
626                        //runs the closure when the client is connected
627                        if let TcpEventData::Connected(res) = res {
628                            Box::new(iter::once(res.map(|msg| {
629                                Some(CommandResponse::ServerConnect {
630                                    welcome_message: if msg.has_welcome_text() {
631                                        Some(msg.get_welcome_text().to_string())
632                                    } else {
633                                        None
634                                    },
635                                    server_state: if let Server::Connected(s) = &state.read().unwrap().server {
636                                        mumlib::state::Server::from(s)
637                                    } else {
638                                        unreachable!("Server should be set to connected when Tcp Connected events resolve")
639                                    },
640                                })
641                            })))
642                        } else {
643                            unreachable!("callback should be provided with a TcpEventData::Connected");
644                        }
645                    },
646                    TcpEvent::Disconnected(DisconnectedReason::InvalidTls) => |_| {
647                        Box::new(iter::once(Err(Error::ServerCertReject)))
648                    }
649                )
650            } else {
651                now!(Err(Error::Disconnected))
652            }
653        }
654        Command::ServerDisconnect => {
655            if let Server::Connected(_) = state.server() {
656                state.server = Server::Disconnected;
657                state
658                    .phase_watcher
659                    .0
660                    .send(StatePhase::Disconnected)
661                    .unwrap();
662
663                state
664                    .audio_output
665                    .play_effect(NotificationEvents::ServerDisconnect);
666                now!(Ok(None))
667            } else {
668                now!(Err(Error::Disconnected))
669            }
670        }
671        Command::ServerStatus { host, port } => ExecutionContext::Ping(
672            Box::new(move || {
673                match (host.as_str(), port)
674                    .to_socket_addrs()
675                    .map(|mut e| e.next())
676                {
677                    Ok(Some(v)) => Ok(v),
678                    _ => Err(Error::InvalidServerAddr(host, port)),
679                }
680            }),
681            Box::new(move |pong| {
682                Ok(pong.map(|pong| CommandResponse::ServerStatus {
683                    version: pong.version,
684                    users: pong.users,
685                    max_users: pong.max_users,
686                    bandwidth: pong.bandwidth,
687                }))
688            }),
689        ),
690        Command::Status => {
691            if let Server::Connected(s) = state.server() {
692                let server_state = mumlib::state::Server::from(s);
693                now!(Ok(Some(CommandResponse::Status { server_state })))
694            } else {
695                now!(Err(Error::Disconnected))
696            }
697        }
698        Command::UserVolumeSet(username, volume) => {
699            if let Server::Connected(s) = state.server() {
700                let user_id = match s
701                    .users()
702                    .iter()
703                    .find(|e| e.1.name() == username)
704                    .map(|e| *e.0)
705                {
706                    None => return now!(Err(Error::InvalidUsername(username))),
707                    Some(v) => v,
708                };
709
710                state.audio_output.set_user_volume(user_id, volume);
711                now!(Ok(None))
712            } else {
713                now!(Err(Error::Disconnected))
714            }
715        }
716        Command::PastMessages { block } => {
717            //does it make sense to wait for messages while not connected?
718            if let Server::Connected(_) = state.server() {
719                if block {
720                    let ref_state = Arc::clone(&og_state);
721                    ExecutionContext::TcpEventSubscriber(
722                        TcpEvent::TextMessage,
723                        Box::new(move |data, sender| {
724                            if let TcpEventData::TextMessage(a) = data {
725                                let message = (
726                                    chrono::Local::now().naive_local(),
727                                    a.get_message().to_owned(),
728                                    ref_state
729                                        .read()
730                                        .unwrap()
731                                        .get_user_name(a.get_actor())
732                                        .unwrap(),
733                                );
734                                sender
735                                    .send(Ok(Some(CommandResponse::PastMessage { message })))
736                                    .is_ok()
737                            } else {
738                                unreachable!("Should only receive a TextMessage data when listening to TextMessage events");
739                            }
740                        }),
741                    )
742                } else {
743                    let messages = std::mem::take(&mut state.message_buffer);
744                    let messages: Vec<_> = messages
745                        .into_iter()
746                        .map(|(timestamp, msg, user)| {
747                            (timestamp, msg, state.get_user_name(user).unwrap())
748                        })
749                        .map(|e| Ok(Some(CommandResponse::PastMessage { message: e })))
750                        .collect();
751
752                    ExecutionContext::Now(Box::new(move || Box::new(messages.into_iter())))
753                }
754            } else {
755                now!(Err(Error::Disconnected))
756            }
757        }
758        Command::SendMessage { message, targets } => {
759            if let Server::Connected(s) = state.server() {
760                let mut msg = msgs::TextMessage::new();
761
762                msg.set_message(message);
763
764                match targets {
765                    MessageTarget::Channel(channels) => {
766                        for (channel, recursive) in channels {
767                            let channel_id = if let ChannelTarget::Named(name) = channel {
768                                let channel = s.channel_name(&name);
769                                match channel {
770                                    Ok(channel) => channel.0,
771                                    Err(e) => {
772                                        return now!(Err(Error::ChannelIdentifierError(name, e)))
773                                    }
774                                }
775                            } else {
776                                s.current_channel().0
777                            };
778
779                            let ids = if recursive {
780                                msg.mut_tree_id()
781                            } else {
782                                msg.mut_channel_id()
783                            };
784                            ids.push(channel_id);
785                        }
786                    }
787                    MessageTarget::User(names) => {
788                        for name in names {
789                            let id = s
790                                .users()
791                                .iter()
792                                .find(|(_, user)| user.name() == name)
793                                .map(|(e, _)| *e);
794
795                            let id = match id {
796                                Some(id) => id,
797                                None => return now!(Err(Error::InvalidUsername(name))),
798                            };
799
800                            msg.mut_session().push(id);
801                        }
802                    }
803                }
804                packet_sender.send(msg.into()).unwrap();
805
806                now!(Ok(None))
807            } else {
808                now!(Err(Error::Disconnected))
809            }
810        }
811    }
812}