Skip to main content

imsg_map/
folders.rs

1//! Folder listing and SETPATH navigation for MAP folder hierarchy.
2
3use tokio::io::{AsyncRead, AsyncWrite};
4
5use crate::client::MapClient;
6use crate::{FolderListing, MapError};
7
8/// iOS telecom/msg folder hierarchy. Validated on SETPATH.
9#[derive(Debug, Clone, Copy, PartialEq, Eq)]
10pub enum Folder {
11    /// SETPATH segment `"inbox"`.
12    Inbox,
13    /// SETPATH segment `"sent"`.
14    Sent,
15    /// Queued outbound messages awaiting delivery.
16    Outbox,
17    /// Messages moved to the trash.
18    Deleted,
19}
20
21impl Folder {
22    /// SETPATH segment name for this folder as required by the MAP specification.
23    #[must_use]
24    pub const fn as_str(self) -> &'static str {
25        match self {
26            Self::Inbox => "inbox",
27            Self::Sent => "sent",
28            Self::Outbox => "outbox",
29            Self::Deleted => "deleted",
30        }
31    }
32}
33
34impl<T: AsyncRead + AsyncWrite + Unpin> MapClient<T> {
35    /// Backs up to root if already inside a subfolder, then navigates `telecom` → `msg` and
36    /// lists that level. Use this instead of a bare [`MapClient::get_folder_listing`], which
37    /// lists only the current OBEX directory — on iOS that is the root unless the
38    /// `telecom/msg` SETPATHs are issued first.
39    ///
40    /// # Errors
41    ///
42    /// Returns [`MapError`] if a backup or forward SETPATH fails, the server returns a
43    /// non-OK response, or the listing XML is malformed.
44    pub async fn list_message_folders(&mut self) -> Result<FolderListing, MapError> {
45        self.reset_to_root().await?;
46        self.setpath("telecom").await?;
47        self.setpath("msg").await?;
48        self.get_folder_listing().await
49    }
50}