using System; using System.Windows.Forms; using BulkArchiveMailer.Core; using Outlook = Microsoft.Office.Interop.Outlook; namespace BulkArchiveMailer.AddIn.UI { /// /// Archive folder, email domain, signature override, test-mode default, /// and the two editable mail templates. Saves straight to /// %APPDATA%\BulkArchiveMailer\config.json via AppSettings. /// public partial class SettingsForm : Form { private readonly Outlook.Application outlookApplication; public SettingsForm(Outlook.Application outlookApplication) { InitializeComponent(); this.outlookApplication = outlookApplication; Load += SettingsForm_Load; } private void SettingsForm_Load(object sender, EventArgs e) { AppSettingsData settings; try { settings = AppSettings.Load(); } catch (Exception ex) { MessageBox.Show( "Не удалось прочитать config.json (" + AppSettings.ConfigFilePath + "):\n" + ex.ToString() + "\n\nБудут показаны пустые настройки — сохранение перезапишет файл заново.", "BulkArchiveMailer", MessageBoxButtons.OK, MessageBoxIcon.Warning); settings = new AppSettingsData(); } PopulateFrom(settings); } /// ComboBox item: displays a friendly label but carries the SmtpAddress that actually gets saved to config.json. The first item (SmtpAddress == "") represents "let Outlook pick its default account". private sealed class FromAccountItem { public string Label { get; set; } = ""; public string SmtpAddress { get; set; } = ""; public override string ToString() => Label; } private const string DefaultAccountLabel = "(по умолчанию Outlook)"; private void PopulateFrom(AppSettingsData settings) { txtArchiveFolder.Text = settings.ArchiveFolder ?? ""; txtDomain.Text = settings.EmailDomain ?? ""; txtSignaturePath.Text = settings.SignatureHtmlPath ?? ""; chkTestModeDefault.Checked = settings.TestModeDefault; PopulateFromAccountCombo(settings.FromAccountSmtpAddress ?? ""); var templates = settings.ToTemplateSet(); txtSshSubject.Text = templates.SshAccess.Subject; txtSshBody.Text = templates.SshAccess.BodyHtml; txtCfgSubject.Text = templates.ConfigUpdate.Subject; txtCfgBody.Text = templates.ConfigUpdate.BodyHtml; } /// /// Fills cboFromAccount with "(по умолчанию Outlook)" plus one /// entry per real Outlook.Account in the current session, then /// selects the item matching savedSmtpAddress. If that address no /// longer belongs to any account in this session (removed/renamed /// since it was configured, or Outlook.Application is unavailable /// e.g. under a design-time host), it just falls back to the /// default item instead of throwing - never blocks opening the /// Settings window over this. /// private void PopulateFromAccountCombo(string savedSmtpAddress) { cboFromAccount.Items.Clear(); cboFromAccount.Items.Add(new FromAccountItem { Label = DefaultAccountLabel, SmtpAddress = "" }); if (outlookApplication != null) { foreach (var account in OutlookAccounts.ListAccounts(outlookApplication)) { var label = string.IsNullOrEmpty(account.SmtpAddress) ? account.DisplayName : account.DisplayName + " <" + account.SmtpAddress + ">"; cboFromAccount.Items.Add(new FromAccountItem { Label = label, SmtpAddress = account.SmtpAddress }); } } var selectedIndex = 0; if (!string.IsNullOrEmpty(savedSmtpAddress)) { for (var i = 0; i < cboFromAccount.Items.Count; i++) { var item = (FromAccountItem)cboFromAccount.Items[i]; if (string.Equals(item.SmtpAddress, savedSmtpAddress, StringComparison.OrdinalIgnoreCase)) { selectedIndex = i; break; } } } cboFromAccount.SelectedIndex = selectedIndex; } private void btnBrowseFolder_Click(object sender, EventArgs e) { using (var dialog = new FolderBrowserDialog()) { dialog.Description = "Папка с архивами, которые ssh-access-tui выкладывает для рассылки"; if (System.IO.Directory.Exists(txtArchiveFolder.Text)) { dialog.SelectedPath = txtArchiveFolder.Text; } if (dialog.ShowDialog(this) == DialogResult.OK) { txtArchiveFolder.Text = dialog.SelectedPath; } } } private void btnBrowseSignature_Click(object sender, EventArgs e) { using (var dialog = new OpenFileDialog()) { dialog.Title = "Выберите файл подписи"; dialog.Filter = "HTML-подпись (*.htm;*.html)|*.htm;*.html|Все файлы (*.*)|*.*"; if (dialog.ShowDialog(this) == DialogResult.OK) { txtSignaturePath.Text = dialog.FileName; } } } private void btnAutoDetectSignature_Click(object sender, EventArgs e) { if (outlookApplication == null) { MessageBox.Show(this, "Outlook.Application недоступен в этом окне.", "BulkArchiveMailer", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } var path = SignatureReader.TryAutoDetectSignaturePath(outlookApplication); if (string.IsNullOrEmpty(path)) { MessageBox.Show( this, "Не удалось определить подпись автоматически (не настроена подпись по умолчанию для новых писем, либо файл не найден). Выберите файл вручную кнопкой \"Обзор...\".", "BulkArchiveMailer", MessageBoxButtons.OK, MessageBoxIcon.Information); return; } txtSignaturePath.Text = path; } private void btnResetDefaults_Click(object sender, EventArgs e) { var confirm = MessageBox.Show( this, "Заменить домен и оба шаблона писем значениями по умолчанию? Папка с архивами и файл подписи не изменятся. Несохранённые правки в этом окне будут потеряны.", "Подтверждение", MessageBoxButtons.YesNo, MessageBoxIcon.Question); if (confirm != DialogResult.Yes) { return; } var defaults = AppSettings.LoadDefaults(); txtDomain.Text = defaults.EmailDomain; var templates = defaults.ToTemplateSet(); txtSshSubject.Text = templates.SshAccess.Subject; txtSshBody.Text = templates.SshAccess.BodyHtml; txtCfgSubject.Text = templates.ConfigUpdate.Subject; txtCfgBody.Text = templates.ConfigUpdate.BodyHtml; } private void btnSave_Click(object sender, EventArgs e) { if (string.IsNullOrWhiteSpace(txtDomain.Text)) { MessageBox.Show(this, "Домен электронной почты не может быть пустым.", "BulkArchiveMailer", MessageBoxButtons.OK, MessageBoxIcon.Warning); tabControl.SelectedTab = tabGeneral; txtDomain.Focus(); return; } if (!string.IsNullOrWhiteSpace(txtArchiveFolder.Text) && !System.IO.Directory.Exists(txtArchiveFolder.Text)) { var proceed = MessageBox.Show( this, "Указанная папка с архивами не существует:\n" + txtArchiveFolder.Text + "\n\nВсё равно сохранить?", "BulkArchiveMailer", MessageBoxButtons.YesNo, MessageBoxIcon.Warning); if (proceed != DialogResult.Yes) { tabControl.SelectedTab = tabGeneral; return; } } var selectedAccount = cboFromAccount.SelectedItem as FromAccountItem; var data = new AppSettingsData { ArchiveFolder = txtArchiveFolder.Text.Trim(), EmailDomain = txtDomain.Text.Trim(), SignatureHtmlPath = txtSignaturePath.Text.Trim(), TestModeDefault = chkTestModeDefault.Checked, FromAccountSmtpAddress = selectedAccount?.SmtpAddress ?? "", }; data.SetTemplate(ArchiveKind.SshAccess, new MailTemplate { Subject = txtSshSubject.Text, BodyHtml = txtSshBody.Text }); data.SetTemplate(ArchiveKind.ConfigUpdate, new MailTemplate { Subject = txtCfgSubject.Text, BodyHtml = txtCfgBody.Text }); try { AppSettings.Save(data); } catch (Exception ex) { MessageBox.Show(this, "Не удалось сохранить настройки: " + ex.ToString(), "BulkArchiveMailer", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } DialogResult = DialogResult.OK; Close(); } private void btnCancel_Click(object sender, EventArgs e) { DialogResult = DialogResult.Cancel; Close(); } } }