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::std::stream::StreamStd;
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" => StreamStd::connect_tcp(host, url.port().unwrap_or(80))?,
232 "https" => StreamStd::connect_tls(host, url.port().unwrap_or(443), &tls)?,
233 scheme => {
234 return Err(MsgraphClientStdError::UrlUnsupportedScheme {
235 url: url.to_string(),
236 scheme: scheme.to_string(),
237 });
238 }
239 };
240
241 stream.set_read_timeout(Some(Duration::from_secs(30)))?;
242
243 Ok(Self {
244 stream: Box::new(stream),
245 auth: HttpAuthBearer::new(token.to_string()),
246 user_id,
247 })
248 }
249
250 pub fn set_stream<S: Read + Write + Send + 'static>(&mut self, stream: S) {
252 self.stream = Box::new(stream);
253 }
254
255 pub fn run<C, T>(
258 &mut self,
259 mut coroutine: C,
260 ) -> Result<MsgraphSendOutput<T>, MsgraphClientStdError>
261 where
262 C: MsgraphCoroutine<
263 Yield = MsgraphYield,
264 Return = Result<MsgraphSendOutput<T>, MsgraphSendError>,
265 >,
266 {
267 let mut buf = [0u8; READ_BUFFER_SIZE];
268 let mut arg: Option<&[u8]> = None;
269
270 loop {
271 match coroutine.resume(arg.take()) {
272 MsgraphCoroutineState::Complete(Ok(out)) => return Ok(out),
273 MsgraphCoroutineState::Complete(Err(err)) => return Err(err.into()),
274 MsgraphCoroutineState::Yielded(MsgraphYield::WantsRead) => {
275 let n = self.stream.read(&mut buf)?;
276 arg = Some(&buf[..n]);
277 }
278 MsgraphCoroutineState::Yielded(MsgraphYield::WantsWrite(bytes)) => {
279 self.stream.write_all(&bytes)?;
280 arg = None;
281 }
282 }
283 }
284 }
285
286 pub fn me(&mut self) -> Result<MsgraphSendOutput<MsgraphUser>, MsgraphClientStdError> {
288 let coroutine = MsgraphUserGet::new(&self.auth, &self.user_id)?;
289 self.run(coroutine)
290 }
291
292 pub fn mail_folders_list(
294 &mut self,
295 params: &MsgraphMailFoldersListParams,
296 ) -> Result<MsgraphSendOutput<MsgraphMailFoldersListResponse>, MsgraphClientStdError> {
297 let coroutine = MsgraphMailFoldersList::new(&self.auth, &self.user_id, params)?;
298 self.run(coroutine)
299 }
300
301 pub fn mail_folder_get(
303 &mut self,
304 id: &str,
305 ) -> Result<MsgraphSendOutput<MsgraphMailFolder>, MsgraphClientStdError> {
306 let coroutine = MsgraphMailFolderGet::new(&self.auth, &self.user_id, id)?;
307 self.run(coroutine)
308 }
309
310 pub fn mail_folder_create(
312 &mut self,
313 folder: &MsgraphMailFolder,
314 ) -> Result<MsgraphSendOutput<MsgraphMailFolder>, MsgraphClientStdError> {
315 let coroutine = MsgraphMailFolderCreate::new(&self.auth, &self.user_id, folder)?;
316 self.run(coroutine)
317 }
318
319 pub fn mail_folder_update(
321 &mut self,
322 id: &str,
323 folder: &MsgraphMailFolder,
324 ) -> Result<MsgraphSendOutput<MsgraphMailFolder>, MsgraphClientStdError> {
325 let coroutine = MsgraphMailFolderUpdate::new(&self.auth, &self.user_id, id, folder)?;
326 self.run(coroutine)
327 }
328
329 pub fn mail_folder_delete(
331 &mut self,
332 id: &str,
333 ) -> Result<MsgraphSendOutput<MsgraphNoResponse>, MsgraphClientStdError> {
334 let coroutine = MsgraphMailFolderDelete::new(&self.auth, &self.user_id, id)?;
335 self.run(coroutine)
336 }
337
338 pub fn mail_folder_copy(
340 &mut self,
341 id: &str,
342 destination: &str,
343 ) -> Result<MsgraphSendOutput<MsgraphMailFolder>, MsgraphClientStdError> {
344 let coroutine = MsgraphMailFolderCopy::new(&self.auth, &self.user_id, id, destination)?;
345 self.run(coroutine)
346 }
347
348 pub fn mail_folder_move(
350 &mut self,
351 id: &str,
352 destination: &str,
353 ) -> Result<MsgraphSendOutput<MsgraphMailFolder>, MsgraphClientStdError> {
354 let coroutine = MsgraphMailFolderMove::new(&self.auth, &self.user_id, id, destination)?;
355 self.run(coroutine)
356 }
357
358 pub fn mail_child_folders_list(
360 &mut self,
361 id: &str,
362 params: &MsgraphMailFoldersListParams,
363 ) -> Result<MsgraphSendOutput<MsgraphMailFoldersListResponse>, MsgraphClientStdError> {
364 let coroutine = MsgraphMailChildFoldersList::new(&self.auth, &self.user_id, id, params)?;
365 self.run(coroutine)
366 }
367
368 pub fn contact_folders_list(
370 &mut self,
371 params: &MsgraphContactFoldersListParams,
372 ) -> Result<MsgraphSendOutput<MsgraphContactFoldersListResponse>, MsgraphClientStdError> {
373 let coroutine = MsgraphContactFoldersList::new(&self.auth, &self.user_id, params)?;
374 self.run(coroutine)
375 }
376
377 pub fn contact_folder_get(
379 &mut self,
380 id: &str,
381 ) -> Result<MsgraphSendOutput<MsgraphContactFolder>, MsgraphClientStdError> {
382 let coroutine = MsgraphContactFolderGet::new(&self.auth, &self.user_id, id)?;
383 self.run(coroutine)
384 }
385
386 pub fn contact_folder_create(
388 &mut self,
389 folder: &MsgraphContactFolder,
390 ) -> Result<MsgraphSendOutput<MsgraphContactFolder>, MsgraphClientStdError> {
391 let coroutine = MsgraphContactFolderCreate::new(&self.auth, &self.user_id, folder)?;
392 self.run(coroutine)
393 }
394
395 pub fn contact_folder_update(
397 &mut self,
398 id: &str,
399 folder: &MsgraphContactFolder,
400 ) -> Result<MsgraphSendOutput<MsgraphContactFolder>, MsgraphClientStdError> {
401 let coroutine = MsgraphContactFolderUpdate::new(&self.auth, &self.user_id, id, folder)?;
402 self.run(coroutine)
403 }
404
405 pub fn contact_folder_delete(
407 &mut self,
408 id: &str,
409 ) -> Result<MsgraphSendOutput<MsgraphNoResponse>, MsgraphClientStdError> {
410 let coroutine = MsgraphContactFolderDelete::new(&self.auth, &self.user_id, id)?;
411 self.run(coroutine)
412 }
413
414 pub fn contact_child_folders_list(
416 &mut self,
417 id: &str,
418 params: &MsgraphContactFoldersListParams,
419 ) -> Result<MsgraphSendOutput<MsgraphContactFoldersListResponse>, MsgraphClientStdError> {
420 let coroutine = MsgraphContactChildFoldersList::new(&self.auth, &self.user_id, id, params)?;
421 self.run(coroutine)
422 }
423
424 pub fn contacts_list(
427 &mut self,
428 folder: Option<&str>,
429 params: &MsgraphContactsListParams,
430 ) -> Result<MsgraphSendOutput<MsgraphContactsListResponse>, MsgraphClientStdError> {
431 let coroutine = MsgraphContactsList::new(&self.auth, &self.user_id, folder, params)?;
432 self.run(coroutine)
433 }
434
435 pub fn contact_get(
437 &mut self,
438 id: &str,
439 expand: Option<&str>,
440 ) -> Result<MsgraphSendOutput<MsgraphContact>, MsgraphClientStdError> {
441 let coroutine = MsgraphContactGet::new(&self.auth, &self.user_id, id, expand)?;
442 self.run(coroutine)
443 }
444
445 pub fn contact_create(
448 &mut self,
449 folder: Option<&str>,
450 contact: &MsgraphContact,
451 ) -> Result<MsgraphSendOutput<MsgraphContact>, MsgraphClientStdError> {
452 let coroutine = MsgraphContactCreate::new(&self.auth, &self.user_id, folder, contact)?;
453 self.run(coroutine)
454 }
455
456 pub fn contact_update(
458 &mut self,
459 id: &str,
460 contact: &MsgraphContact,
461 ) -> Result<MsgraphSendOutput<MsgraphContact>, MsgraphClientStdError> {
462 let coroutine = MsgraphContactUpdate::new(&self.auth, &self.user_id, id, contact)?;
463 self.run(coroutine)
464 }
465
466 pub fn contact_delete(
468 &mut self,
469 id: &str,
470 ) -> Result<MsgraphSendOutput<MsgraphNoResponse>, MsgraphClientStdError> {
471 let coroutine = MsgraphContactDelete::new(&self.auth, &self.user_id, id)?;
472 self.run(coroutine)
473 }
474
475 pub fn contacts_delta(
478 &mut self,
479 folder: Option<&str>,
480 select: Option<&str>,
481 ) -> Result<MsgraphSendOutput<MsgraphContactsDeltaResponse>, MsgraphClientStdError> {
482 let coroutine = MsgraphContactsDelta::new(&self.auth, &self.user_id, folder, select)?;
483 self.run(coroutine)
484 }
485
486 pub fn messages_list(
489 &mut self,
490 folder: Option<&str>,
491 params: &MsgraphMessagesListParams,
492 ) -> Result<MsgraphSendOutput<MsgraphMessagesListResponse>, MsgraphClientStdError> {
493 let coroutine = MsgraphMessagesList::new(&self.auth, &self.user_id, folder, params)?;
494 self.run(coroutine)
495 }
496
497 pub fn message_get(
499 &mut self,
500 id: &str,
501 ) -> Result<MsgraphSendOutput<MsgraphMessage>, MsgraphClientStdError> {
502 let coroutine = MsgraphMessageGet::new(&self.auth, &self.user_id, id)?;
503 self.run(coroutine)
504 }
505
506 pub fn message_get_raw(
508 &mut self,
509 id: &str,
510 ) -> Result<MsgraphSendOutput<Vec<u8>>, MsgraphClientStdError> {
511 let coroutine = MsgraphMessageGetRaw::new(&self.auth, &self.user_id, id)?;
512 self.run(coroutine)
513 }
514
515 pub fn message_create(
518 &mut self,
519 folder: Option<&str>,
520 message: &MsgraphMessage,
521 ) -> Result<MsgraphSendOutput<MsgraphMessage>, MsgraphClientStdError> {
522 let coroutine = MsgraphMessageCreate::new(&self.auth, &self.user_id, folder, message)?;
523 self.run(coroutine)
524 }
525
526 pub fn message_create_mime(
529 &mut self,
530 folder: Option<&str>,
531 raw: &[u8],
532 ) -> Result<MsgraphSendOutput<MsgraphMessage>, MsgraphClientStdError> {
533 let coroutine = MsgraphMessageCreateMime::new(&self.auth, &self.user_id, folder, raw)?;
534 self.run(coroutine)
535 }
536
537 pub fn message_update(
539 &mut self,
540 id: &str,
541 message: &MsgraphMessage,
542 ) -> Result<MsgraphSendOutput<MsgraphMessage>, MsgraphClientStdError> {
543 let coroutine = MsgraphMessageUpdate::new(&self.auth, &self.user_id, id, message)?;
544 self.run(coroutine)
545 }
546
547 pub fn message_delete(
549 &mut self,
550 id: &str,
551 ) -> Result<MsgraphSendOutput<MsgraphNoResponse>, MsgraphClientStdError> {
552 let coroutine = MsgraphMessageDelete::new(&self.auth, &self.user_id, id)?;
553 self.run(coroutine)
554 }
555
556 pub fn message_move(
558 &mut self,
559 id: &str,
560 destination: &str,
561 ) -> Result<MsgraphSendOutput<MsgraphMessage>, MsgraphClientStdError> {
562 let coroutine = MsgraphMessageMove::new(&self.auth, &self.user_id, id, destination)?;
563 self.run(coroutine)
564 }
565
566 pub fn message_copy(
568 &mut self,
569 id: &str,
570 destination: &str,
571 ) -> Result<MsgraphSendOutput<MsgraphMessage>, MsgraphClientStdError> {
572 let coroutine = MsgraphMessageCopy::new(&self.auth, &self.user_id, id, destination)?;
573 self.run(coroutine)
574 }
575
576 pub fn messages_delta(
579 &mut self,
580 folder: Option<&str>,
581 select: Option<&str>,
582 ) -> Result<MsgraphSendOutput<MsgraphMessagesDeltaResponse>, MsgraphClientStdError> {
583 let coroutine = MsgraphMessagesDelta::new(&self.auth, &self.user_id, folder, select)?;
584 self.run(coroutine)
585 }
586
587 pub fn messages_delta_from_link(
590 &mut self,
591 link: &str,
592 ) -> Result<MsgraphSendOutput<MsgraphMessagesDeltaResponse>, MsgraphClientStdError> {
593 let coroutine = MsgraphMessagesDelta::from_link(&self.auth, link)?;
594 self.run(coroutine)
595 }
596
597 pub fn attachment_create(
599 &mut self,
600 message_id: &str,
601 name: &str,
602 content: &[u8],
603 content_type: Option<&str>,
604 ) -> Result<MsgraphSendOutput<MsgraphAttachment>, MsgraphClientStdError> {
605 let coroutine = MsgraphAttachmentCreate::new(
606 &self.auth,
607 &self.user_id,
608 message_id,
609 name,
610 content,
611 content_type,
612 )?;
613 self.run(coroutine)
614 }
615
616 pub fn attachments_list(
618 &mut self,
619 message_id: &str,
620 ) -> Result<MsgraphSendOutput<MsgraphAttachmentsListResponse>, MsgraphClientStdError> {
621 let coroutine = MsgraphAttachmentsList::new(&self.auth, &self.user_id, message_id)?;
622 self.run(coroutine)
623 }
624
625 pub fn attachment_get_raw(
627 &mut self,
628 message_id: &str,
629 attachment_id: &str,
630 ) -> Result<MsgraphSendOutput<Vec<u8>>, MsgraphClientStdError> {
631 let coroutine =
632 MsgraphAttachmentGetRaw::new(&self.auth, &self.user_id, message_id, attachment_id)?;
633 self.run(coroutine)
634 }
635
636 pub fn attachment_delete(
638 &mut self,
639 message_id: &str,
640 attachment_id: &str,
641 ) -> Result<MsgraphSendOutput<MsgraphNoResponse>, MsgraphClientStdError> {
642 let coroutine =
643 MsgraphAttachmentDelete::new(&self.auth, &self.user_id, message_id, attachment_id)?;
644 self.run(coroutine)
645 }
646
647 pub fn message_send(
649 &mut self,
650 id: &str,
651 ) -> Result<MsgraphSendOutput<MsgraphNoResponse>, MsgraphClientStdError> {
652 let coroutine = MsgraphMessageSend::new(&self.auth, &self.user_id, id)?;
653 self.run(coroutine)
654 }
655
656 pub fn mail_send(
658 &mut self,
659 message: &MsgraphMessage,
660 save_to_sent_items: bool,
661 ) -> Result<MsgraphSendOutput<MsgraphNoResponse>, MsgraphClientStdError> {
662 let coroutine =
663 MsgraphMailSend::new(&self.auth, &self.user_id, message, save_to_sent_items)?;
664 self.run(coroutine)
665 }
666
667 pub fn mail_send_mime(
670 &mut self,
671 raw: &[u8],
672 ) -> Result<MsgraphSendOutput<MsgraphNoResponse>, MsgraphClientStdError> {
673 let coroutine = MsgraphMailSendMime::new(&self.auth, &self.user_id, raw)?;
674 self.run(coroutine)
675 }
676}
677
678impl fmt::Debug for MsgraphClientStd {
679 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
680 f.debug_struct("MsgraphClientStd")
681 .field("auth", &self.auth)
682 .field("user_id", &self.user_id)
683 .finish_non_exhaustive()
684 }
685}
686
687pub trait MsgraphStream: Read + Write + Send + Any {
690 fn as_any_mut(&mut self) -> &mut dyn Any;
692}
693
694impl<T: Read + Write + Send + Any> MsgraphStream for T {
695 fn as_any_mut(&mut self) -> &mut dyn Any {
696 self
697 }
698}