1 """Config flow for imap integration."""
3 from __future__
import annotations
5 from collections.abc
import Mapping
9 from aioimaplib
import AioImapException
10 import voluptuous
as vol
34 TemplateSelectorConfig,
40 CONF_CUSTOM_EVENT_DATA_TEMPLATE,
42 CONF_EVENT_MESSAGE_DATA,
44 CONF_MAX_MESSAGE_SIZE,
48 DEFAULT_MAX_MESSAGE_SIZE,
51 MAX_MESSAGE_SIZE_LIMIT,
54 from .coordinator
import connect_to_server
55 from .errors
import InvalidAuth, InvalidFolder
60 options=
list(SSLCipherList),
61 mode=SelectSelectorMode.DROPDOWN,
62 translation_key=CONF_SSL_CIPHER_LIST,
68 options=MESSAGE_DATA_OPTIONS,
69 translation_key=CONF_EVENT_MESSAGE_DATA,
74 CONFIG_SCHEMA = vol.Schema(
76 vol.Required(CONF_USERNAME): str,
77 vol.Required(CONF_PASSWORD): str,
78 vol.Required(CONF_SERVER): str,
79 vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port,
80 vol.Optional(CONF_CHARSET, default=
"utf-8"): str,
81 vol.Optional(CONF_FOLDER, default=
"INBOX"): str,
82 vol.Optional(CONF_SEARCH, default=
"UnSeen UnDeleted"): str,
84 vol.Optional(CONF_EVENT_MESSAGE_DATA, default=[]): EVENT_MESSAGE_DATA_SELECTOR,
87 CONFIG_SCHEMA_ADVANCED = {
89 CONF_SSL_CIPHER_LIST, default=SSLCipherList.PYTHON_DEFAULT
91 vol.Optional(CONF_VERIFY_SSL, default=
True): BOOLEAN_SELECTOR,
94 OPTIONS_SCHEMA = vol.Schema(
96 vol.Optional(CONF_FOLDER, default=
"INBOX"): str,
97 vol.Optional(CONF_SEARCH, default=
"UnSeen UnDeleted"): str,
100 CONF_EVENT_MESSAGE_DATA, default=MESSAGE_DATA_OPTIONS
101 ): EVENT_MESSAGE_DATA_SELECTOR,
105 OPTIONS_SCHEMA_ADVANCED = {
106 vol.Optional(CONF_CUSTOM_EVENT_DATA_TEMPLATE): TEMPLATE_SELECTOR,
107 vol.Optional(CONF_MAX_MESSAGE_SIZE, default=DEFAULT_MAX_MESSAGE_SIZE): vol.All(
109 vol.Range(min=DEFAULT_MAX_MESSAGE_SIZE, max=MAX_MESSAGE_SIZE_LIMIT),
111 vol.Optional(CONF_ENABLE_PUSH, default=
True): BOOLEAN_SELECTOR,
116 hass: HomeAssistant, user_input: dict[str, Any]
118 """Validate user input."""
123 result, lines = await imap_client.search(
124 user_input[CONF_SEARCH],
125 charset=user_input[CONF_CHARSET],
129 errors[CONF_USERNAME] = errors[CONF_PASSWORD] =
"invalid_auth"
130 except InvalidFolder:
131 errors[CONF_FOLDER] =
"invalid_folder"
136 errors[
"base"] =
"ssl_error"
137 except (TimeoutError, AioImapException, ConnectionRefusedError):
138 errors[
"base"] =
"cannot_connect"
141 if "The specified charset is not supported" in lines[0].decode(
"utf-8"):
142 errors[CONF_CHARSET] =
"invalid_charset"
144 errors[CONF_SEARCH] =
"invalid_search"
150 """Handle a config flow for imap."""
155 self, user_input: dict[str, Any] |
None =
None
156 ) -> ConfigFlowResult:
157 """Handle the initial step."""
159 schema = CONFIG_SCHEMA
161 schema = schema.extend(CONFIG_SCHEMA_ADVANCED)
163 if user_input
is None:
169 for key
in (CONF_USERNAME, CONF_SERVER, CONF_FOLDER, CONF_SEARCH)
174 title = user_input[CONF_USERNAME]
182 self, entry_data: Mapping[str, Any]
183 ) -> ConfigFlowResult:
184 """Perform reauth upon an API authentication error."""
188 self, user_input: dict[str, str] |
None =
None
189 ) -> ConfigFlowResult:
190 """Confirm reauth dialog."""
193 if user_input
is not None:
194 user_input = {**reauth_entry.data, **user_input}
199 description_placeholders={
200 CONF_USERNAME: reauth_entry.data[CONF_USERNAME],
201 CONF_NAME: reauth_entry.title,
203 step_id=
"reauth_confirm",
204 data_schema=vol.Schema(
206 vol.Required(CONF_PASSWORD): str,
215 config_entry: ConfigEntry,
216 ) -> ImapOptionsFlow:
217 """Get the options flow for this handler."""
222 """Option flow handler."""
225 self, user_input: dict[str, Any] |
None =
None
226 ) -> ConfigFlowResult:
227 """Manage the options."""
228 errors: dict[str, str] |
None =
None
230 if user_input
is not None:
236 CONF_FOLDER: user_input[CONF_FOLDER],
237 CONF_SEARCH: user_input[CONF_SEARCH],
242 except AbortFlow
as err:
243 errors = {
"base": err.reason}
245 entry_data.update(user_input)
248 self.hass.config_entries.async_update_entry(
251 self.hass.async_create_task(
252 self.hass.config_entries.async_reload(
258 schema = OPTIONS_SCHEMA
260 schema = schema.extend(OPTIONS_SCHEMA_ADVANCED)
263 return self.
async_show_formasync_show_form(step_id=
"init", data_schema=schema, errors=errors)
ConfigFlowResult async_step_user(self, dict[str, Any]|None user_input=None)
ConfigFlowResult async_step_reauth(self, Mapping[str, Any] entry_data)
ConfigFlowResult async_step_reauth_confirm(self, dict[str, str]|None user_input=None)
ImapOptionsFlow async_get_options_flow(ConfigEntry config_entry)
ConfigFlowResult async_step_init(self, dict[str, Any]|None user_input=None)
ConfigEntry _get_reauth_entry(self)
ConfigFlowResult async_create_entry(self, *str title, Mapping[str, Any] data, str|None description=None, Mapping[str, str]|None description_placeholders=None, Mapping[str, Any]|None options=None)
ConfigFlowResult async_update_reload_and_abort(self, ConfigEntry entry, *str|None|UndefinedType unique_id=UNDEFINED, str|UndefinedType title=UNDEFINED, Mapping[str, Any]|UndefinedType data=UNDEFINED, Mapping[str, Any]|UndefinedType data_updates=UNDEFINED, Mapping[str, Any]|UndefinedType options=UNDEFINED, str|UndefinedType reason=UNDEFINED, bool reload_even_if_entry_is_unchanged=True)
None _async_abort_entries_match(self, dict[str, Any]|None match_dict=None)
ConfigFlowResult async_show_form(self, *str|None step_id=None, vol.Schema|None data_schema=None, dict[str, str]|None errors=None, Mapping[str, str]|None description_placeholders=None, bool|None last_step=None, str|None preview=None)
None _async_abort_entries_match(self, dict[str, Any]|None match_dict=None)
ConfigEntry config_entry(self)
None config_entry(self, ConfigEntry value)
bool show_advanced_options(self)
vol.Schema add_suggested_values_to_schema(self, vol.Schema data_schema, Mapping[str, Any]|None suggested_values)
_FlowResultT async_show_form(self, *str|None step_id=None, vol.Schema|None data_schema=None, dict[str, str]|None errors=None, Mapping[str, str]|None description_placeholders=None, bool|None last_step=None, str|None preview=None)
_FlowResultT async_create_entry(self, *str|None title=None, Mapping[str, Any] data, str|None description=None, Mapping[str, str]|None description_placeholders=None)
dict[str, str] validate_input(HomeAssistant hass, dict[str, Any] user_input)
IMAP4_SSL connect_to_server(Mapping[str, Any] data)