outlook_mapi/
mapi_logon.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT license.
3
4//! Define [`Logon`] and [`LogonFlags`].
5
6use crate::{Initialize, sys};
7use std::{iter, ptr, sync::Arc};
8use windows::Win32::Foundation::*;
9use windows_core::*;
10
11/// Set of flags that can be passed to [`sys::MAPILogonEx`].
12#[derive(Default)]
13pub struct LogonFlags {
14    /// Pass [`sys::MAPI_ALLOW_OTHERS`].
15    pub allow_others: bool,
16
17    /// Pass [`sys::MAPI_BG_SESSION`].
18    pub bg_session: bool,
19
20    /// Pass [`sys::MAPI_EXPLICIT_PROFILE`].
21    pub explicit_profile: bool,
22
23    /// Pass [`sys::MAPI_EXTENDED`].
24    pub extended: bool,
25
26    /// Pass [`sys::MAPI_FORCE_DOWNLOAD`].
27    pub force_download: bool,
28
29    /// Pass [`sys::MAPI_LOGON_UI`].
30    pub logon_ui: bool,
31
32    /// Pass [`sys::MAPI_NEW_SESSION`].
33    pub new_session: bool,
34
35    /// Pass [`sys::MAPI_NO_MAIL`].
36    pub no_mail: bool,
37
38    /// Pass [`sys::MAPI_NT_SERVICE`].
39    pub nt_service: bool,
40
41    /// Pass [`sys::MAPI_SERVICE_UI_ALWAYS`].
42    pub service_ui_always: bool,
43
44    /// Pass [`sys::MAPI_TIMEOUT_SHORT`].
45    pub timeout_short: bool,
46
47    /// Pass [`sys::MAPI_UNICODE`].
48    pub unicode: bool,
49
50    /// Pass [`sys::MAPI_USE_DEFAULT`].
51    pub use_default: bool,
52}
53
54impl From<LogonFlags> for u32 {
55    fn from(value: LogonFlags) -> Self {
56        let allow_others = if value.allow_others {
57            sys::MAPI_ALLOW_OTHERS
58        } else {
59            0
60        };
61        let bg_session = if value.bg_session {
62            sys::MAPI_BG_SESSION
63        } else {
64            0
65        };
66        let explicit_profile = if value.explicit_profile {
67            sys::MAPI_EXPLICIT_PROFILE
68        } else {
69            0
70        };
71        let extended = if value.extended {
72            sys::MAPI_EXTENDED
73        } else {
74            0
75        };
76        let force_download = if value.force_download {
77            sys::MAPI_FORCE_DOWNLOAD
78        } else {
79            0
80        };
81        let logon_ui = if value.logon_ui {
82            sys::MAPI_LOGON_UI
83        } else {
84            0
85        };
86        let new_session = if value.new_session {
87            sys::MAPI_NEW_SESSION
88        } else {
89            0
90        };
91        let no_mail = if value.no_mail { sys::MAPI_NO_MAIL } else { 0 };
92        let nt_service = if value.nt_service {
93            sys::MAPI_NT_SERVICE
94        } else {
95            0
96        };
97        let service_ui_always = if value.service_ui_always {
98            sys::MAPI_SERVICE_UI_ALWAYS
99        } else {
100            0
101        };
102        let timeout_short = if value.timeout_short {
103            sys::MAPI_TIMEOUT_SHORT
104        } else {
105            0
106        };
107        let unicode = if value.unicode { sys::MAPI_UNICODE } else { 0 };
108        let use_default = if value.use_default {
109            sys::MAPI_USE_DEFAULT
110        } else {
111            0
112        };
113
114        allow_others
115            | bg_session
116            | explicit_profile
117            | extended
118            | force_download
119            | logon_ui
120            | new_session
121            | no_mail
122            | nt_service
123            | service_ui_always
124            | timeout_short
125            | unicode
126            | use_default
127    }
128}
129
130/// Call [`sys::MAPILogonEx`] and hold on to the [`sys::IMAPISession`].
131///
132/// This helper also holds onto an `Arc<Initialize>`, which ensures that there are balanced calls
133/// to [`sys::MAPIInitialize`] and [`sys::MAPIUninitialize`] around every [`Logon`] object that
134/// shares a reference to that instance of [`Initialize`].
135pub struct Logon {
136    /// Access the [`sys::IMAPISession`].
137    pub session: sys::IMAPISession,
138
139    _initialized: Arc<Initialize>,
140}
141
142impl Logon {
143    pub fn new(
144        initialized: Arc<Initialize>,
145        ui_param: HWND,
146        profile_name: Option<&str>,
147        password: Option<&str>,
148        flags: LogonFlags,
149    ) -> Result<Self> {
150        let mut profile_name: Option<Vec<_>> =
151            profile_name.map(|value| value.bytes().chain(iter::once(0)).collect());
152        let profile_name = profile_name
153            .as_mut()
154            .map(|value| value.as_mut_ptr())
155            .unwrap_or(ptr::null_mut());
156        let mut password: Option<Vec<_>> =
157            password.map(|value| value.bytes().chain(iter::once(0)).collect());
158        let password = password
159            .as_mut()
160            .map(|value| value.as_mut_ptr())
161            .unwrap_or(ptr::null_mut());
162
163        Ok(Self {
164            _initialized: initialized,
165            session: unsafe {
166                let mut session = None;
167                sys::MAPILogonEx(
168                    ui_param.0 as usize,
169                    profile_name as *mut _,
170                    password as *mut _,
171                    flags.into(),
172                    ptr::from_mut(&mut session),
173                )?;
174                session
175            }
176            .ok_or_else(|| Error::from(E_FAIL))?,
177        })
178    }
179}