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, MsgraphContactFoldersListResponse,
55 child_folders::MsgraphContactChildFoldersList, create::MsgraphContactFolderCreate,
56 delete::MsgraphContactFolderDelete, get::MsgraphContactFolderGet,
57 list::MsgraphContactFoldersList, list::MsgraphContactFoldersListParams,
58 update::MsgraphContactFolderUpdate,
59 },
60 contacts::{
61 MsgraphContact, MsgraphContactsDeltaResponse, MsgraphContactsListResponse,
62 create::MsgraphContactCreate, delete::MsgraphContactDelete,
63 delta::MsgraphContactsDelta, get::MsgraphContactGet, list::MsgraphContactsList,
64 list::MsgraphContactsListParams, update::MsgraphContactUpdate,
65 },
66 get::MsgraphUserGet,
67 mail_folders::{
68 MsgraphMailFolder, MsgraphMailFoldersListResponse,
69 child_folders::MsgraphMailChildFoldersList, copy::MsgraphMailFolderCopy,
70 create::MsgraphMailFolderCreate, delete::MsgraphMailFolderDelete,
71 get::MsgraphMailFolderGet, list::MsgraphMailFoldersList,
72 list::MsgraphMailFoldersListParams, r#move::MsgraphMailFolderMove,
73 update::MsgraphMailFolderUpdate,
74 },
75 messages::{
76 MsgraphMessage, MsgraphMessagesListResponse,
77 attachments::{
78 MsgraphAttachment, MsgraphAttachmentsListResponse, create::MsgraphAttachmentCreate,
79 delete::MsgraphAttachmentDelete, get_raw::MsgraphAttachmentGetRaw,
80 list::MsgraphAttachmentsList,
81 },
82 copy::MsgraphMessageCopy,
83 create::MsgraphMessageCreate,
84 create_mime::MsgraphMessageCreateMime,
85 delete::MsgraphMessageDelete,
86 get::MsgraphMessageGet,
87 get_raw::MsgraphMessageGetRaw,
88 list::MsgraphMessagesList,
89 list::MsgraphMessagesListParams,
90 r#move::MsgraphMessageMove,
91 send::MsgraphMessageSend,
92 update::MsgraphMessageUpdate,
93 },
94 send_mail::{MsgraphMailSend, MsgraphMailSendMime},
95 },
96 v1::send::{MsgraphNoResponse, MsgraphSendError, MsgraphSendOutput},
97};
98
99#[derive(Debug, Error)]
101pub enum MsgraphClientStdError {
102 #[error(transparent)]
104 Send(#[from] MsgraphSendError),
105 #[error(transparent)]
107 Io(#[from] io::Error),
108 #[cfg(any(
110 feature = "rustls-aws",
111 feature = "rustls-ring",
112 feature = "native-tls"
113 ))]
114 #[error(transparent)]
115 Tls(#[from] anyhow::Error),
116 #[cfg(any(
118 feature = "rustls-aws",
119 feature = "rustls-ring",
120 feature = "native-tls"
121 ))]
122 #[error("Microsoft Graph URL `{0}` has no host")]
123 UrlMissingHost(String),
124 #[cfg(any(
126 feature = "rustls-aws",
127 feature = "rustls-ring",
128 feature = "native-tls"
129 ))]
130 #[error(
131 "Microsoft Graph URL `{url}` has unsupported scheme `{scheme}` (expected `http` or `https`)"
132 )]
133 UrlUnsupportedScheme {
134 url: String,
136 scheme: String,
138 },
139}
140
141pub struct MsgraphClientStdConnectOptions {
144 #[cfg(any(
146 feature = "rustls-aws",
147 feature = "rustls-ring",
148 feature = "native-tls"
149 ))]
150 pub tls: Tls,
151 pub user_id: String,
153}
154
155impl Default for MsgraphClientStdConnectOptions {
156 fn default() -> Self {
157 Self {
158 #[cfg(any(
159 feature = "rustls-aws",
160 feature = "rustls-ring",
161 feature = "native-tls"
162 ))]
163 tls: Tls::default(),
164 user_id: String::from("me"),
165 }
166 }
167}
168
169const READ_BUFFER_SIZE: usize = 16 * 1024;
170
171pub struct MsgraphClientStd {
174 pub stream: Box<dyn MsgraphStream>,
176 pub auth: HttpAuthBearer,
178 pub user_id: String,
180}
181
182impl MsgraphClientStd {
183 pub fn new<S: Read + Write + Send + 'static>(
185 stream: S,
186 token: impl ToString,
187 options: MsgraphClientStdConnectOptions,
188 ) -> Self {
189 Self {
190 stream: Box::new(stream),
191 auth: HttpAuthBearer::new(token.to_string()),
192 user_id: options.user_id,
193 }
194 }
195
196 #[cfg(any(
199 feature = "rustls-aws",
200 feature = "rustls-ring",
201 feature = "native-tls"
202 ))]
203 pub fn connect(
204 token: impl ToString,
205 options: MsgraphClientStdConnectOptions,
206 ) -> Result<Self, MsgraphClientStdError> {
207 let MsgraphClientStdConnectOptions { tls, user_id } = options;
208
209 let url = Url::parse(MSGRAPH_API_BASE).expect("Microsoft Graph API base URL is valid");
210 let host = url
211 .host_str()
212 .ok_or_else(|| MsgraphClientStdError::UrlMissingHost(url.to_string()))?;
213
214 let stream = match url.scheme() {
215 "http" => StreamStd::connect_tcp(host, url.port().unwrap_or(80))?,
216 "https" => StreamStd::connect_tls(host, url.port().unwrap_or(443), &tls)?,
217 scheme => {
218 return Err(MsgraphClientStdError::UrlUnsupportedScheme {
219 url: url.to_string(),
220 scheme: scheme.to_string(),
221 });
222 }
223 };
224
225 stream.set_read_timeout(Some(Duration::from_secs(30)))?;
226
227 Ok(Self {
228 stream: Box::new(stream),
229 auth: HttpAuthBearer::new(token.to_string()),
230 user_id,
231 })
232 }
233
234 pub fn set_stream<S: Read + Write + Send + 'static>(&mut self, stream: S) {
236 self.stream = Box::new(stream);
237 }
238
239 pub fn run<C, T>(
242 &mut self,
243 mut coroutine: C,
244 ) -> Result<MsgraphSendOutput<T>, MsgraphClientStdError>
245 where
246 C: MsgraphCoroutine<
247 Yield = MsgraphYield,
248 Return = Result<MsgraphSendOutput<T>, MsgraphSendError>,
249 >,
250 {
251 let mut buf = [0u8; READ_BUFFER_SIZE];
252 let mut arg: Option<&[u8]> = None;
253
254 loop {
255 match coroutine.resume(arg.take()) {
256 MsgraphCoroutineState::Complete(Ok(out)) => return Ok(out),
257 MsgraphCoroutineState::Complete(Err(err)) => return Err(err.into()),
258 MsgraphCoroutineState::Yielded(MsgraphYield::WantsRead) => {
259 let n = self.stream.read(&mut buf)?;
260 arg = Some(&buf[..n]);
261 }
262 MsgraphCoroutineState::Yielded(MsgraphYield::WantsWrite(bytes)) => {
263 self.stream.write_all(&bytes)?;
264 arg = None;
265 }
266 }
267 }
268 }
269
270 pub fn me(&mut self) -> Result<MsgraphSendOutput<MsgraphUser>, MsgraphClientStdError> {
272 let coroutine = MsgraphUserGet::new(&self.auth, &self.user_id)?;
273 self.run(coroutine)
274 }
275
276 pub fn mail_folders_list(
278 &mut self,
279 params: &MsgraphMailFoldersListParams,
280 ) -> Result<MsgraphSendOutput<MsgraphMailFoldersListResponse>, MsgraphClientStdError> {
281 let coroutine = MsgraphMailFoldersList::new(&self.auth, &self.user_id, params)?;
282 self.run(coroutine)
283 }
284
285 pub fn mail_folder_get(
287 &mut self,
288 id: &str,
289 ) -> Result<MsgraphSendOutput<MsgraphMailFolder>, MsgraphClientStdError> {
290 let coroutine = MsgraphMailFolderGet::new(&self.auth, &self.user_id, id)?;
291 self.run(coroutine)
292 }
293
294 pub fn mail_folder_create(
296 &mut self,
297 folder: &MsgraphMailFolder,
298 ) -> Result<MsgraphSendOutput<MsgraphMailFolder>, MsgraphClientStdError> {
299 let coroutine = MsgraphMailFolderCreate::new(&self.auth, &self.user_id, folder)?;
300 self.run(coroutine)
301 }
302
303 pub fn mail_folder_update(
305 &mut self,
306 id: &str,
307 folder: &MsgraphMailFolder,
308 ) -> Result<MsgraphSendOutput<MsgraphMailFolder>, MsgraphClientStdError> {
309 let coroutine = MsgraphMailFolderUpdate::new(&self.auth, &self.user_id, id, folder)?;
310 self.run(coroutine)
311 }
312
313 pub fn mail_folder_delete(
315 &mut self,
316 id: &str,
317 ) -> Result<MsgraphSendOutput<MsgraphNoResponse>, MsgraphClientStdError> {
318 let coroutine = MsgraphMailFolderDelete::new(&self.auth, &self.user_id, id)?;
319 self.run(coroutine)
320 }
321
322 pub fn mail_folder_copy(
324 &mut self,
325 id: &str,
326 destination: &str,
327 ) -> Result<MsgraphSendOutput<MsgraphMailFolder>, MsgraphClientStdError> {
328 let coroutine = MsgraphMailFolderCopy::new(&self.auth, &self.user_id, id, destination)?;
329 self.run(coroutine)
330 }
331
332 pub fn mail_folder_move(
334 &mut self,
335 id: &str,
336 destination: &str,
337 ) -> Result<MsgraphSendOutput<MsgraphMailFolder>, MsgraphClientStdError> {
338 let coroutine = MsgraphMailFolderMove::new(&self.auth, &self.user_id, id, destination)?;
339 self.run(coroutine)
340 }
341
342 pub fn mail_child_folders_list(
344 &mut self,
345 id: &str,
346 params: &MsgraphMailFoldersListParams,
347 ) -> Result<MsgraphSendOutput<MsgraphMailFoldersListResponse>, MsgraphClientStdError> {
348 let coroutine = MsgraphMailChildFoldersList::new(&self.auth, &self.user_id, id, params)?;
349 self.run(coroutine)
350 }
351
352 pub fn contact_folders_list(
354 &mut self,
355 params: &MsgraphContactFoldersListParams,
356 ) -> Result<MsgraphSendOutput<MsgraphContactFoldersListResponse>, MsgraphClientStdError> {
357 let coroutine = MsgraphContactFoldersList::new(&self.auth, &self.user_id, params)?;
358 self.run(coroutine)
359 }
360
361 pub fn contact_folder_get(
363 &mut self,
364 id: &str,
365 ) -> Result<MsgraphSendOutput<MsgraphContactFolder>, MsgraphClientStdError> {
366 let coroutine = MsgraphContactFolderGet::new(&self.auth, &self.user_id, id)?;
367 self.run(coroutine)
368 }
369
370 pub fn contact_folder_create(
372 &mut self,
373 folder: &MsgraphContactFolder,
374 ) -> Result<MsgraphSendOutput<MsgraphContactFolder>, MsgraphClientStdError> {
375 let coroutine = MsgraphContactFolderCreate::new(&self.auth, &self.user_id, folder)?;
376 self.run(coroutine)
377 }
378
379 pub fn contact_folder_update(
381 &mut self,
382 id: &str,
383 folder: &MsgraphContactFolder,
384 ) -> Result<MsgraphSendOutput<MsgraphContactFolder>, MsgraphClientStdError> {
385 let coroutine = MsgraphContactFolderUpdate::new(&self.auth, &self.user_id, id, folder)?;
386 self.run(coroutine)
387 }
388
389 pub fn contact_folder_delete(
391 &mut self,
392 id: &str,
393 ) -> Result<MsgraphSendOutput<MsgraphNoResponse>, MsgraphClientStdError> {
394 let coroutine = MsgraphContactFolderDelete::new(&self.auth, &self.user_id, id)?;
395 self.run(coroutine)
396 }
397
398 pub fn contact_child_folders_list(
400 &mut self,
401 id: &str,
402 params: &MsgraphContactFoldersListParams,
403 ) -> Result<MsgraphSendOutput<MsgraphContactFoldersListResponse>, MsgraphClientStdError> {
404 let coroutine = MsgraphContactChildFoldersList::new(&self.auth, &self.user_id, id, params)?;
405 self.run(coroutine)
406 }
407
408 pub fn contacts_list(
411 &mut self,
412 folder: Option<&str>,
413 params: &MsgraphContactsListParams,
414 ) -> Result<MsgraphSendOutput<MsgraphContactsListResponse>, MsgraphClientStdError> {
415 let coroutine = MsgraphContactsList::new(&self.auth, &self.user_id, folder, params)?;
416 self.run(coroutine)
417 }
418
419 pub fn contact_get(
421 &mut self,
422 id: &str,
423 expand: Option<&str>,
424 ) -> Result<MsgraphSendOutput<MsgraphContact>, MsgraphClientStdError> {
425 let coroutine = MsgraphContactGet::new(&self.auth, &self.user_id, id, expand)?;
426 self.run(coroutine)
427 }
428
429 pub fn contact_create(
432 &mut self,
433 folder: Option<&str>,
434 contact: &MsgraphContact,
435 ) -> Result<MsgraphSendOutput<MsgraphContact>, MsgraphClientStdError> {
436 let coroutine = MsgraphContactCreate::new(&self.auth, &self.user_id, folder, contact)?;
437 self.run(coroutine)
438 }
439
440 pub fn contact_update(
442 &mut self,
443 id: &str,
444 contact: &MsgraphContact,
445 ) -> Result<MsgraphSendOutput<MsgraphContact>, MsgraphClientStdError> {
446 let coroutine = MsgraphContactUpdate::new(&self.auth, &self.user_id, id, contact)?;
447 self.run(coroutine)
448 }
449
450 pub fn contact_delete(
452 &mut self,
453 id: &str,
454 ) -> Result<MsgraphSendOutput<MsgraphNoResponse>, MsgraphClientStdError> {
455 let coroutine = MsgraphContactDelete::new(&self.auth, &self.user_id, id)?;
456 self.run(coroutine)
457 }
458
459 pub fn contacts_delta(
462 &mut self,
463 folder: Option<&str>,
464 select: Option<&str>,
465 ) -> Result<MsgraphSendOutput<MsgraphContactsDeltaResponse>, MsgraphClientStdError> {
466 let coroutine = MsgraphContactsDelta::new(&self.auth, &self.user_id, folder, select)?;
467 self.run(coroutine)
468 }
469
470 pub fn messages_list(
473 &mut self,
474 folder: Option<&str>,
475 params: &MsgraphMessagesListParams,
476 ) -> Result<MsgraphSendOutput<MsgraphMessagesListResponse>, MsgraphClientStdError> {
477 let coroutine = MsgraphMessagesList::new(&self.auth, &self.user_id, folder, params)?;
478 self.run(coroutine)
479 }
480
481 pub fn message_get(
483 &mut self,
484 id: &str,
485 ) -> Result<MsgraphSendOutput<MsgraphMessage>, MsgraphClientStdError> {
486 let coroutine = MsgraphMessageGet::new(&self.auth, &self.user_id, id)?;
487 self.run(coroutine)
488 }
489
490 pub fn message_get_raw(
492 &mut self,
493 id: &str,
494 ) -> Result<MsgraphSendOutput<Vec<u8>>, MsgraphClientStdError> {
495 let coroutine = MsgraphMessageGetRaw::new(&self.auth, &self.user_id, id)?;
496 self.run(coroutine)
497 }
498
499 pub fn message_create(
502 &mut self,
503 folder: Option<&str>,
504 message: &MsgraphMessage,
505 ) -> Result<MsgraphSendOutput<MsgraphMessage>, MsgraphClientStdError> {
506 let coroutine = MsgraphMessageCreate::new(&self.auth, &self.user_id, folder, message)?;
507 self.run(coroutine)
508 }
509
510 pub fn message_create_mime(
513 &mut self,
514 folder: Option<&str>,
515 raw: &[u8],
516 ) -> Result<MsgraphSendOutput<MsgraphMessage>, MsgraphClientStdError> {
517 let coroutine = MsgraphMessageCreateMime::new(&self.auth, &self.user_id, folder, raw)?;
518 self.run(coroutine)
519 }
520
521 pub fn message_update(
523 &mut self,
524 id: &str,
525 message: &MsgraphMessage,
526 ) -> Result<MsgraphSendOutput<MsgraphMessage>, MsgraphClientStdError> {
527 let coroutine = MsgraphMessageUpdate::new(&self.auth, &self.user_id, id, message)?;
528 self.run(coroutine)
529 }
530
531 pub fn message_delete(
533 &mut self,
534 id: &str,
535 ) -> Result<MsgraphSendOutput<MsgraphNoResponse>, MsgraphClientStdError> {
536 let coroutine = MsgraphMessageDelete::new(&self.auth, &self.user_id, id)?;
537 self.run(coroutine)
538 }
539
540 pub fn message_move(
542 &mut self,
543 id: &str,
544 destination: &str,
545 ) -> Result<MsgraphSendOutput<MsgraphMessage>, MsgraphClientStdError> {
546 let coroutine = MsgraphMessageMove::new(&self.auth, &self.user_id, id, destination)?;
547 self.run(coroutine)
548 }
549
550 pub fn message_copy(
552 &mut self,
553 id: &str,
554 destination: &str,
555 ) -> Result<MsgraphSendOutput<MsgraphMessage>, MsgraphClientStdError> {
556 let coroutine = MsgraphMessageCopy::new(&self.auth, &self.user_id, id, destination)?;
557 self.run(coroutine)
558 }
559
560 pub fn attachment_create(
562 &mut self,
563 message_id: &str,
564 name: &str,
565 content: &[u8],
566 content_type: Option<&str>,
567 ) -> Result<MsgraphSendOutput<MsgraphAttachment>, MsgraphClientStdError> {
568 let coroutine = MsgraphAttachmentCreate::new(
569 &self.auth,
570 &self.user_id,
571 message_id,
572 name,
573 content,
574 content_type,
575 )?;
576 self.run(coroutine)
577 }
578
579 pub fn attachments_list(
581 &mut self,
582 message_id: &str,
583 ) -> Result<MsgraphSendOutput<MsgraphAttachmentsListResponse>, MsgraphClientStdError> {
584 let coroutine = MsgraphAttachmentsList::new(&self.auth, &self.user_id, message_id)?;
585 self.run(coroutine)
586 }
587
588 pub fn attachment_get_raw(
590 &mut self,
591 message_id: &str,
592 attachment_id: &str,
593 ) -> Result<MsgraphSendOutput<Vec<u8>>, MsgraphClientStdError> {
594 let coroutine =
595 MsgraphAttachmentGetRaw::new(&self.auth, &self.user_id, message_id, attachment_id)?;
596 self.run(coroutine)
597 }
598
599 pub fn attachment_delete(
601 &mut self,
602 message_id: &str,
603 attachment_id: &str,
604 ) -> Result<MsgraphSendOutput<MsgraphNoResponse>, MsgraphClientStdError> {
605 let coroutine =
606 MsgraphAttachmentDelete::new(&self.auth, &self.user_id, message_id, attachment_id)?;
607 self.run(coroutine)
608 }
609
610 pub fn message_send(
612 &mut self,
613 id: &str,
614 ) -> Result<MsgraphSendOutput<MsgraphNoResponse>, MsgraphClientStdError> {
615 let coroutine = MsgraphMessageSend::new(&self.auth, &self.user_id, id)?;
616 self.run(coroutine)
617 }
618
619 pub fn mail_send(
621 &mut self,
622 message: &MsgraphMessage,
623 save_to_sent_items: bool,
624 ) -> Result<MsgraphSendOutput<MsgraphNoResponse>, MsgraphClientStdError> {
625 let coroutine =
626 MsgraphMailSend::new(&self.auth, &self.user_id, message, save_to_sent_items)?;
627 self.run(coroutine)
628 }
629
630 pub fn mail_send_mime(
633 &mut self,
634 raw: &[u8],
635 ) -> Result<MsgraphSendOutput<MsgraphNoResponse>, MsgraphClientStdError> {
636 let coroutine = MsgraphMailSendMime::new(&self.auth, &self.user_id, raw)?;
637 self.run(coroutine)
638 }
639}
640
641impl fmt::Debug for MsgraphClientStd {
642 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
643 f.debug_struct("MsgraphClientStd")
644 .field("auth", &self.auth)
645 .field("user_id", &self.user_id)
646 .finish_non_exhaustive()
647 }
648}
649
650pub trait MsgraphStream: Read + Write + Send + Any {
653 fn as_any_mut(&mut self) -> &mut dyn Any;
655}
656
657impl<T: Read + Write + Send + Any> MsgraphStream for T {
658 fn as_any_mut(&mut self) -> &mut dyn Any {
659 self
660 }
661}