1#[cfg(any(
6 feature = "rustls-aws",
7 feature = "rustls-ring",
8 feature = "native-tls"
9))]
10use core::time::Duration;
11use core::{any::Any, 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#[cfg(any(
30 feature = "rustls-aws",
31 feature = "rustls-ring",
32 feature = "native-tls"
33))]
34pub use pimalaya_stream::tls::*;
35use thiserror::Error;
36#[cfg(any(
37 feature = "rustls-aws",
38 feature = "rustls-ring",
39 feature = "native-tls"
40))]
41use url::Url;
42
43#[cfg(any(
44 feature = "rustls-aws",
45 feature = "rustls-ring",
46 feature = "native-tls"
47))]
48use crate::v1::send::MSGRAPH_API_BASE;
49use crate::{
50 coroutine::*,
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#[derive(Debug, Error)]
117pub enum MsgraphClientStdError {
118 #[error(transparent)]
120 Send(#[from] MsgraphSendError),
121 #[error(transparent)]
123 Io(#[from] io::Error),
124 #[cfg(any(
126 feature = "rustls-aws",
127 feature = "rustls-ring",
128 feature = "native-tls"
129 ))]
130 #[error(transparent)]
131 Tls(#[from] anyhow::Error),
132 #[cfg(any(
134 feature = "rustls-aws",
135 feature = "rustls-ring",
136 feature = "native-tls"
137 ))]
138 #[error("Microsoft Graph URL `{0}` has no host")]
139 UrlMissingHost(String),
140 #[cfg(any(
142 feature = "rustls-aws",
143 feature = "rustls-ring",
144 feature = "native-tls"
145 ))]
146 #[error(
147 "Microsoft Graph URL `{url}` has unsupported scheme `{scheme}` (expected `http` or `https`)"
148 )]
149 UrlUnsupportedScheme {
150 url: String,
152 scheme: String,
154 },
155}
156
157pub struct MsgraphClientStdConnectOptions {
160 #[cfg(any(
162 feature = "rustls-aws",
163 feature = "rustls-ring",
164 feature = "native-tls"
165 ))]
166 pub tls: Tls,
167 pub user_id: String,
169}
170
171impl Default for MsgraphClientStdConnectOptions {
172 fn default() -> Self {
173 Self {
174 #[cfg(any(
175 feature = "rustls-aws",
176 feature = "rustls-ring",
177 feature = "native-tls"
178 ))]
179 tls: Tls::default(),
180 user_id: String::from("me"),
181 }
182 }
183}
184
185const READ_BUFFER_SIZE: usize = 16 * 1024;
186
187pub struct MsgraphClientStd {
190 pub stream: Box<dyn MsgraphStream>,
192 pub auth: HttpAuthBearer,
194 pub user_id: String,
196}
197
198impl MsgraphClientStd {
199 pub fn new<S: Read + Write + Send + 'static>(
201 stream: S,
202 token: impl ToString,
203 options: MsgraphClientStdConnectOptions,
204 ) -> Self {
205 Self {
206 stream: Box::new(stream),
207 auth: HttpAuthBearer::new(token.to_string()),
208 user_id: options.user_id,
209 }
210 }
211
212 #[cfg(any(
215 feature = "rustls-aws",
216 feature = "rustls-ring",
217 feature = "native-tls"
218 ))]
219 pub fn connect(
220 token: impl ToString,
221 options: MsgraphClientStdConnectOptions,
222 ) -> Result<Self, MsgraphClientStdError> {
223 let MsgraphClientStdConnectOptions { tls, user_id } = options;
224
225 let url = Url::parse(MSGRAPH_API_BASE).expect("Microsoft Graph API base URL is valid");
226 let host = url
227 .host_str()
228 .ok_or_else(|| MsgraphClientStdError::UrlMissingHost(url.to_string()))?;
229
230 let stream = match url.scheme() {
231 "http" => {
232 let port = url.port().unwrap_or(80);
233 let opts = TcpConnectOptions::default();
234 Stream::connect_tcp(host, port, opts)?
235 }
236 "https" => {
237 let port = url.port().unwrap_or(443);
238 let opts = TlsConnectOptions {
239 tls: tls.clone(),
240 ..Default::default()
241 };
242
243 Stream::connect_tls(host, port, opts)?
244 }
245 scheme => {
246 return Err(MsgraphClientStdError::UrlUnsupportedScheme {
247 url: url.to_string(),
248 scheme: scheme.to_string(),
249 });
250 }
251 };
252
253 stream.set_read_timeout(Some(Duration::from_secs(30)))?;
254
255 Ok(Self {
256 stream: Box::new(stream),
257 auth: HttpAuthBearer::new(token.to_string()),
258 user_id,
259 })
260 }
261
262 pub fn set_stream<S: Read + Write + Send + 'static>(&mut self, stream: S) {
264 self.stream = Box::new(stream);
265 }
266
267 pub fn run<C, T>(
270 &mut self,
271 mut coroutine: C,
272 ) -> Result<MsgraphSendOutput<T>, MsgraphClientStdError>
273 where
274 C: MsgraphCoroutine<
275 Yield = MsgraphYield,
276 Return = Result<MsgraphSendOutput<T>, MsgraphSendError>,
277 >,
278 {
279 let mut buf = [0u8; READ_BUFFER_SIZE];
280 let mut arg: Option<&[u8]> = None;
281
282 loop {
283 match coroutine.resume(arg.take()) {
284 MsgraphCoroutineState::Complete(Ok(out)) => return Ok(out),
285 MsgraphCoroutineState::Complete(Err(err)) => return Err(err.into()),
286 MsgraphCoroutineState::Yielded(MsgraphYield::WantsRead) => {
287 let n = self.stream.read(&mut buf)?;
288 arg = Some(&buf[..n]);
289 }
290 MsgraphCoroutineState::Yielded(MsgraphYield::WantsWrite(bytes)) => {
291 self.stream.write_all(&bytes)?;
292 arg = None;
293 }
294 }
295 }
296 }
297
298 pub fn me(&mut self) -> Result<MsgraphSendOutput<MsgraphUser>, MsgraphClientStdError> {
300 let coroutine = MsgraphUserGet::new(&self.auth, &self.user_id)?;
301 self.run(coroutine)
302 }
303
304 pub fn mail_folders_list(
306 &mut self,
307 params: &MsgraphMailFoldersListParams,
308 ) -> Result<MsgraphSendOutput<MsgraphMailFoldersListResponse>, MsgraphClientStdError> {
309 let coroutine = MsgraphMailFoldersList::new(&self.auth, &self.user_id, params)?;
310 self.run(coroutine)
311 }
312
313 pub fn mail_folder_get(
315 &mut self,
316 id: &str,
317 ) -> Result<MsgraphSendOutput<MsgraphMailFolder>, MsgraphClientStdError> {
318 let coroutine = MsgraphMailFolderGet::new(&self.auth, &self.user_id, id)?;
319 self.run(coroutine)
320 }
321
322 pub fn mail_folder_create(
324 &mut self,
325 folder: &MsgraphMailFolder,
326 ) -> Result<MsgraphSendOutput<MsgraphMailFolder>, MsgraphClientStdError> {
327 let coroutine = MsgraphMailFolderCreate::new(&self.auth, &self.user_id, folder)?;
328 self.run(coroutine)
329 }
330
331 pub fn mail_folder_update(
333 &mut self,
334 id: &str,
335 folder: &MsgraphMailFolder,
336 ) -> Result<MsgraphSendOutput<MsgraphMailFolder>, MsgraphClientStdError> {
337 let coroutine = MsgraphMailFolderUpdate::new(&self.auth, &self.user_id, id, folder)?;
338 self.run(coroutine)
339 }
340
341 pub fn mail_folder_delete(
343 &mut self,
344 id: &str,
345 ) -> Result<MsgraphSendOutput<MsgraphNoResponse>, MsgraphClientStdError> {
346 let coroutine = MsgraphMailFolderDelete::new(&self.auth, &self.user_id, id)?;
347 self.run(coroutine)
348 }
349
350 pub fn mail_folder_copy(
352 &mut self,
353 id: &str,
354 destination: &str,
355 ) -> Result<MsgraphSendOutput<MsgraphMailFolder>, MsgraphClientStdError> {
356 let coroutine = MsgraphMailFolderCopy::new(&self.auth, &self.user_id, id, destination)?;
357 self.run(coroutine)
358 }
359
360 pub fn mail_folder_move(
362 &mut self,
363 id: &str,
364 destination: &str,
365 ) -> Result<MsgraphSendOutput<MsgraphMailFolder>, MsgraphClientStdError> {
366 let coroutine = MsgraphMailFolderMove::new(&self.auth, &self.user_id, id, destination)?;
367 self.run(coroutine)
368 }
369
370 pub fn mail_child_folders_list(
372 &mut self,
373 id: &str,
374 params: &MsgraphMailFoldersListParams,
375 ) -> Result<MsgraphSendOutput<MsgraphMailFoldersListResponse>, MsgraphClientStdError> {
376 let coroutine = MsgraphMailChildFoldersList::new(&self.auth, &self.user_id, id, params)?;
377 self.run(coroutine)
378 }
379
380 pub fn contact_folders_list(
382 &mut self,
383 params: &MsgraphContactFoldersListParams,
384 ) -> Result<MsgraphSendOutput<MsgraphContactFoldersListResponse>, MsgraphClientStdError> {
385 let coroutine = MsgraphContactFoldersList::new(&self.auth, &self.user_id, params)?;
386 self.run(coroutine)
387 }
388
389 pub fn contact_folder_get(
391 &mut self,
392 id: &str,
393 ) -> Result<MsgraphSendOutput<MsgraphContactFolder>, MsgraphClientStdError> {
394 let coroutine = MsgraphContactFolderGet::new(&self.auth, &self.user_id, id)?;
395 self.run(coroutine)
396 }
397
398 pub fn contact_folder_create(
400 &mut self,
401 folder: &MsgraphContactFolder,
402 ) -> Result<MsgraphSendOutput<MsgraphContactFolder>, MsgraphClientStdError> {
403 let coroutine = MsgraphContactFolderCreate::new(&self.auth, &self.user_id, folder)?;
404 self.run(coroutine)
405 }
406
407 pub fn contact_folder_update(
409 &mut self,
410 id: &str,
411 folder: &MsgraphContactFolder,
412 ) -> Result<MsgraphSendOutput<MsgraphContactFolder>, MsgraphClientStdError> {
413 let coroutine = MsgraphContactFolderUpdate::new(&self.auth, &self.user_id, id, folder)?;
414 self.run(coroutine)
415 }
416
417 pub fn contact_folder_delete(
419 &mut self,
420 id: &str,
421 ) -> Result<MsgraphSendOutput<MsgraphNoResponse>, MsgraphClientStdError> {
422 let coroutine = MsgraphContactFolderDelete::new(&self.auth, &self.user_id, id)?;
423 self.run(coroutine)
424 }
425
426 pub fn contact_child_folders_list(
428 &mut self,
429 id: &str,
430 params: &MsgraphContactFoldersListParams,
431 ) -> Result<MsgraphSendOutput<MsgraphContactFoldersListResponse>, MsgraphClientStdError> {
432 let coroutine = MsgraphContactChildFoldersList::new(&self.auth, &self.user_id, id, params)?;
433 self.run(coroutine)
434 }
435
436 pub fn contacts_list(
439 &mut self,
440 folder: Option<&str>,
441 params: &MsgraphContactsListParams,
442 ) -> Result<MsgraphSendOutput<MsgraphContactsListResponse>, MsgraphClientStdError> {
443 let coroutine = MsgraphContactsList::new(&self.auth, &self.user_id, folder, params)?;
444 self.run(coroutine)
445 }
446
447 pub fn contact_get(
449 &mut self,
450 id: &str,
451 expand: Option<&str>,
452 ) -> Result<MsgraphSendOutput<MsgraphContact>, MsgraphClientStdError> {
453 let coroutine = MsgraphContactGet::new(&self.auth, &self.user_id, id, expand)?;
454 self.run(coroutine)
455 }
456
457 pub fn contact_create(
460 &mut self,
461 folder: Option<&str>,
462 contact: &MsgraphContact,
463 ) -> Result<MsgraphSendOutput<MsgraphContact>, MsgraphClientStdError> {
464 let coroutine = MsgraphContactCreate::new(&self.auth, &self.user_id, folder, contact)?;
465 self.run(coroutine)
466 }
467
468 pub fn contact_update(
470 &mut self,
471 id: &str,
472 contact: &MsgraphContact,
473 ) -> Result<MsgraphSendOutput<MsgraphContact>, MsgraphClientStdError> {
474 let coroutine = MsgraphContactUpdate::new(&self.auth, &self.user_id, id, contact)?;
475 self.run(coroutine)
476 }
477
478 pub fn contact_delete(
480 &mut self,
481 id: &str,
482 ) -> Result<MsgraphSendOutput<MsgraphNoResponse>, MsgraphClientStdError> {
483 let coroutine = MsgraphContactDelete::new(&self.auth, &self.user_id, id)?;
484 self.run(coroutine)
485 }
486
487 pub fn contacts_delta(
490 &mut self,
491 folder: Option<&str>,
492 select: Option<&str>,
493 ) -> Result<MsgraphSendOutput<MsgraphContactsDeltaResponse>, MsgraphClientStdError> {
494 let coroutine = MsgraphContactsDelta::new(&self.auth, &self.user_id, folder, select)?;
495 self.run(coroutine)
496 }
497
498 pub fn contacts_delta_from_link(
501 &mut self,
502 link: &str,
503 ) -> Result<MsgraphSendOutput<MsgraphContactsDeltaResponse>, MsgraphClientStdError> {
504 let coroutine = MsgraphContactsDelta::from_link(&self.auth, link)?;
505 self.run(coroutine)
506 }
507
508 pub fn messages_list(
511 &mut self,
512 folder: Option<&str>,
513 params: &MsgraphMessagesListParams,
514 ) -> Result<MsgraphSendOutput<MsgraphMessagesListResponse>, MsgraphClientStdError> {
515 let coroutine = MsgraphMessagesList::new(&self.auth, &self.user_id, folder, params)?;
516 self.run(coroutine)
517 }
518
519 pub fn message_get(
521 &mut self,
522 id: &str,
523 ) -> Result<MsgraphSendOutput<MsgraphMessage>, MsgraphClientStdError> {
524 let coroutine = MsgraphMessageGet::new(&self.auth, &self.user_id, id)?;
525 self.run(coroutine)
526 }
527
528 pub fn message_get_raw(
530 &mut self,
531 id: &str,
532 ) -> Result<MsgraphSendOutput<Vec<u8>>, MsgraphClientStdError> {
533 let coroutine = MsgraphMessageGetRaw::new(&self.auth, &self.user_id, id)?;
534 self.run(coroutine)
535 }
536
537 pub fn message_create(
540 &mut self,
541 folder: Option<&str>,
542 message: &MsgraphMessage,
543 ) -> Result<MsgraphSendOutput<MsgraphMessage>, MsgraphClientStdError> {
544 let coroutine = MsgraphMessageCreate::new(&self.auth, &self.user_id, folder, message)?;
545 self.run(coroutine)
546 }
547
548 pub fn message_create_mime(
551 &mut self,
552 folder: Option<&str>,
553 raw: &[u8],
554 ) -> Result<MsgraphSendOutput<MsgraphMessage>, MsgraphClientStdError> {
555 let coroutine = MsgraphMessageCreateMime::new(&self.auth, &self.user_id, folder, raw)?;
556 self.run(coroutine)
557 }
558
559 pub fn message_update(
561 &mut self,
562 id: &str,
563 message: &MsgraphMessage,
564 ) -> Result<MsgraphSendOutput<MsgraphMessage>, MsgraphClientStdError> {
565 let coroutine = MsgraphMessageUpdate::new(&self.auth, &self.user_id, id, message)?;
566 self.run(coroutine)
567 }
568
569 pub fn message_delete(
571 &mut self,
572 id: &str,
573 ) -> Result<MsgraphSendOutput<MsgraphNoResponse>, MsgraphClientStdError> {
574 let coroutine = MsgraphMessageDelete::new(&self.auth, &self.user_id, id)?;
575 self.run(coroutine)
576 }
577
578 pub fn message_move(
580 &mut self,
581 id: &str,
582 destination: &str,
583 ) -> Result<MsgraphSendOutput<MsgraphMessage>, MsgraphClientStdError> {
584 let coroutine = MsgraphMessageMove::new(&self.auth, &self.user_id, id, destination)?;
585 self.run(coroutine)
586 }
587
588 pub fn message_copy(
590 &mut self,
591 id: &str,
592 destination: &str,
593 ) -> Result<MsgraphSendOutput<MsgraphMessage>, MsgraphClientStdError> {
594 let coroutine = MsgraphMessageCopy::new(&self.auth, &self.user_id, id, destination)?;
595 self.run(coroutine)
596 }
597
598 pub fn messages_delta(
601 &mut self,
602 folder: Option<&str>,
603 select: Option<&str>,
604 ) -> Result<MsgraphSendOutput<MsgraphMessagesDeltaResponse>, MsgraphClientStdError> {
605 let coroutine = MsgraphMessagesDelta::new(&self.auth, &self.user_id, folder, select)?;
606 self.run(coroutine)
607 }
608
609 pub fn messages_delta_from_link(
612 &mut self,
613 link: &str,
614 ) -> Result<MsgraphSendOutput<MsgraphMessagesDeltaResponse>, MsgraphClientStdError> {
615 let coroutine = MsgraphMessagesDelta::from_link(&self.auth, link)?;
616 self.run(coroutine)
617 }
618
619 pub fn attachment_create(
621 &mut self,
622 message_id: &str,
623 name: &str,
624 content: &[u8],
625 content_type: Option<&str>,
626 ) -> Result<MsgraphSendOutput<MsgraphAttachment>, MsgraphClientStdError> {
627 let coroutine = MsgraphAttachmentCreate::new(
628 &self.auth,
629 &self.user_id,
630 message_id,
631 name,
632 content,
633 content_type,
634 )?;
635 self.run(coroutine)
636 }
637
638 pub fn attachments_list(
640 &mut self,
641 message_id: &str,
642 ) -> Result<MsgraphSendOutput<MsgraphAttachmentsListResponse>, MsgraphClientStdError> {
643 let coroutine = MsgraphAttachmentsList::new(&self.auth, &self.user_id, message_id)?;
644 self.run(coroutine)
645 }
646
647 pub fn attachment_get_raw(
649 &mut self,
650 message_id: &str,
651 attachment_id: &str,
652 ) -> Result<MsgraphSendOutput<Vec<u8>>, MsgraphClientStdError> {
653 let coroutine =
654 MsgraphAttachmentGetRaw::new(&self.auth, &self.user_id, message_id, attachment_id)?;
655 self.run(coroutine)
656 }
657
658 pub fn attachment_delete(
660 &mut self,
661 message_id: &str,
662 attachment_id: &str,
663 ) -> Result<MsgraphSendOutput<MsgraphNoResponse>, MsgraphClientStdError> {
664 let coroutine =
665 MsgraphAttachmentDelete::new(&self.auth, &self.user_id, message_id, attachment_id)?;
666 self.run(coroutine)
667 }
668
669 pub fn message_send(
671 &mut self,
672 id: &str,
673 ) -> Result<MsgraphSendOutput<MsgraphNoResponse>, MsgraphClientStdError> {
674 let coroutine = MsgraphMessageSend::new(&self.auth, &self.user_id, id)?;
675 self.run(coroutine)
676 }
677
678 pub fn mail_send(
680 &mut self,
681 message: &MsgraphMessage,
682 save_to_sent_items: bool,
683 ) -> Result<MsgraphSendOutput<MsgraphNoResponse>, MsgraphClientStdError> {
684 let coroutine =
685 MsgraphMailSend::new(&self.auth, &self.user_id, message, save_to_sent_items)?;
686 self.run(coroutine)
687 }
688
689 pub fn mail_send_mime(
692 &mut self,
693 raw: &[u8],
694 ) -> Result<MsgraphSendOutput<MsgraphNoResponse>, MsgraphClientStdError> {
695 let coroutine = MsgraphMailSendMime::new(&self.auth, &self.user_id, raw)?;
696 self.run(coroutine)
697 }
698}
699
700impl fmt::Debug for MsgraphClientStd {
701 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
702 f.debug_struct("MsgraphClientStd")
703 .field("auth", &self.auth)
704 .field("user_id", &self.user_id)
705 .finish_non_exhaustive()
706 }
707}
708
709pub trait MsgraphStream: Read + Write + Send + Any {
712 fn as_any_mut(&mut self) -> &mut dyn Any;
714}
715
716impl<T: Read + Write + Send + Any> MsgraphStream for T {
717 fn as_any_mut(&mut self) -> &mut dyn Any {
718 self
719 }
720}