Fixes #3964 - Selecting custom ports for mail channel ends in 'host not reachable'.

This commit is contained in:
Rolf Schmidt 2022-03-03 10:04:12 +01:00
parent 8671aea0b4
commit cc9977460e
14 changed files with 118 additions and 36 deletions

View file

@ -307,6 +307,7 @@ class ChannelEmailAccountWizard extends App.ControllerWizardModal
events: events:
'submit .js-intro': 'probeBasedOnIntro' 'submit .js-intro': 'probeBasedOnIntro'
'submit .js-inbound': 'probeInbound' 'submit .js-inbound': 'probeInbound'
'change .js-inbound [name=adapter]': 'toggleInboundAdapter'
'change .js-outbound [name=adapter]': 'toggleOutboundAdapter' 'change .js-outbound [name=adapter]': 'toggleOutboundAdapter'
'submit .js-outbound': 'probleOutbound' 'submit .js-outbound': 'probleOutbound'
'click .js-goToSlide': 'goToSlide' 'click .js-goToSlide': 'goToSlide'
@ -404,7 +405,7 @@ class ChannelEmailAccountWizard extends App.ControllerWizardModal
{ name: 'options::host', display: __('Host'), tag: 'input', type: 'text', limit: 120, null: false, autocapitalize: false }, { name: 'options::host', display: __('Host'), tag: 'input', type: 'text', limit: 120, null: false, autocapitalize: false },
{ name: 'options::user', display: __('User'), tag: 'input', type: 'text', limit: 120, null: false, autocapitalize: false, autocomplete: 'off' }, { name: 'options::user', display: __('User'), tag: 'input', type: 'text', limit: 120, null: false, autocapitalize: false, autocomplete: 'off' },
{ name: 'options::password', display: __('Password'), tag: 'input', type: 'password', limit: 120, null: false, autocapitalize: false, autocomplete: 'new-password', single: true }, { name: 'options::password', display: __('Password'), tag: 'input', type: 'password', limit: 120, null: false, autocapitalize: false, autocomplete: 'new-password', single: true },
{ name: 'options::ssl', display: __('SSL/STARTTLS'), tag: 'boolean', null: true, options: { true: 'yes', false: 'no' }, default: true, translate: true, item_class: 'formGroup--halfSize' }, { name: 'options::ssl', display: __('SSL/STARTTLS'), tag: 'select', null: true, options: { 'off': __('No SSL'), 'ssl': __('SSL'), 'starttls': __('STARTTLS') }, default: 'ssl', translate: true, item_class: 'formGroup--halfSize' },
{ name: 'options::port', display: __('Port'), tag: 'input', type: 'text', limit: 6, null: true, autocapitalize: false, default: '993', item_class: 'formGroup--halfSize' }, { name: 'options::port', display: __('Port'), tag: 'input', type: 'text', limit: 6, null: true, autocapitalize: false, default: '993', item_class: 'formGroup--halfSize' },
{ name: 'options::folder', display: __('Folder'), tag: 'input', type: 'text', limit: 120, null: true, autocapitalize: false, item_class: 'formGroup--halfSize' }, { name: 'options::folder', display: __('Folder'), tag: 'input', type: 'text', limit: 120, null: true, autocapitalize: false, item_class: 'formGroup--halfSize' },
{ name: 'options::keep_on_server', display: __('Keep messages on server'), tag: 'boolean', null: true, options: { true: 'yes', false: 'no' }, translate: true, default: false, item_class: 'formGroup--halfSize' }, { name: 'options::keep_on_server', display: __('Keep messages on server'), tag: 'boolean', null: true, options: { true: 'yes', false: 'no' }, translate: true, default: false, item_class: 'formGroup--halfSize' },
@ -438,14 +439,26 @@ class ChannelEmailAccountWizard extends App.ControllerWizardModal
showHideFolder, showHideFolder,
] ]
) )
@toggleInboundAdapter()
form.el.find("select[name='options::ssl']").off('change').on('change', (e) -> form.el.find("select[name='options::ssl']").off('change').on('change', (e) ->
if $(e.target).val() is 'true' if $(e.target).val() is 'ssl'
form.el.find("[name='options::port']").val('993') form.el.find("[name='options::port']").val('993')
else else if $(e.target).val() is 'off'
form.el.find("[name='options::port']").val('143') form.el.find("[name='options::port']").val('143')
) )
toggleInboundAdapter: =>
form = @$('.base-inbound-settings')
adapter = form.find("select[name='adapter']")
starttls = form.find("select[name='options::ssl'] option[value='starttls']")
if adapter.val() isnt 'imap'
starttls.remove()
else if starttls.length < 1
starttls = $('<option/>').attr('value', 'starttls').text(__('STARTTLS'))
form.find("select[name='options::ssl']").append(starttls)
toggleOutboundAdapter: => toggleOutboundAdapter: =>
# fill user / password based on intro info # fill user / password based on intro info

View file

@ -2,6 +2,7 @@ class GettingStartedChannelEmail extends App.ControllerWizardFullScreen
events: events:
'submit .js-intro': 'probeBasedOnIntro' 'submit .js-intro': 'probeBasedOnIntro'
'submit .js-inbound': 'probeInbound' 'submit .js-inbound': 'probeInbound'
'change .js-inbound [name=adapter]': 'toggleInboundAdapter'
'change .js-outbound [name=adapter]': 'toggleOutboundAdapter' 'change .js-outbound [name=adapter]': 'toggleOutboundAdapter'
'submit .js-outbound': 'probleOutbound' 'submit .js-outbound': 'probleOutbound'
'click .js-goToSlide': 'goToSlide' 'click .js-goToSlide': 'goToSlide'
@ -76,7 +77,7 @@ class GettingStartedChannelEmail extends App.ControllerWizardFullScreen
{ name: 'options::host', display: __('Host'), tag: 'input', type: 'text', limit: 120, null: false, autocapitalize: false }, { name: 'options::host', display: __('Host'), tag: 'input', type: 'text', limit: 120, null: false, autocapitalize: false },
{ name: 'options::user', display: __('User'), tag: 'input', type: 'text', limit: 120, null: false, autocapitalize: false, autocomplete: 'off', }, { name: 'options::user', display: __('User'), tag: 'input', type: 'text', limit: 120, null: false, autocapitalize: false, autocomplete: 'off', },
{ name: 'options::password', display: __('Password'), tag: 'input', type: 'password', limit: 120, null: false, autocapitalize: false, autocomplete: 'off', single: true }, { name: 'options::password', display: __('Password'), tag: 'input', type: 'password', limit: 120, null: false, autocapitalize: false, autocomplete: 'off', single: true },
{ name: 'options::ssl', display: __('SSL/STARTTLS'), tag: 'boolean', null: true, options: { true: 'yes', false: 'no' }, default: true, translate: true, item_class: 'formGroup--halfSize' }, { name: 'options::ssl', display: __('SSL/STARTTLS'), tag: 'select', null: true, options: { 'off': __('No SSL'), 'ssl': __('SSL'), 'starttls': __('STARTTLS') }, default: 'ssl', translate: true, item_class: 'formGroup--halfSize' },
{ name: 'options::port', display: __('Port'), tag: 'input', type: 'text', limit: 6, null: true, autocapitalize: false, default: '993', item_class: 'formGroup--halfSize' }, { name: 'options::port', display: __('Port'), tag: 'input', type: 'text', limit: 6, null: true, autocapitalize: false, default: '993', item_class: 'formGroup--halfSize' },
{ name: 'options::folder', display: __('Folder'), tag: 'input', type: 'text', limit: 120, null: true, autocapitalize: false, item_class: 'formGroup--halfSize' }, { name: 'options::folder', display: __('Folder'), tag: 'input', type: 'text', limit: 120, null: true, autocapitalize: false, item_class: 'formGroup--halfSize' },
{ name: 'options::keep_on_server', display: __('Keep messages on server'), tag: 'boolean', null: true, options: { true: 'yes', false: 'no' }, translate: true, default: false, item_class: 'formGroup--halfSize' }, { name: 'options::keep_on_server', display: __('Keep messages on server'), tag: 'boolean', null: true, options: { true: 'yes', false: 'no' }, translate: true, default: false, item_class: 'formGroup--halfSize' },
@ -101,14 +102,26 @@ class GettingStartedChannelEmail extends App.ControllerWizardFullScreen
showHideFolder, showHideFolder,
] ]
) )
@toggleInboundAdapter()
form.el.find("select[name='options::ssl']").off('change').on('change', (e) -> form.el.find("select[name='options::ssl']").off('change').on('change', (e) ->
if $(e.target).val() is 'true' if $(e.target).val() is 'ssl'
form.el.find("[name='options::port']").val('993') form.el.find("[name='options::port']").val('993')
else else if $(e.target).val() is 'off'
form.el.find("[name='options::port']").val('143') form.el.find("[name='options::port']").val('143')
) )
toggleInboundAdapter: =>
form = @$('.base-inbound-settings')
adapter = form.find("select[name='adapter']")
starttls = form.find("select[name='options::ssl'] option[value='starttls']")
if adapter.val() isnt 'imap'
starttls.remove()
else if starttls.length < 1
starttls = $('<option/>').attr('value', 'starttls').text(__('STARTTLS'))
form.find("select[name='options::ssl']").append(starttls)
toggleOutboundAdapter: => toggleOutboundAdapter: =>
# fill user / password based on intro info # fill user / password based on intro info

View file

@ -87,9 +87,12 @@ example
keep_on_server = true keep_on_server = true
end end
if options.key?(:ssl) && options[:ssl] == false case options[:ssl]
when 'off'
ssl = false ssl = false
port = 143 when 'starttls'
ssl = false
starttls = true
end end
port = if options.key?(:port) && options[:port].present? port = if options.key?(:port) && options[:port].present?
@ -100,11 +103,6 @@ example
143 143
end end
if ssl == true && port != 993
ssl = false
starttls = true
end
if options[:folder].present? if options[:folder].present?
folder = options[:folder] folder = options[:folder]
end end

View file

@ -46,18 +46,16 @@ returns
def fetch(options, channel, check_type = '', verify_string = '') def fetch(options, channel, check_type = '', verify_string = '')
ssl = true ssl = true
port = 995 if options[:ssl] == 'off'
if options.key?(:ssl) && options[:ssl] == false
ssl = false ssl = false
port = 110
end end
if options.key?(:port) && options[:port].present?
port = options[:port]
# disable ssl for non ssl ports port = if options.key?(:port) && options[:port].present?
if port == 110 && !options.key?(:ssl) options[:port].to_i
ssl = false elsif ssl == true
end 995
else
110
end end
Rails.logger.info "fetching pop3 (#{options[:host]}/#{options[:user]} port=#{port},ssl=#{ssl})" Rails.logger.info "fetching pop3 (#{options[:host]}/#{options[:user]} port=#{port},ssl=#{ssl})"

View file

@ -0,0 +1,21 @@
# Copyright (C) 2012-2022 Zammad Foundation, https://zammad-foundation.org/
class Issue3964InboundFixOptions < ActiveRecord::Migration[6.0]
def change
# return if it's a new setup
return if !Setting.exists?(name: 'system_init_done')
Channel.where(area: ['Email::Account', 'Google::Account', 'Microsoft365::Account']).find_each do |channel|
ssl = channel.options.dig(:inbound, :options, :ssl)
next if ssl.nil?
channel.options[:inbound][:options][:ssl] = if ssl == true
'ssl'
else
'off'
end
channel.save!
end
end
end

View file

@ -6350,6 +6350,11 @@ msgstr ""
msgid "No Proxy" msgid "No Proxy"
msgstr "" msgstr ""
#: app/assets/javascripts/app/controllers/_channel/email.coffee
#: app/assets/javascripts/app/controllers/getting_started/channel_email.coffee
msgid "No SSL"
msgstr ""
#: app/assets/javascripts/app/controllers/_plugin/translation_support.coffee #: app/assets/javascripts/app/controllers/_plugin/translation_support.coffee
msgid "No Thanks!" msgid "No Thanks!"
msgstr "" msgstr ""
@ -7770,6 +7775,11 @@ msgstr ""
msgid "SMTP - configure your own outgoing SMTP settings" msgid "SMTP - configure your own outgoing SMTP settings"
msgstr "" msgstr ""
#: app/assets/javascripts/app/controllers/_channel/email.coffee
#: app/assets/javascripts/app/controllers/getting_started/channel_email.coffee
msgid "SSL"
msgstr ""
#: app/assets/javascripts/app/models/webhook.coffee #: app/assets/javascripts/app/models/webhook.coffee
msgid "SSL Verify" msgid "SSL Verify"
msgstr "" msgstr ""
@ -7787,6 +7797,11 @@ msgstr ""
msgid "SSO" msgid "SSO"
msgstr "" msgstr ""
#: app/assets/javascripts/app/controllers/_channel/email.coffee
#: app/assets/javascripts/app/controllers/getting_started/channel_email.coffee
msgid "STARTTLS"
msgstr ""
#: app/assets/javascripts/app/controllers/_ui_element/basedate.coffee #: app/assets/javascripts/app/controllers/_ui_element/basedate.coffee
msgid "Sat" msgid "Sat"
msgstr "" msgstr ""

View file

@ -49,7 +49,7 @@ class ExternalCredential::Google
options: { options: {
auth_type: 'XOAUTH2', auth_type: 'XOAUTH2',
host: 'imap.gmail.com', host: 'imap.gmail.com',
ssl: true, ssl: 'ssl',
user: user_data[:email], user: user_data[:email],
}, },
}, },

View file

@ -53,7 +53,7 @@ class ExternalCredential::Microsoft365
options: { options: {
auth_type: 'XOAUTH2', auth_type: 'XOAUTH2',
host: 'outlook.office365.com', host: 'outlook.office365.com',
ssl: true, ssl: 'ssl',
user: user_data[:preferred_username], user: user_data[:preferred_username],
}, },
}, },

View file

@ -0,0 +1,24 @@
# Copyright (C) 2012-2022 Zammad Foundation, https://zammad-foundation.org/
require 'rails_helper'
RSpec.describe Issue3964InboundFixOptions, type: :db_migration do
let(:channel1) { create(:google_channel) }
let(:channel2) { create(:google_channel) }
before do
channel1.options[:inbound][:options][:ssl] = true
channel1.save
channel2.options[:inbound][:options][:ssl] = false
channel2.save
migrate
end
it 'sets the correct ssl value for ssl true' do
expect(channel1.reload.options[:inbound][:options][:ssl]).to eq('ssl')
end
it 'sets the correct ssl value for ssl false' do
expect(channel2.reload.options[:inbound][:options][:ssl]).to eq('off')
end
end

View file

@ -133,7 +133,7 @@ FactoryBot.define do
'options' => { 'options' => {
'auth_type' => 'XOAUTH2', 'auth_type' => 'XOAUTH2',
'host' => 'imap.gmail.com', 'host' => 'imap.gmail.com',
'ssl' => true, 'ssl' => 'ssl',
'user' => ENV['GMAIL_USER'], 'user' => ENV['GMAIL_USER'],
'folder' => '', 'folder' => '',
'keep_on_server' => false, 'keep_on_server' => false,
@ -175,7 +175,7 @@ FactoryBot.define do
'options' => { 'options' => {
'auth_type' => 'XOAUTH2', 'auth_type' => 'XOAUTH2',
'host' => 'outlook.office365.com', 'host' => 'outlook.office365.com',
'ssl' => true, 'ssl' => 'ssl',
'user' => ENV['MICROSOFT365_USER'], 'user' => ENV['MICROSOFT365_USER'],
'folder' => '', 'folder' => '',
'keep_on_server' => false, 'keep_on_server' => false,

View file

@ -188,7 +188,7 @@ RSpec.describe AutoWizard do
host: 'mx1.example.com', host: 'mx1.example.com',
user: 'not_existing', user: 'not_existing',
password: 'some_pass', password: 'some_pass',
ssl: true ssl: 'ssl'
} }
}, },
outbound: { outbound: {
@ -227,7 +227,7 @@ RSpec.describe AutoWizard do
host: 'mx1.example.com', host: 'mx1.example.com',
user: 'not_existing', user: 'not_existing',
password: 'some_pass', password: 'some_pass',
ssl: true ssl: 'ssl'
} }
}, },
outbound: { outbound: {

View file

@ -121,7 +121,7 @@ RSpec.describe ExternalCredential::Google do
'options' => a_hash_including( 'options' => a_hash_including(
'auth_type' => 'XOAUTH2', 'auth_type' => 'XOAUTH2',
'host' => 'imap.gmail.com', 'host' => 'imap.gmail.com',
'ssl' => true, 'ssl' => 'ssl',
'user' => primary_email, 'user' => primary_email,
) )
), ),

View file

@ -87,7 +87,7 @@ RSpec.describe ExternalCredential::Microsoft365 do
'options' => a_hash_including( 'options' => a_hash_including(
'auth_type' => 'XOAUTH2', 'auth_type' => 'XOAUTH2',
'host' => 'outlook.office365.com', 'host' => 'outlook.office365.com',
'ssl' => true, 'ssl' => 'ssl',
'user' => email_address, 'user' => email_address,
) )
), ),

View file

@ -151,8 +151,8 @@ RSpec.describe 'Manage > Channels > Email', type: :system do
click '.js-expert' click '.js-expert'
expect(find('input[name="options::port"]').value).to eq('993') expect(find('input[name="options::port"]').value).to eq('993')
field = find('select[name="options::ssl"]') field = find('select[name="options::ssl"]')
option_yes = field.find(:option, 'yes') option_yes = field.find(:option, 'SSL')
option_no = field.find(:option, 'no') option_no = field.find(:option, 'No SSL')
option_no.select_option option_no.select_option
expect(find('input[name="options::port"]').value).to eq('143') expect(find('input[name="options::port"]').value).to eq('143')
option_yes.select_option option_yes.select_option