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 get::MsgraphMessageGet,
103 get_raw::MsgraphMessageGetRaw,
104 list::{MsgraphMessagesList, MsgraphMessagesListParams, MsgraphMessagesListResponse},
105 r#move::MsgraphMessageMove,
106 send::MsgraphMessageSend,
107 update::MsgraphMessageUpdate,
108 },
109 send_mail::{MsgraphMailSend, MsgraphMailSendMime},
110 },
111 v1::send::{MsgraphNoResponse, MsgraphSendError, MsgraphSendOutput},
112};
113
114#[derive(Debug, Error)]
116pub enum MsgraphClientStdError {
117 #[error(transparent)]
119 Send(#[from] MsgraphSendError),
120 #[error(transparent)]
122 Io(#[from] io::Error),
123 #[cfg(any(
125 feature = "rustls-aws",
126 feature = "rustls-ring",
127 feature = "native-tls"
128 ))]
129 #[error(transparent)]
130 Tls(#[from] anyhow::Error),
131 #[cfg(any(
133 feature = "rustls-aws",
134 feature = "rustls-ring",
135 feature = "native-tls"
136 ))]
137 #[error("Microsoft Graph URL `{0}` has no host")]
138 UrlMissingHost(String),
139 #[cfg(any(
141 feature = "rustls-aws",
142 feature = "rustls-ring",
143 feature = "native-tls"
144 ))]
145 #[error(
146 "Microsoft Graph URL `{url}` has unsupported scheme `{scheme}` (expected `http` or `https`)"
147 )]
148 UrlUnsupportedScheme {
149 url: String,
151 scheme: String,
153 },
154}
155
156pub struct MsgraphClientStdConnectOptions {
159 #[cfg(any(
161 feature = "rustls-aws",
162 feature = "rustls-ring",
163 feature = "native-tls"
164 ))]
165 pub tls: Tls,
166 pub user_id: String,
168}
169
170impl Default for MsgraphClientStdConnectOptions {
171 fn default() -> Self {
172 Self {
173 #[cfg(any(
174 feature = "rustls-aws",
175 feature = "rustls-ring",
176 feature = "native-tls"
177 ))]
178 tls: Tls::default(),
179 user_id: String::from("me"),
180 }
181 }
182}
183
184const READ_BUFFER_SIZE: usize = 16 * 1024;
185
186pub struct MsgraphClientStd {
189 pub stream: Box<dyn MsgraphStream>,
191 pub auth: HttpAuthBearer,
193 pub user_id: String,
195}
196
197impl MsgraphClientStd {
198 pub fn new<S: Read + Write + Send + 'static>(
200 stream: S,
201 token: impl ToString,
202 options: MsgraphClientStdConnectOptions,
203 ) -> Self {
204 Self {
205 stream: Box::new(stream),
206 auth: HttpAuthBearer::new(token.to_string()),
207 user_id: options.user_id,
208 }
209 }
210
211 #[cfg(any(
214 feature = "rustls-aws",
215 feature = "rustls-ring",
216 feature = "native-tls"
217 ))]
218 pub fn connect(
219 token: impl ToString,
220 options: MsgraphClientStdConnectOptions,
221 ) -> Result<Self, MsgraphClientStdError> {
222 let MsgraphClientStdConnectOptions { tls, user_id } = options;
223
224 let url = Url::parse(MSGRAPH_API_BASE).expect("Microsoft Graph API base URL is valid");
225 let host = url
226 .host_str()
227 .ok_or_else(|| MsgraphClientStdError::UrlMissingHost(url.to_string()))?;
228
229 let stream = match url.scheme() {
230 "http" => StreamStd::connect_tcp(host, url.port().unwrap_or(80))?,
231 "https" => StreamStd::connect_tls(host, url.port().unwrap_or(443), &tls)?,
232 scheme => {
233 return Err(MsgraphClientStdError::UrlUnsupportedScheme {
234 url: url.to_string(),
235 scheme: scheme.to_string(),
236 });
237 }
238 };
239
240 stream.set_read_timeout(Some(Duration::from_secs(30)))?;
241
242 Ok(Self {
243 stream: Box::new(stream),
244 auth: HttpAuthBearer::new(token.to_string()),
245 user_id,
246 })
247 }
248
249 pub fn set_stream<S: Read + Write + Send + 'static>(&mut self, stream: S) {
251 self.stream = Box::new(stream);
252 }
253
254 pub fn run<C, T>(
257 &mut self,
258 mut coroutine: C,
259 ) -> Result<MsgraphSendOutput<T>, MsgraphClientStdError>
260 where
261 C: MsgraphCoroutine<
262 Yield = MsgraphYield,
263 Return = Result<MsgraphSendOutput<T>, MsgraphSendError>,
264 >,
265 {
266 let mut buf = [0u8; READ_BUFFER_SIZE];
267 let mut arg: Option<&[u8]> = None;
268
269 loop {
270 match coroutine.resume(arg.take()) {
271 MsgraphCoroutineState::Complete(Ok(out)) => return Ok(out),
272 MsgraphCoroutineState::Complete(Err(err)) => return Err(err.into()),
273 MsgraphCoroutineState::Yielded(MsgraphYield::WantsRead) => {
274 let n = self.stream.read(&mut buf)?;
275 arg = Some(&buf[..n]);
276 }
277 MsgraphCoroutineState::Yielded(MsgraphYield::WantsWrite(bytes)) => {
278 self.stream.write_all(&bytes)?;
279 arg = None;
280 }
281 }
282 }
283 }
284
285 pub fn me(&mut self) -> Result<MsgraphSendOutput<MsgraphUser>, MsgraphClientStdError> {
287 let coroutine = MsgraphUserGet::new(&self.auth, &self.user_id)?;
288 self.run(coroutine)
289 }
290
291 pub fn mail_folders_list(
293 &mut self,
294 params: &MsgraphMailFoldersListParams,
295 ) -> Result<MsgraphSendOutput<MsgraphMailFoldersListResponse>, MsgraphClientStdError> {
296 let coroutine = MsgraphMailFoldersList::new(&self.auth, &self.user_id, params)?;
297 self.run(coroutine)
298 }
299
300 pub fn mail_folder_get(
302 &mut self,
303 id: &str,
304 ) -> Result<MsgraphSendOutput<MsgraphMailFolder>, MsgraphClientStdError> {
305 let coroutine = MsgraphMailFolderGet::new(&self.auth, &self.user_id, id)?;
306 self.run(coroutine)
307 }
308
309 pub fn mail_folder_create(
311 &mut self,
312 folder: &MsgraphMailFolder,
313 ) -> Result<MsgraphSendOutput<MsgraphMailFolder>, MsgraphClientStdError> {
314 let coroutine = MsgraphMailFolderCreate::new(&self.auth, &self.user_id, folder)?;
315 self.run(coroutine)
316 }
317
318 pub fn mail_folder_update(
320 &mut self,
321 id: &str,
322 folder: &MsgraphMailFolder,
323 ) -> Result<MsgraphSendOutput<MsgraphMailFolder>, MsgraphClientStdError> {
324 let coroutine = MsgraphMailFolderUpdate::new(&self.auth, &self.user_id, id, folder)?;
325 self.run(coroutine)
326 }
327
328 pub fn mail_folder_delete(
330 &mut self,
331 id: &str,
332 ) -> Result<MsgraphSendOutput<MsgraphNoResponse>, MsgraphClientStdError> {
333 let coroutine = MsgraphMailFolderDelete::new(&self.auth, &self.user_id, id)?;
334 self.run(coroutine)
335 }
336
337 pub fn mail_folder_copy(
339 &mut self,
340 id: &str,
341 destination: &str,
342 ) -> Result<MsgraphSendOutput<MsgraphMailFolder>, MsgraphClientStdError> {
343 let coroutine = MsgraphMailFolderCopy::new(&self.auth, &self.user_id, id, destination)?;
344 self.run(coroutine)
345 }
346
347 pub fn mail_folder_move(
349 &mut self,
350 id: &str,
351 destination: &str,
352 ) -> Result<MsgraphSendOutput<MsgraphMailFolder>, MsgraphClientStdError> {
353 let coroutine = MsgraphMailFolderMove::new(&self.auth, &self.user_id, id, destination)?;
354 self.run(coroutine)
355 }
356
357 pub fn mail_child_folders_list(
359 &mut self,
360 id: &str,
361 params: &MsgraphMailFoldersListParams,
362 ) -> Result<MsgraphSendOutput<MsgraphMailFoldersListResponse>, MsgraphClientStdError> {
363 let coroutine = MsgraphMailChildFoldersList::new(&self.auth, &self.user_id, id, params)?;
364 self.run(coroutine)
365 }
366
367 pub fn contact_folders_list(
369 &mut self,
370 params: &MsgraphContactFoldersListParams,
371 ) -> Result<MsgraphSendOutput<MsgraphContactFoldersListResponse>, MsgraphClientStdError> {
372 let coroutine = MsgraphContactFoldersList::new(&self.auth, &self.user_id, params)?;
373 self.run(coroutine)
374 }
375
376 pub fn contact_folder_get(
378 &mut self,
379 id: &str,
380 ) -> Result<MsgraphSendOutput<MsgraphContactFolder>, MsgraphClientStdError> {
381 let coroutine = MsgraphContactFolderGet::new(&self.auth, &self.user_id, id)?;
382 self.run(coroutine)
383 }
384
385 pub fn contact_folder_create(
387 &mut self,
388 folder: &MsgraphContactFolder,
389 ) -> Result<MsgraphSendOutput<MsgraphContactFolder>, MsgraphClientStdError> {
390 let coroutine = MsgraphContactFolderCreate::new(&self.auth, &self.user_id, folder)?;
391 self.run(coroutine)
392 }
393
394 pub fn contact_folder_update(
396 &mut self,
397 id: &str,
398 folder: &MsgraphContactFolder,
399 ) -> Result<MsgraphSendOutput<MsgraphContactFolder>, MsgraphClientStdError> {
400 let coroutine = MsgraphContactFolderUpdate::new(&self.auth, &self.user_id, id, folder)?;
401 self.run(coroutine)
402 }
403
404 pub fn contact_folder_delete(
406 &mut self,
407 id: &str,
408 ) -> Result<MsgraphSendOutput<MsgraphNoResponse>, MsgraphClientStdError> {
409 let coroutine = MsgraphContactFolderDelete::new(&self.auth, &self.user_id, id)?;
410 self.run(coroutine)
411 }
412
413 pub fn contact_child_folders_list(
415 &mut self,
416 id: &str,
417 params: &MsgraphContactFoldersListParams,
418 ) -> Result<MsgraphSendOutput<MsgraphContactFoldersListResponse>, MsgraphClientStdError> {
419 let coroutine = MsgraphContactChildFoldersList::new(&self.auth, &self.user_id, id, params)?;
420 self.run(coroutine)
421 }
422
423 pub fn contacts_list(
426 &mut self,
427 folder: Option<&str>,
428 params: &MsgraphContactsListParams,
429 ) -> Result<MsgraphSendOutput<MsgraphContactsListResponse>, MsgraphClientStdError> {
430 let coroutine = MsgraphContactsList::new(&self.auth, &self.user_id, folder, params)?;
431 self.run(coroutine)
432 }
433
434 pub fn contact_get(
436 &mut self,
437 id: &str,
438 expand: Option<&str>,
439 ) -> Result<MsgraphSendOutput<MsgraphContact>, MsgraphClientStdError> {
440 let coroutine = MsgraphContactGet::new(&self.auth, &self.user_id, id, expand)?;
441 self.run(coroutine)
442 }
443
444 pub fn contact_create(
447 &mut self,
448 folder: Option<&str>,
449 contact: &MsgraphContact,
450 ) -> Result<MsgraphSendOutput<MsgraphContact>, MsgraphClientStdError> {
451 let coroutine = MsgraphContactCreate::new(&self.auth, &self.user_id, folder, contact)?;
452 self.run(coroutine)
453 }
454
455 pub fn contact_update(
457 &mut self,
458 id: &str,
459 contact: &MsgraphContact,
460 ) -> Result<MsgraphSendOutput<MsgraphContact>, MsgraphClientStdError> {
461 let coroutine = MsgraphContactUpdate::new(&self.auth, &self.user_id, id, contact)?;
462 self.run(coroutine)
463 }
464
465 pub fn contact_delete(
467 &mut self,
468 id: &str,
469 ) -> Result<MsgraphSendOutput<MsgraphNoResponse>, MsgraphClientStdError> {
470 let coroutine = MsgraphContactDelete::new(&self.auth, &self.user_id, id)?;
471 self.run(coroutine)
472 }
473
474 pub fn contacts_delta(
477 &mut self,
478 folder: Option<&str>,
479 select: Option<&str>,
480 ) -> Result<MsgraphSendOutput<MsgraphContactsDeltaResponse>, MsgraphClientStdError> {
481 let coroutine = MsgraphContactsDelta::new(&self.auth, &self.user_id, folder, select)?;
482 self.run(coroutine)
483 }
484
485 pub fn messages_list(
488 &mut self,
489 folder: Option<&str>,
490 params: &MsgraphMessagesListParams,
491 ) -> Result<MsgraphSendOutput<MsgraphMessagesListResponse>, MsgraphClientStdError> {
492 let coroutine = MsgraphMessagesList::new(&self.auth, &self.user_id, folder, params)?;
493 self.run(coroutine)
494 }
495
496 pub fn message_get(
498 &mut self,
499 id: &str,
500 ) -> Result<MsgraphSendOutput<MsgraphMessage>, MsgraphClientStdError> {
501 let coroutine = MsgraphMessageGet::new(&self.auth, &self.user_id, id)?;
502 self.run(coroutine)
503 }
504
505 pub fn message_get_raw(
507 &mut self,
508 id: &str,
509 ) -> Result<MsgraphSendOutput<Vec<u8>>, MsgraphClientStdError> {
510 let coroutine = MsgraphMessageGetRaw::new(&self.auth, &self.user_id, id)?;
511 self.run(coroutine)
512 }
513
514 pub fn message_create(
517 &mut self,
518 folder: Option<&str>,
519 message: &MsgraphMessage,
520 ) -> Result<MsgraphSendOutput<MsgraphMessage>, MsgraphClientStdError> {
521 let coroutine = MsgraphMessageCreate::new(&self.auth, &self.user_id, folder, message)?;
522 self.run(coroutine)
523 }
524
525 pub fn message_create_mime(
528 &mut self,
529 folder: Option<&str>,
530 raw: &[u8],
531 ) -> Result<MsgraphSendOutput<MsgraphMessage>, MsgraphClientStdError> {
532 let coroutine = MsgraphMessageCreateMime::new(&self.auth, &self.user_id, folder, raw)?;
533 self.run(coroutine)
534 }
535
536 pub fn message_update(
538 &mut self,
539 id: &str,
540 message: &MsgraphMessage,
541 ) -> Result<MsgraphSendOutput<MsgraphMessage>, MsgraphClientStdError> {
542 let coroutine = MsgraphMessageUpdate::new(&self.auth, &self.user_id, id, message)?;
543 self.run(coroutine)
544 }
545
546 pub fn message_delete(
548 &mut self,
549 id: &str,
550 ) -> Result<MsgraphSendOutput<MsgraphNoResponse>, MsgraphClientStdError> {
551 let coroutine = MsgraphMessageDelete::new(&self.auth, &self.user_id, id)?;
552 self.run(coroutine)
553 }
554
555 pub fn message_move(
557 &mut self,
558 id: &str,
559 destination: &str,
560 ) -> Result<MsgraphSendOutput<MsgraphMessage>, MsgraphClientStdError> {
561 let coroutine = MsgraphMessageMove::new(&self.auth, &self.user_id, id, destination)?;
562 self.run(coroutine)
563 }
564
565 pub fn message_copy(
567 &mut self,
568 id: &str,
569 destination: &str,
570 ) -> Result<MsgraphSendOutput<MsgraphMessage>, MsgraphClientStdError> {
571 let coroutine = MsgraphMessageCopy::new(&self.auth, &self.user_id, id, destination)?;
572 self.run(coroutine)
573 }
574
575 pub fn attachment_create(
577 &mut self,
578 message_id: &str,
579 name: &str,
580 content: &[u8],
581 content_type: Option<&str>,
582 ) -> Result<MsgraphSendOutput<MsgraphAttachment>, MsgraphClientStdError> {
583 let coroutine = MsgraphAttachmentCreate::new(
584 &self.auth,
585 &self.user_id,
586 message_id,
587 name,
588 content,
589 content_type,
590 )?;
591 self.run(coroutine)
592 }
593
594 pub fn attachments_list(
596 &mut self,
597 message_id: &str,
598 ) -> Result<MsgraphSendOutput<MsgraphAttachmentsListResponse>, MsgraphClientStdError> {
599 let coroutine = MsgraphAttachmentsList::new(&self.auth, &self.user_id, message_id)?;
600 self.run(coroutine)
601 }
602
603 pub fn attachment_get_raw(
605 &mut self,
606 message_id: &str,
607 attachment_id: &str,
608 ) -> Result<MsgraphSendOutput<Vec<u8>>, MsgraphClientStdError> {
609 let coroutine =
610 MsgraphAttachmentGetRaw::new(&self.auth, &self.user_id, message_id, attachment_id)?;
611 self.run(coroutine)
612 }
613
614 pub fn attachment_delete(
616 &mut self,
617 message_id: &str,
618 attachment_id: &str,
619 ) -> Result<MsgraphSendOutput<MsgraphNoResponse>, MsgraphClientStdError> {
620 let coroutine =
621 MsgraphAttachmentDelete::new(&self.auth, &self.user_id, message_id, attachment_id)?;
622 self.run(coroutine)
623 }
624
625 pub fn message_send(
627 &mut self,
628 id: &str,
629 ) -> Result<MsgraphSendOutput<MsgraphNoResponse>, MsgraphClientStdError> {
630 let coroutine = MsgraphMessageSend::new(&self.auth, &self.user_id, id)?;
631 self.run(coroutine)
632 }
633
634 pub fn mail_send(
636 &mut self,
637 message: &MsgraphMessage,
638 save_to_sent_items: bool,
639 ) -> Result<MsgraphSendOutput<MsgraphNoResponse>, MsgraphClientStdError> {
640 let coroutine =
641 MsgraphMailSend::new(&self.auth, &self.user_id, message, save_to_sent_items)?;
642 self.run(coroutine)
643 }
644
645 pub fn mail_send_mime(
648 &mut self,
649 raw: &[u8],
650 ) -> Result<MsgraphSendOutput<MsgraphNoResponse>, MsgraphClientStdError> {
651 let coroutine = MsgraphMailSendMime::new(&self.auth, &self.user_id, raw)?;
652 self.run(coroutine)
653 }
654}
655
656impl fmt::Debug for MsgraphClientStd {
657 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
658 f.debug_struct("MsgraphClientStd")
659 .field("auth", &self.auth)
660 .field("user_id", &self.user_id)
661 .finish_non_exhaustive()
662 }
663}
664
665pub trait MsgraphStream: Read + Write + Send + Any {
668 fn as_any_mut(&mut self) -> &mut dyn Any;
670}
671
672impl<T: Read + Write + Send + Any> MsgraphStream for T {
673 fn as_any_mut(&mut self) -> &mut dyn Any {
674 self
675 }
676}