Skip to main content

io_msgraph/v1/
client.rs

1//! Std-blocking Microsoft Graph client: wraps a `Read + Write` stream
2//! plus the bearer credential and runs the coroutines against
3//! `graph.microsoft.com`. Gated behind the `client` feature.
4
5#[cfg(any(
6    feature = "rustls-aws",
7    feature = "rustls-ring",
8    feature = "native-tls"
9))]
10use core::time::Duration;
11use core::{any::Any, error::Error, fmt};
12
13use alloc::{
14    boxed::Box,
15    string::{String, ToString},
16    vec::Vec,
17};
18use std::io::{self, Read, Write};
19
20use io_http::rfc6750::bearer::HttpAuthBearer;
21#[cfg(any(
22    feature = "rustls-aws",
23    feature = "rustls-ring",
24    feature = "native-tls"
25))]
26use pimalaya_stream::stream::{Stream, TcpConnectOptions, TlsConnectOptions};
27/// TLS backend selection re-exported from pimalaya-stream, feeding
28/// [`MsgraphClientStdConnectOptions::tls`].
29#[cfg(any(
30    feature = "rustls-aws",
31    feature = "rustls-ring",
32    feature = "native-tls"
33))]
34pub use pimalaya_stream::tls::*;
35#[cfg(any(
36    feature = "rustls-aws",
37    feature = "rustls-ring",
38    feature = "native-tls"
39))]
40use url::Url;
41
42#[cfg(any(
43    feature = "rustls-aws",
44    feature = "rustls-ring",
45    feature = "native-tls"
46))]
47use crate::v1::send::MSGRAPH_API_BASE;
48use crate::{
49    coroutine::*,
50    v1::rest::batch::{MsgraphBatch, MsgraphBatchRequest, MsgraphBatchResponses},
51    v1::rest::users::{
52        MsgraphUser,
53        contact_folders::{
54            MsgraphContactFolder,
55            child_folders::MsgraphContactChildFoldersList,
56            create::MsgraphContactFolderCreate,
57            delete::MsgraphContactFolderDelete,
58            get::MsgraphContactFolderGet,
59            list::{
60                MsgraphContactFoldersList, MsgraphContactFoldersListParams,
61                MsgraphContactFoldersListResponse,
62            },
63            update::MsgraphContactFolderUpdate,
64        },
65        contacts::{
66            MsgraphContact,
67            create::MsgraphContactCreate,
68            delete::MsgraphContactDelete,
69            delta::{MsgraphContactsDelta, MsgraphContactsDeltaResponse},
70            get::MsgraphContactGet,
71            list::{MsgraphContactsList, MsgraphContactsListParams, MsgraphContactsListResponse},
72            update::MsgraphContactUpdate,
73        },
74        get::MsgraphUserGet,
75        mail_folders::{
76            MsgraphMailFolder,
77            child_folders::MsgraphMailChildFoldersList,
78            copy::MsgraphMailFolderCopy,
79            create::MsgraphMailFolderCreate,
80            delete::MsgraphMailFolderDelete,
81            get::MsgraphMailFolderGet,
82            list::{
83                MsgraphMailFoldersList, MsgraphMailFoldersListParams,
84                MsgraphMailFoldersListResponse,
85            },
86            r#move::MsgraphMailFolderMove,
87            update::MsgraphMailFolderUpdate,
88        },
89        messages::{
90            MsgraphMessage,
91            attachments::{
92                MsgraphAttachment,
93                create::MsgraphAttachmentCreate,
94                delete::MsgraphAttachmentDelete,
95                get_raw::MsgraphAttachmentGetRaw,
96                list::{MsgraphAttachmentsList, MsgraphAttachmentsListResponse},
97            },
98            copy::MsgraphMessageCopy,
99            create::MsgraphMessageCreate,
100            create_mime::MsgraphMessageCreateMime,
101            delete::MsgraphMessageDelete,
102            delta::{MsgraphMessagesDelta, MsgraphMessagesDeltaResponse},
103            get::MsgraphMessageGet,
104            get_raw::MsgraphMessageGetRaw,
105            list::{MsgraphMessagesList, MsgraphMessagesListParams, MsgraphMessagesListResponse},
106            r#move::MsgraphMessageMove,
107            send::MsgraphMessageSend,
108            update::MsgraphMessageUpdate,
109        },
110        send_mail::{MsgraphMailSend, MsgraphMailSendMime},
111    },
112    v1::send::{MsgraphNoResponse, MsgraphSendError, MsgraphSendOutput},
113};
114
115/// Error returned by [`MsgraphClientStd`] operations.
116#[derive(Debug)]
117pub enum MsgraphClientStdError {
118    /// A coroutine completed with an error.
119    Send(MsgraphSendError),
120    /// Reading from or writing to the stream failed.
121    Io(io::Error),
122    /// Opening the TCP/TLS connection failed.
123    #[cfg(any(
124        feature = "rustls-aws",
125        feature = "rustls-ring",
126        feature = "native-tls"
127    ))]
128    Tls(anyhow::Error),
129    /// The API base URL has no host to connect to.
130    #[cfg(any(
131        feature = "rustls-aws",
132        feature = "rustls-ring",
133        feature = "native-tls"
134    ))]
135    UrlMissingHost(String),
136    /// The API base URL scheme is neither http nor https.
137    #[cfg(any(
138        feature = "rustls-aws",
139        feature = "rustls-ring",
140        feature = "native-tls"
141    ))]
142    UrlUnsupportedScheme {
143        /// The rejected API base URL.
144        url: String,
145        /// The scheme of the rejected URL.
146        scheme: String,
147    },
148}
149
150impl fmt::Display for MsgraphClientStdError {
151    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
152        match self {
153            Self::Send(err) => err.fmt(f),
154            Self::Io(err) => err.fmt(f),
155            #[cfg(any(
156                feature = "rustls-aws",
157                feature = "rustls-ring",
158                feature = "native-tls"
159            ))]
160            Self::Tls(err) => err.fmt(f),
161            #[cfg(any(
162                feature = "rustls-aws",
163                feature = "rustls-ring",
164                feature = "native-tls"
165            ))]
166            Self::UrlMissingHost(url) => write!(f, "Microsoft Graph URL `{url}` has no host"),
167            #[cfg(any(
168                feature = "rustls-aws",
169                feature = "rustls-ring",
170                feature = "native-tls"
171            ))]
172            Self::UrlUnsupportedScheme { url, scheme } => write!(
173                f,
174                "Microsoft Graph URL `{url}` has unsupported scheme `{scheme}` (expected `http` or `https`)"
175            ),
176        }
177    }
178}
179
180impl Error for MsgraphClientStdError {
181    fn source(&self) -> Option<&(dyn Error + 'static)> {
182        match self {
183            Self::Send(err) => err.source(),
184            Self::Io(err) => err.source(),
185            #[cfg(any(
186                feature = "rustls-aws",
187                feature = "rustls-ring",
188                feature = "native-tls"
189            ))]
190            Self::Tls(err) => err.source(),
191            #[cfg(any(
192                feature = "rustls-aws",
193                feature = "rustls-ring",
194                feature = "native-tls"
195            ))]
196            _ => None,
197        }
198    }
199}
200
201impl From<MsgraphSendError> for MsgraphClientStdError {
202    fn from(err: MsgraphSendError) -> Self {
203        Self::Send(err)
204    }
205}
206
207impl From<io::Error> for MsgraphClientStdError {
208    fn from(err: io::Error) -> Self {
209        Self::Io(err)
210    }
211}
212
213#[cfg(any(
214    feature = "rustls-aws",
215    feature = "rustls-ring",
216    feature = "native-tls"
217))]
218impl From<anyhow::Error> for MsgraphClientStdError {
219    fn from(err: anyhow::Error) -> Self {
220        Self::Tls(err)
221    }
222}
223
224/// Optional settings for [`MsgraphClientStd::connect`]; every field has a
225/// default (the TLS backend default, and `me` as the mailbox owner).
226pub struct MsgraphClientStdConnectOptions {
227    /// The TLS backend configuration used to open the connection.
228    #[cfg(any(
229        feature = "rustls-aws",
230        feature = "rustls-ring",
231        feature = "native-tls"
232    ))]
233    pub tls: Tls,
234    /// The mailbox owner: `me`, a user id or a principal name.
235    pub user_id: String,
236}
237
238impl Default for MsgraphClientStdConnectOptions {
239    fn default() -> Self {
240        Self {
241            #[cfg(any(
242                feature = "rustls-aws",
243                feature = "rustls-ring",
244                feature = "native-tls"
245            ))]
246            tls: Tls::default(),
247            user_id: String::from("me"),
248        }
249    }
250}
251
252const READ_BUFFER_SIZE: usize = 16 * 1024;
253
254/// Std blocking Microsoft Graph client: a stream, the bearer
255/// credential and the mailbox owner, with one method per operation.
256pub struct MsgraphClientStd {
257    /// The stream carrying the HTTPS connection to the Graph API.
258    pub stream: Box<dyn MsgraphStream>,
259    /// The bearer credential added to every request.
260    pub auth: HttpAuthBearer,
261    /// The mailbox owner: `me`, a user id or a principal name.
262    pub user_id: String,
263}
264
265impl MsgraphClientStd {
266    /// Builds a client over a caller-managed stream.
267    pub fn new<S: Read + Write + Send + 'static>(
268        stream: S,
269        token: impl ToString,
270        options: MsgraphClientStdConnectOptions,
271    ) -> Self {
272        Self {
273            stream: Box::new(stream),
274            auth: HttpAuthBearer::new(token.to_string()),
275            user_id: options.user_id,
276        }
277    }
278
279    /// Builds a client by opening a TCP/TLS connection to the Graph
280    /// API endpoint through pimalaya-stream.
281    #[cfg(any(
282        feature = "rustls-aws",
283        feature = "rustls-ring",
284        feature = "native-tls"
285    ))]
286    pub fn connect(
287        token: impl ToString,
288        options: MsgraphClientStdConnectOptions,
289    ) -> Result<Self, MsgraphClientStdError> {
290        let MsgraphClientStdConnectOptions { tls, user_id } = options;
291
292        let url = Url::parse(MSGRAPH_API_BASE).expect("Microsoft Graph API base URL is valid");
293        let host = url
294            .host_str()
295            .ok_or_else(|| MsgraphClientStdError::UrlMissingHost(url.to_string()))?;
296
297        let stream = match url.scheme() {
298            "http" => {
299                let port = url.port().unwrap_or(80);
300                let opts = TcpConnectOptions::default();
301                Stream::connect_tcp(host, port, opts)?
302            }
303            "https" => {
304                let port = url.port().unwrap_or(443);
305                let opts = TlsConnectOptions {
306                    tls: tls.clone(),
307                    ..Default::default()
308                };
309
310                Stream::connect_tls(host, port, opts)?
311            }
312            scheme => {
313                return Err(MsgraphClientStdError::UrlUnsupportedScheme {
314                    url: url.to_string(),
315                    scheme: scheme.to_string(),
316                });
317            }
318        };
319
320        stream.set_read_timeout(Some(Duration::from_secs(30)))?;
321
322        Ok(Self {
323            stream: Box::new(stream),
324            auth: HttpAuthBearer::new(token.to_string()),
325            user_id,
326        })
327    }
328
329    /// Replaces the underlying stream (e.g. after a connection reset).
330    pub fn set_stream<S: Read + Write + Send + 'static>(&mut self, stream: S) {
331        self.stream = Box::new(stream);
332    }
333
334    /// Runs the given coroutine to completion against the stream,
335    /// fulfilling its read and write requests.
336    pub fn run<C, T>(
337        &mut self,
338        mut coroutine: C,
339    ) -> Result<MsgraphSendOutput<T>, MsgraphClientStdError>
340    where
341        C: MsgraphCoroutine<
342                Yield = MsgraphYield,
343                Return = Result<MsgraphSendOutput<T>, MsgraphSendError>,
344            >,
345    {
346        let mut buf = [0u8; READ_BUFFER_SIZE];
347        let mut arg: Option<&[u8]> = None;
348
349        loop {
350            match coroutine.resume(arg.take()) {
351                MsgraphCoroutineState::Complete(Ok(out)) => return Ok(out),
352                MsgraphCoroutineState::Complete(Err(err)) => return Err(err.into()),
353                MsgraphCoroutineState::Yielded(MsgraphYield::WantsRead) => {
354                    let n = self.stream.read(&mut buf)?;
355                    arg = Some(&buf[..n]);
356                }
357                MsgraphCoroutineState::Yielded(MsgraphYield::WantsWrite(bytes)) => {
358                    self.stream.write_all(&bytes)?;
359                    arg = None;
360                }
361            }
362        }
363    }
364
365    /// Sends several requests in one HTTP call.
366    pub fn batch(
367        &mut self,
368        requests: &[MsgraphBatchRequest],
369    ) -> Result<MsgraphSendOutput<MsgraphBatchResponses>, MsgraphClientStdError> {
370        let coroutine = MsgraphBatch::new(&self.auth, requests)?;
371        self.run(coroutine)
372    }
373
374    /// Gets the profile of the mailbox owner.
375    pub fn me(&mut self) -> Result<MsgraphSendOutput<MsgraphUser>, MsgraphClientStdError> {
376        let coroutine = MsgraphUserGet::new(&self.auth, &self.user_id)?;
377        self.run(coroutine)
378    }
379
380    /// Lists the mail folders of the mailbox.
381    pub fn mail_folders_list(
382        &mut self,
383        params: &MsgraphMailFoldersListParams,
384    ) -> Result<MsgraphSendOutput<MsgraphMailFoldersListResponse>, MsgraphClientStdError> {
385        let coroutine = MsgraphMailFoldersList::new(&self.auth, &self.user_id, params)?;
386        self.run(coroutine)
387    }
388
389    /// Gets a mail folder by id.
390    pub fn mail_folder_get(
391        &mut self,
392        id: &str,
393    ) -> Result<MsgraphSendOutput<MsgraphMailFolder>, MsgraphClientStdError> {
394        let coroutine = MsgraphMailFolderGet::new(&self.auth, &self.user_id, id)?;
395        self.run(coroutine)
396    }
397
398    /// Creates a mail folder.
399    pub fn mail_folder_create(
400        &mut self,
401        folder: &MsgraphMailFolder,
402    ) -> Result<MsgraphSendOutput<MsgraphMailFolder>, MsgraphClientStdError> {
403        let coroutine = MsgraphMailFolderCreate::new(&self.auth, &self.user_id, folder)?;
404        self.run(coroutine)
405    }
406
407    /// Updates a mail folder by id.
408    pub fn mail_folder_update(
409        &mut self,
410        id: &str,
411        folder: &MsgraphMailFolder,
412    ) -> Result<MsgraphSendOutput<MsgraphMailFolder>, MsgraphClientStdError> {
413        let coroutine = MsgraphMailFolderUpdate::new(&self.auth, &self.user_id, id, folder)?;
414        self.run(coroutine)
415    }
416
417    /// Deletes a mail folder by id.
418    pub fn mail_folder_delete(
419        &mut self,
420        id: &str,
421    ) -> Result<MsgraphSendOutput<MsgraphNoResponse>, MsgraphClientStdError> {
422        let coroutine = MsgraphMailFolderDelete::new(&self.auth, &self.user_id, id)?;
423        self.run(coroutine)
424    }
425
426    /// Copies a mail folder into a destination folder.
427    pub fn mail_folder_copy(
428        &mut self,
429        id: &str,
430        destination: &str,
431    ) -> Result<MsgraphSendOutput<MsgraphMailFolder>, MsgraphClientStdError> {
432        let coroutine = MsgraphMailFolderCopy::new(&self.auth, &self.user_id, id, destination)?;
433        self.run(coroutine)
434    }
435
436    /// Moves a mail folder into a destination folder.
437    pub fn mail_folder_move(
438        &mut self,
439        id: &str,
440        destination: &str,
441    ) -> Result<MsgraphSendOutput<MsgraphMailFolder>, MsgraphClientStdError> {
442        let coroutine = MsgraphMailFolderMove::new(&self.auth, &self.user_id, id, destination)?;
443        self.run(coroutine)
444    }
445
446    /// Lists the child folders of a mail folder.
447    pub fn mail_child_folders_list(
448        &mut self,
449        id: &str,
450        params: &MsgraphMailFoldersListParams,
451    ) -> Result<MsgraphSendOutput<MsgraphMailFoldersListResponse>, MsgraphClientStdError> {
452        let coroutine = MsgraphMailChildFoldersList::new(&self.auth, &self.user_id, id, params)?;
453        self.run(coroutine)
454    }
455
456    /// Lists the contact folders of the mailbox.
457    pub fn contact_folders_list(
458        &mut self,
459        params: &MsgraphContactFoldersListParams,
460    ) -> Result<MsgraphSendOutput<MsgraphContactFoldersListResponse>, MsgraphClientStdError> {
461        let coroutine = MsgraphContactFoldersList::new(&self.auth, &self.user_id, params)?;
462        self.run(coroutine)
463    }
464
465    /// Gets a contact folder by id.
466    pub fn contact_folder_get(
467        &mut self,
468        id: &str,
469    ) -> Result<MsgraphSendOutput<MsgraphContactFolder>, MsgraphClientStdError> {
470        let coroutine = MsgraphContactFolderGet::new(&self.auth, &self.user_id, id)?;
471        self.run(coroutine)
472    }
473
474    /// Creates a contact folder.
475    pub fn contact_folder_create(
476        &mut self,
477        folder: &MsgraphContactFolder,
478    ) -> Result<MsgraphSendOutput<MsgraphContactFolder>, MsgraphClientStdError> {
479        let coroutine = MsgraphContactFolderCreate::new(&self.auth, &self.user_id, folder)?;
480        self.run(coroutine)
481    }
482
483    /// Updates a contact folder by id.
484    pub fn contact_folder_update(
485        &mut self,
486        id: &str,
487        folder: &MsgraphContactFolder,
488    ) -> Result<MsgraphSendOutput<MsgraphContactFolder>, MsgraphClientStdError> {
489        let coroutine = MsgraphContactFolderUpdate::new(&self.auth, &self.user_id, id, folder)?;
490        self.run(coroutine)
491    }
492
493    /// Deletes a contact folder by id.
494    pub fn contact_folder_delete(
495        &mut self,
496        id: &str,
497    ) -> Result<MsgraphSendOutput<MsgraphNoResponse>, MsgraphClientStdError> {
498        let coroutine = MsgraphContactFolderDelete::new(&self.auth, &self.user_id, id)?;
499        self.run(coroutine)
500    }
501
502    /// Lists the child folders of a contact folder.
503    pub fn contact_child_folders_list(
504        &mut self,
505        id: &str,
506        params: &MsgraphContactFoldersListParams,
507    ) -> Result<MsgraphSendOutput<MsgraphContactFoldersListResponse>, MsgraphClientStdError> {
508        let coroutine = MsgraphContactChildFoldersList::new(&self.auth, &self.user_id, id, params)?;
509        self.run(coroutine)
510    }
511
512    /// Lists the contacts of the default Contacts folder, or of the
513    /// given contact folder.
514    pub fn contacts_list(
515        &mut self,
516        folder: Option<&str>,
517        params: &MsgraphContactsListParams,
518    ) -> Result<MsgraphSendOutput<MsgraphContactsListResponse>, MsgraphClientStdError> {
519        let coroutine = MsgraphContactsList::new(&self.auth, &self.user_id, folder, params)?;
520        self.run(coroutine)
521    }
522
523    /// Gets a contact by id, optionally expanding the given relations.
524    pub fn contact_get(
525        &mut self,
526        id: &str,
527        expand: Option<&str>,
528    ) -> Result<MsgraphSendOutput<MsgraphContact>, MsgraphClientStdError> {
529        let coroutine = MsgraphContactGet::new(&self.auth, &self.user_id, id, expand)?;
530        self.run(coroutine)
531    }
532
533    /// Creates a contact in the default Contacts folder, or in the
534    /// given contact folder.
535    pub fn contact_create(
536        &mut self,
537        folder: Option<&str>,
538        contact: &MsgraphContact,
539    ) -> Result<MsgraphSendOutput<MsgraphContact>, MsgraphClientStdError> {
540        let coroutine = MsgraphContactCreate::new(&self.auth, &self.user_id, folder, contact)?;
541        self.run(coroutine)
542    }
543
544    /// Updates a contact by id.
545    pub fn contact_update(
546        &mut self,
547        id: &str,
548        contact: &MsgraphContact,
549    ) -> Result<MsgraphSendOutput<MsgraphContact>, MsgraphClientStdError> {
550        let coroutine = MsgraphContactUpdate::new(&self.auth, &self.user_id, id, contact)?;
551        self.run(coroutine)
552    }
553
554    /// Deletes a contact by id.
555    pub fn contact_delete(
556        &mut self,
557        id: &str,
558    ) -> Result<MsgraphSendOutput<MsgraphNoResponse>, MsgraphClientStdError> {
559        let coroutine = MsgraphContactDelete::new(&self.auth, &self.user_id, id)?;
560        self.run(coroutine)
561    }
562
563    /// Starts a contacts delta round over the default Contacts folder,
564    /// or over the given contact folder.
565    pub fn contacts_delta(
566        &mut self,
567        folder: Option<&str>,
568        select: Option<&str>,
569    ) -> Result<MsgraphSendOutput<MsgraphContactsDeltaResponse>, MsgraphClientStdError> {
570        let coroutine = MsgraphContactsDelta::new(&self.auth, &self.user_id, folder, select)?;
571        self.run(coroutine)
572    }
573
574    /// Continues a contacts delta round from an `@odata.nextLink`, or
575    /// starts the next round from a saved `@odata.deltaLink`.
576    pub fn contacts_delta_from_link(
577        &mut self,
578        link: &str,
579    ) -> Result<MsgraphSendOutput<MsgraphContactsDeltaResponse>, MsgraphClientStdError> {
580        let coroutine = MsgraphContactsDelta::from_link(&self.auth, link)?;
581        self.run(coroutine)
582    }
583
584    /// Lists the messages of the whole mailbox, or of the given mail
585    /// folder.
586    pub fn messages_list(
587        &mut self,
588        folder: Option<&str>,
589        params: &MsgraphMessagesListParams,
590    ) -> Result<MsgraphSendOutput<MsgraphMessagesListResponse>, MsgraphClientStdError> {
591        let coroutine = MsgraphMessagesList::new(&self.auth, &self.user_id, folder, params)?;
592        self.run(coroutine)
593    }
594
595    /// Gets a message by id.
596    pub fn message_get(
597        &mut self,
598        id: &str,
599    ) -> Result<MsgraphSendOutput<MsgraphMessage>, MsgraphClientStdError> {
600        let coroutine = MsgraphMessageGet::new(&self.auth, &self.user_id, id)?;
601        self.run(coroutine)
602    }
603
604    /// Gets the raw RFC 5322 MIME content of a message by id.
605    pub fn message_get_raw(
606        &mut self,
607        id: &str,
608    ) -> Result<MsgraphSendOutput<Vec<u8>>, MsgraphClientStdError> {
609        let coroutine = MsgraphMessageGetRaw::new(&self.auth, &self.user_id, id)?;
610        self.run(coroutine)
611    }
612
613    /// Creates a draft message from JSON in the Drafts folder, or in
614    /// the given mail folder.
615    pub fn message_create(
616        &mut self,
617        folder: Option<&str>,
618        message: &MsgraphMessage,
619    ) -> Result<MsgraphSendOutput<MsgraphMessage>, MsgraphClientStdError> {
620        let coroutine = MsgraphMessageCreate::new(&self.auth, &self.user_id, folder, message)?;
621        self.run(coroutine)
622    }
623
624    /// Creates a draft message from raw RFC 5322 MIME bytes in the
625    /// Drafts folder, or in the given mail folder.
626    pub fn message_create_mime(
627        &mut self,
628        folder: Option<&str>,
629        raw: &[u8],
630    ) -> Result<MsgraphSendOutput<MsgraphMessage>, MsgraphClientStdError> {
631        let coroutine = MsgraphMessageCreateMime::new(&self.auth, &self.user_id, folder, raw)?;
632        self.run(coroutine)
633    }
634
635    /// Updates a message by id.
636    pub fn message_update(
637        &mut self,
638        id: &str,
639        message: &MsgraphMessage,
640    ) -> Result<MsgraphSendOutput<MsgraphMessage>, MsgraphClientStdError> {
641        let coroutine = MsgraphMessageUpdate::new(&self.auth, &self.user_id, id, message)?;
642        self.run(coroutine)
643    }
644
645    /// Deletes a message by id.
646    pub fn message_delete(
647        &mut self,
648        id: &str,
649    ) -> Result<MsgraphSendOutput<MsgraphNoResponse>, MsgraphClientStdError> {
650        let coroutine = MsgraphMessageDelete::new(&self.auth, &self.user_id, id)?;
651        self.run(coroutine)
652    }
653
654    /// Moves a message into a destination folder.
655    pub fn message_move(
656        &mut self,
657        id: &str,
658        destination: &str,
659    ) -> Result<MsgraphSendOutput<MsgraphMessage>, MsgraphClientStdError> {
660        let coroutine = MsgraphMessageMove::new(&self.auth, &self.user_id, id, destination)?;
661        self.run(coroutine)
662    }
663
664    /// Copies a message into a destination folder.
665    pub fn message_copy(
666        &mut self,
667        id: &str,
668        destination: &str,
669    ) -> Result<MsgraphSendOutput<MsgraphMessage>, MsgraphClientStdError> {
670        let coroutine = MsgraphMessageCopy::new(&self.auth, &self.user_id, id, destination)?;
671        self.run(coroutine)
672    }
673
674    /// Starts a messages delta round over the whole mailbox, or over
675    /// the given mail folder.
676    pub fn messages_delta(
677        &mut self,
678        folder: Option<&str>,
679        select: Option<&str>,
680    ) -> Result<MsgraphSendOutput<MsgraphMessagesDeltaResponse>, MsgraphClientStdError> {
681        let coroutine = MsgraphMessagesDelta::new(&self.auth, &self.user_id, folder, select)?;
682        self.run(coroutine)
683    }
684
685    /// Continues a messages delta round from an `@odata.nextLink`, or
686    /// starts the next round from a saved `@odata.deltaLink`.
687    pub fn messages_delta_from_link(
688        &mut self,
689        link: &str,
690    ) -> Result<MsgraphSendOutput<MsgraphMessagesDeltaResponse>, MsgraphClientStdError> {
691        let coroutine = MsgraphMessagesDelta::from_link(&self.auth, link)?;
692        self.run(coroutine)
693    }
694
695    /// Creates a file attachment on a message.
696    pub fn attachment_create(
697        &mut self,
698        message_id: &str,
699        name: &str,
700        content: &[u8],
701        content_type: Option<&str>,
702    ) -> Result<MsgraphSendOutput<MsgraphAttachment>, MsgraphClientStdError> {
703        let coroutine = MsgraphAttachmentCreate::new(
704            &self.auth,
705            &self.user_id,
706            message_id,
707            name,
708            content,
709            content_type,
710        )?;
711        self.run(coroutine)
712    }
713
714    /// Lists the attachments of a message.
715    pub fn attachments_list(
716        &mut self,
717        message_id: &str,
718    ) -> Result<MsgraphSendOutput<MsgraphAttachmentsListResponse>, MsgraphClientStdError> {
719        let coroutine = MsgraphAttachmentsList::new(&self.auth, &self.user_id, message_id)?;
720        self.run(coroutine)
721    }
722
723    /// Gets the raw content of an attachment.
724    pub fn attachment_get_raw(
725        &mut self,
726        message_id: &str,
727        attachment_id: &str,
728    ) -> Result<MsgraphSendOutput<Vec<u8>>, MsgraphClientStdError> {
729        let coroutine =
730            MsgraphAttachmentGetRaw::new(&self.auth, &self.user_id, message_id, attachment_id)?;
731        self.run(coroutine)
732    }
733
734    /// Deletes an attachment of a message.
735    pub fn attachment_delete(
736        &mut self,
737        message_id: &str,
738        attachment_id: &str,
739    ) -> Result<MsgraphSendOutput<MsgraphNoResponse>, MsgraphClientStdError> {
740        let coroutine =
741            MsgraphAttachmentDelete::new(&self.auth, &self.user_id, message_id, attachment_id)?;
742        self.run(coroutine)
743    }
744
745    /// Sends an existing draft message by id.
746    pub fn message_send(
747        &mut self,
748        id: &str,
749    ) -> Result<MsgraphSendOutput<MsgraphNoResponse>, MsgraphClientStdError> {
750        let coroutine = MsgraphMessageSend::new(&self.auth, &self.user_id, id)?;
751        self.run(coroutine)
752    }
753
754    /// Sends a message described as JSON through the sendMail action.
755    pub fn mail_send(
756        &mut self,
757        message: &MsgraphMessage,
758        save_to_sent_items: bool,
759    ) -> Result<MsgraphSendOutput<MsgraphNoResponse>, MsgraphClientStdError> {
760        let coroutine =
761            MsgraphMailSend::new(&self.auth, &self.user_id, message, save_to_sent_items)?;
762        self.run(coroutine)
763    }
764
765    /// Sends a message given as raw RFC 5322 MIME bytes through the
766    /// sendMail action.
767    pub fn mail_send_mime(
768        &mut self,
769        raw: &[u8],
770    ) -> Result<MsgraphSendOutput<MsgraphNoResponse>, MsgraphClientStdError> {
771        let coroutine = MsgraphMailSendMime::new(&self.auth, &self.user_id, raw)?;
772        self.run(coroutine)
773    }
774}
775
776impl fmt::Debug for MsgraphClientStd {
777    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
778        f.debug_struct("MsgraphClientStd")
779            .field("auth", &self.auth)
780            .field("user_id", &self.user_id)
781            .finish_non_exhaustive()
782    }
783}
784
785/// Blocking stream the client runs over, downcastable through `Any`
786/// (e.g. to recover a concrete TLS stream).
787pub trait MsgraphStream: Read + Write + Send + Any {
788    /// The stream as a mutable `Any`, ready for downcasting.
789    fn as_any_mut(&mut self) -> &mut dyn Any;
790}
791
792impl<T: Read + Write + Send + Any> MsgraphStream for T {
793    fn as_any_mut(&mut self) -> &mut dyn Any {
794        self
795    }
796}