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