diff --git a/agent_based/curl.py b/agent_based/curl.py
index d5563422f08802adcb14eb4f091305a68f0fe4a4..34030d6accb16fb422f4d64969df2cf0253570c1 100644
--- a/agent_based/curl.py
+++ b/agent_based/curl.py
@@ -28,6 +28,7 @@
 # 2022-04-26: made http(s) URLs clickable
 # 2022-05-15: added workaround for raise ValueError("Cannot render negative timespan")
 # 2022-05-17: fixed wrong import path for  _TIME_UNITS and _gen_timespan_chunks
+# 2023-06-07: moved gui files to ~/local/lib/chek_mk/gui/plugins/...
 #
 
 # Example output from agent:
diff --git a/curl-0.1.9-20230607.mkp b/curl-0.1.9-20230607.mkp
new file mode 100644
index 0000000000000000000000000000000000000000..554db2d6b2669da4a6a773151f2804ddb3f6d211
Binary files /dev/null and b/curl-0.1.9-20230607.mkp differ
diff --git a/curl.mkp b/curl.mkp
index 8a38d4db2aaadcc599b9392c916fd4727df5c172..554db2d6b2669da4a6a773151f2804ddb3f6d211 100644
Binary files a/curl.mkp and b/curl.mkp differ
diff --git a/gui/metrics/curl.py b/gui/metrics/curl.py
new file mode 100644
index 0000000000000000000000000000000000000000..bf186c5e436ba65459cd49fea5339465e8edd928
--- /dev/null
+++ b/gui/metrics/curl.py
@@ -0,0 +1,210 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# License: GNU General Public License v2
+#
+# Author: thl-cmk[at]outlook[dot]com
+# URL   : https://thl-cmk.hopto.org
+# Date  : 2022-02-15
+#
+# Metrics file for the curl plugin
+#
+# 2022-02-15: rewritten form cmk 2.0, based on the work by doc[at]snowheaven[dot]de
+# 2022-02-20: added num_connects, num_redirects, size_download, size_header and speed_download
+# 2022-03-13: moved cert time left graph to the end of graphs
+# 2022-05-17: added scalars to cert_time_left
+
+from cmk.gui.i18n import _
+
+from cmk.gui.plugins.metrics.utils import (
+    metric_info,
+    graph_info,
+    perfometer_info,
+)
+
+metric_info['time_namelookup'] = {
+    'title': _('Time name lookup'),
+    'unit': 's',
+    'color': '11/a',
+}
+metric_info['time_connect'] = {
+    'title': _('Time connect'),
+    'unit': 's',
+    'color': '21/a',
+}
+metric_info['time_appconnect'] = {
+    'title': _('Time app connect'),
+    'unit': 's',
+    'color': '31/b',
+}
+metric_info['time_pretransfer'] = {
+    'title': _('Time pre transfer'),
+    'unit': 's',
+    'color': '41/c',
+}
+metric_info['time_starttransfer'] = {
+    'title': _('Time start transfer'),
+    'unit': 's',
+    'color': '13/b',
+}
+metric_info['time_total'] = {
+    'title': _('Time Total'),
+    'unit': 's',
+    'color': '25/a',
+}
+metric_info['time_redirect'] = {
+    'title': _('Time redirect'),
+    'unit': 's',
+    'color': '33/b',
+}
+
+metric_info['num_connects'] = {
+    'title': _('# of connects'),
+    'unit': 'count',
+    'color': '14/a',
+}
+metric_info['num_redirects'] = {
+    'title': _('# of redirects'),
+    'unit': 'count',
+    'color': '24/b',
+}
+metric_info['num_headers'] = {
+    'title': _('# of headers'),
+    'unit': 'count',
+    'color': '34/b',
+}
+
+metric_info['size_download'] = {
+    'title': _('Size download'),
+    'unit': 'bytes',
+    'color': '15/b',
+}
+metric_info['size_upload'] = {
+    'title': _('Size upload'),
+    'unit': 'bytes',
+    'color': '25/b',
+}
+
+metric_info['size_header'] = {
+    'title': _('Size header'),
+    'unit': 'bytes',
+    'color': '35/b',
+}
+metric_info['size_request'] = {
+    'title': _('Size request'),
+    'unit': 'bytes',
+    'color': '14/b',
+}
+
+metric_info['speed_download'] = {
+    'title': _('Speed download'),
+    'unit': 'bytes/s',
+    'color': '23/a',
+}
+metric_info['speed_upload'] = {
+    'title': _('Speed upload'),
+    'unit': 'bytes/s',
+    'color': '13/a',
+}
+
+metric_info['cert_time_left'] = {
+    'title': _('Certificate Time left'),
+    'unit': 's',
+    'color': '33/b',
+}
+
+graph_info['curl_times_total'] = {
+    'title': _('Times total'),
+    'metrics': [
+        ('time_total', 'area'),
+    ],
+    'scalars': [
+        ('time_total:crit', _('crit')),
+        ('time_total:warn', _('warn')),
+    ],
+}
+graph_info['curl_times'] = {
+    'title': _('Times'),
+    'metrics': [
+        ('time_redirect', 'line'),
+        ('time_starttransfer', 'line'),
+        ('time_pretransfer', 'line'),
+        ('time_appconnect', 'line'),
+        ('time_connect', 'line'),
+        ('time_namelookup', 'line'),
+    ],
+    'optional_metrics': [
+        'time_redirect',
+        'time_starttransfer',
+        'time_pretransfer',
+        'time_appconnect',
+        'time_connect',
+        'time_namelookup',
+    ],
+}
+graph_info['curl_speed'] = {
+    'title': _('Speed'),
+    'metrics': [
+        ('speed_upload', '-area'),
+        ('speed_download', 'area'),
+    ],
+    'optional_metrics': [
+        'speed_download',
+        'speed_upload',
+    ],
+}
+graph_info['curl_size_download'] = {
+    'title': _('Size download/upload'),
+    'metrics': [
+        ('size_upload', '-area'),
+        ('size_download', 'area'),
+    ],
+    'optional_metrics': [
+        'size_upload',
+        'size_download',
+    ],
+}
+graph_info['curl_size_header'] = {
+    'title': _('Size header/request'),
+    'metrics': [
+        ('size_request', '-area'),
+        ('size_header', 'area'),
+    ],
+    'optional_metrics': [
+        'size_request',
+        'size_header',
+    ],
+}
+graph_info['curl_counts'] = {
+    'title': _('Counts'),
+    'metrics': [
+        ('num_redirects', '-line'),
+        ('num_connects', 'line'),
+        ('num_headers', 'line'),
+
+    ],
+    'optional_metrics': [
+        'num_connects',
+        'num_redirects',
+        'num_headers',
+    ],
+}
+graph_info['curl_cert_time'] = {
+    'title': _('Certificate time left'),
+    'metrics': [
+        ('cert_time_left', 'area'),
+    ],
+    'scalars': [
+        ('cert_time_left:crit', _('crit')),
+        ('cert_time_left:warn', _('warn')),
+    ],
+}
+
+perfometer_info.append(
+    {
+        'type': 'logarithmic',
+        'metric': 'time_total',
+        'half_value': 5.0,  # 5 seconds -> bar half full
+        'exponent': 2.0,  # every double of 5 == 10% of bar more full
+    },
+)
diff --git a/gui/wato/curl.py b/gui/wato/curl.py
new file mode 100644
index 0000000000000000000000000000000000000000..c55f0a5e7f488a82c4d9768c6441e1b739cf6b8a
--- /dev/null
+++ b/gui/wato/curl.py
@@ -0,0 +1,1330 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# License: GNU General Public License v2
+#
+# Author: thl-cmk[at]outlook[dot]com
+# URL   : https://thl-cmk.hopto.org
+# Date  : 2022-02-15
+#
+# WATO file for curl plugin (bakery and check)
+#
+# 2022-02-19: moved global options under "Default settings"
+#             added per url settings
+#             added proxy settings (--proxy, --proxy-user, --proxy-digest, --proxy-basic, --proxy-ntlm, --proxy-anyauth)
+#             added follow redirects (--location)
+#             added don't verify certificates (--insecure)
+# 2022-02-21: added tls/ssl version (--tlsv1.3, --tlsv1.2, --tlsv1.1, --tlsv1.0, --tlsv1,  --sslv3, --sslv2)
+#             added http version (--http2, --http1.1, --http1.0)
+#             added header only (--head)
+#             added user authentication (--user, --basic, --digest, --ntlm, --ntlm-wb, --negotiate, --anyauth)
+#             added to proxy authentication (--proxy-negotiate)
+# 2022-02-22: added option for cURL check plugin
+# 2022-02-24: changed forbidden_chars from '<>| ' to '"<>#%{}|\^~[]` ' + "'"
+# 2022-02-25: added plugin interval and timeout options
+#             added noproxy option to default settings
+# 2022-02-26: added proxy protocol (--socks4, --socks4a, --socks4a, --socks5-hostname)
+# 2022-02-27: added expected_strings option to default settings
+# 2022-02-28: added expected_strings option to url settings
+#             added state_item_not_found option
+# 2022-03-01: added options --limit-rate, --max-filesize, --max-time, --speed-limit, --speed-time, --connect-timeout
+#             added options --user-agent, --compressed, --no-alpn, --no-npn, --tcp-fastopen, --tcp-nodelay,
+#             added options --cert-status
+# 2022-03-02: added options --referer -header and api_key_header (header from password store)
+# 2022-03-05: added option --dump-header, state_header_str_not_found
+# 2022-03-06: added option --verbose, --stderr cert_time_left
+#             fixed upper/lower levels
+# 2022-03-10: optimized generation of upper/lower limit
+#             added transform for ms to s -> no need in th agent to change the value any more
+# 2022-03-11: added check to avoid duplicate service names in url list
+#             added --location-trust, --max-redirs
+#             reworked redirect (--location, --location-trust, --max-redirs)
+#             reworked cert verify (-insecure, --cert-status, --ssl-no-revok)
+#             reworked advanced_settings (--no-alpn, --no-npn, --tcp-fastopen, -tcp-nodelay)
+#             removed get_session_data. moved to curl default options
+# 2022-03-12: added --cacert
+#             added max_age
+# 2022-03-13: added post data
+#             made some entries fordable (Default options/Per URL settings, CA Cert)
+#             changed url and service_name to curl_service tuple
+#             changed headers to list of tuple
+# 2022-03-15: added regex pattern match for bakery
+# 2022-03-18: added regex pattern match for check
+# 2022-03-19: added options --dns-interface, -dns-ipv4-addr, --dns-ipv6-addr and --dns-servers
+#             reworked ip_address_resolution section
+#             added options --ftp-account, --ftp-alternative-to-user, --ftp-create-dirs, --ftp-method
+#             added options --ftp-pasv, --disable-epsv, --ftp-pret, --ftp-skip-pasv-ip
+#             added options --ftp-port, --disable-eprt
+#             added options --ftp-ssl-control, --ftp-ssl-ccc, --ftp-ssl-ccc-mode
+# 2022-03-21: moved  --connect-timeout, --limit-rate, --max-filesize, --max-time, --speed-limit, --speed-time
+#             to "limits" sub Directory
+# 2022-03-22: added curl_error_code_to_ignore and http_error_code_to_ignore options
+# 2022-03-24: added options --hostpubmd5, --hostpubsha256, --pubkey
+# 2022-03-24: added options --key --passs
+#             reworked user_auth section
+# 2022-03-25: added options --compressed-ssh, --list-only, --use-ascii
+#             added options --path-as-is, --ssl-allow-beast, --no-buffer, --no-keepalive, --no-sessionid
+# 2022-03-28: added options --mail-auth, --mail-from, --mail-rcpt, --mail-rcpt-allowfails, --crlf, --upload-file (SMTP)
+# 2022-04-10: added options to deploy cURL executable, no separate rules for curl and curl executable anymore
+#             windows/linux summarized under on option, no separate WATO rules per OS necessary anymore
+# 2022-04-26: added check option clickable_url
+#             clarified option 'Don\'t verify certificate/pub key', 'Don\'t stop at verify errors (certificate/pub key)'
+#
+
+import ipaddress
+from cmk.gui.i18n import _
+from cmk.gui.exceptions import MKUserError
+from cmk.gui.valuespec import (
+    Dictionary,
+    ListOf,
+    CascadingDropdown,
+    TextUnicode,
+    FixedValue,
+    Integer,
+    Tuple,
+    DropdownChoice,
+    MonitoringState,
+    ListOfStrings,
+    TextInput,
+    Checkbox,
+    Transform,
+    CAorCAChain,
+    Optional,
+    Foldable,
+    Age,
+    # Url,
+    UploadOrPasteTextFile,
+    Alternative,
+)
+from cmk.gui.plugins.wato.utils import (
+    rulespec_registry,
+    HostRulespec,
+    RulespecGroupCheckParametersOperatingSystem,
+    CheckParameterRulespecWithItem,
+)
+from cmk.gui.plugins.wato.utils import (
+    PasswordFromStore,
+)
+
+from cmk.gui.cee.plugins.wato.agent_bakery.rulespecs.utils import (
+    RulespecGroupMonitoringAgentsAgentPlugins,
+)
+
+bakery_plugin_version = '20220426.v0.0.8'
+
+# unsafe characters https://www.tutorialspoint.com/html/html_url_encoding.htm
+forbidden_chars = '"<>#%{}|\^~[]` \''
+
+_limits_transform = [
+    ('time_namelookup', 'Time name lookup', 'ms', ),
+    ('time_connect', 'Time connect', 'ms', ),
+    ('time_appconnect', 'Time app connect', 'ms', ),
+    ('time_pretransfer', 'Time pre transfer', 'ms', ),
+    ('time_redirect', 'Time redirect', 'ms', ),
+    ('time_starttransfer', 'Time start transfer', 'ms', ),
+    ('time_total', 'Time Total', 'ms', ),
+]
+
+_limits_no_transform = [
+    ('cert_time_left', 'Certificate life time', 'Day(s)', ),
+    ('num_connects', '# of connects', 'count', ),
+    ('num_redirects', '# of redirects', 'count', ),
+    ('num_headers', '# of headers', 'count', ),
+    ('size_download', 'Size download', 'bytes', ),
+    ('size_upload', 'Size upload', 'bytes', ),
+    ('size_header', 'Size header', 'bytes', ),
+    ('size_request', 'Size request', 'bytes', ),
+    ('speed_download', 'Speed download', 'bytes/s', ),
+    ('speed_upload', 'Speed upload', 'bytes/s', ),
+]
+
+_curl_check_elements = [
+    ('clickable_url',
+     FixedValue(
+         True,
+         title=_('Render clickable URLs for HTTP/HTTPS (see Inline help)'),
+         totext=_(''),
+         help=_('Needs "Escape HTML in service output" rule or in Global settings enabled to work.')
+     )),
+    ('state_item_not_found',
+     MonitoringState(
+         default_value=1,
+         title=_('State on item not found'),
+         help=_('Monitoring state if the item is not found in the agent data. Default is UNKNOWN.')
+     )),
+    ('state_http_result_not_200',
+     MonitoringState(
+         default_value=1,
+         title=_('State on HTTP result not OK'),
+         help=_('Monitoring state if the HTTP return code is not in 2xx or 3xx. Default is WARN.')
+     )),
+    ('http_error_code_to_ignore',
+     ListOfStrings(
+         title=_('HTTP error codes to ignore'),
+         allow_empty=False,
+         orientation='horizontal',
+         valuespec=Integer(size=3, minvalue=0, maxvalue=999),
+     )),
+    ('state_curl_result_not_0',
+     MonitoringState(
+         default_value=1,
+         title=_('State on cURL exit code not OK'),
+         help=_('Monitoring state if the exit code is not 0. Default is WARN.')
+     )),
+    ('curl_error_code_to_ignore',
+     ListOfStrings(
+         title=_('cURL error codes to ignore'),
+         allow_empty=False,
+         orientation='horizontal',
+         valuespec=Integer(size=3, minvalue=0, maxvalue=999),
+     )),
+    ('state_verify_sll_not_0',
+     MonitoringState(
+         default_value=1,
+         title=_('State on SSL verify not OK'),
+         help=_('Monitoring state if the SSL verify code is not 0. Default is WARN.')
+     )),
+    ('state_expected_str_not_found',
+     MonitoringState(
+         default_value=1,
+         title=_('State on expected string not found'),
+         help=_('Monitoring state if one expected string is not found in the cURL output. Default is WARN.')
+     )),
+    ('state_header_str_not_found',
+     MonitoringState(
+         default_value=1,
+         title=_('State on expected header not found'),
+         help=_('Monitoring state if one expected header string is not found in the cURL output. Default is WARN.')
+     )),
+    ('state_for_regex',
+     Tuple(
+         title=_('State for regex pattern match'),
+         elements=[
+             MonitoringState(
+                 default_value=0,
+                 title=_('State on regex pattern match'),
+             ),
+             MonitoringState(
+                 default_value=1,
+                 title=_('State on regex pattern don\'t match'),
+             ),
+             MonitoringState(
+                 default_value=0,
+                 title=_('State on regex pattern match info missing'),
+             ),
+         ],
+     )),
+    ('show_additional_info',
+     Tuple(
+         title=_('Show additional info'),
+         help=_('Shows RAW data from cURL in the service details.'),
+         elements=[
+             Checkbox('Request headers'),
+             Checkbox('Response headers'),
+             Checkbox('(TLS/SSL) session info'),
+             Checkbox('RAW data'),
+         ],
+     )),
+    ('max_age',
+     Tuple(
+         title=_('Maximum age'),
+         elements=[
+             Age(
+                 title=_('Warning at'),
+                 help=_('Warn, if the age of the page is older than this'),
+                 default_value=3600 * 24,
+             ),
+             Age(
+                 title=_('Critical at'),
+                 help=_('Critical, if the age of the page is older than this'),
+                 default_value=3600 * 24 * 4,
+             ),
+             MonitoringState(
+                 default_value=0,
+                 title=_('State if not available'),
+                 help=_(
+                     'Monitoring state if the "Last-Modified" header is not available in the agent data. Default is OK.'
+                 )
+             ),
+         ]
+     )),
+]
+
+
+def _get_tuple_upper(_unit: str) -> Tuple:
+    return Tuple(
+        title=_('Upper limits'),
+        orientation='horizontal',
+        elements=[
+            Integer(title=_('Warning at'), minvalue=0, unit=_(_unit), size=10),
+            Integer(title=_('Critical at'), minvalue=0, unit=_(_unit), size=10),
+        ],
+    )
+
+
+def _get_tuple_lower(_unit):
+    return Tuple(
+        title=_('Lower limits'),
+        orientation='horizontal',
+        elements=[
+            Integer(title=_('Warning below'), minvalue=0, unit=_(_unit), size=10),
+            Integer(title=_('Critical below'), minvalue=0, unit=_(_unit), size=10),
+        ],
+    )
+
+
+for key, label, unit in _limits_transform:
+    _curl_check_elements.append(
+        (key,
+         Dictionary(
+             title=_(label),
+             elements=[
+                 ('upper',
+                  Transform(
+                      _get_tuple_upper(unit),
+                      # run after read from rules.mk before show in wato
+                      forth=lambda elems: (int((elems[0] * 1000)), int((elems[1] * 1000))),
+                      # run before write to rule.mk after input in wato
+                      back=lambda elems: (float((elems[0] / 1000)), float((elems[1] / 1000))),
+                  )),
+                 ('lower',
+                  Transform(
+                      _get_tuple_lower(unit),
+                      forth=lambda elems: (int((elems[0] * 1000)), int((elems[1] * 1000))),
+                      back=lambda elems: (float((elems[0] / 1000)), float((elems[1] / 1000))),
+                  )),
+             ],
+         ))
+    )
+
+for key, label, unit in _limits_no_transform:
+    _curl_check_elements.append(
+        (key,
+         Dictionary(
+             title=_(label),
+             elements=[
+                 ('upper', _get_tuple_upper(unit)),
+                 ('lower', _get_tuple_lower(unit)),
+             ],
+         ))
+    )
+
+
+def _valuespec_curl():
+    return Dictionary(
+        elements=_curl_check_elements,
+    )
+
+
+rulespec_registry.register(
+    CheckParameterRulespecWithItem(
+        check_group_name='curl',
+        group=RulespecGroupCheckParametersOperatingSystem,
+        parameter_valuespec=_valuespec_curl,
+        title=lambda: _('cURL'),
+        match_type='dict',
+        item_spec=lambda: TextUnicode(title=_('cURL service name'), ),
+    ))
+
+# #########################################################################################################
+#
+# cURL bakery options
+#
+# #########################################################################################################
+
+_option_curl_service = ('curl_service',
+                        Tuple(
+                            elements=[
+                                TextUnicode(
+                                    title=_('Service name'),
+                                    help=_('Name for the discovered service, for example www.example.com'),
+                                    allow_empty=False,
+                                    placeholder='your.service.name',
+                                    forbidden_chars=forbidden_chars,
+                                ),
+                                TextUnicode(  # ToDo: change to URL?
+                                    title=_('URL to check'),
+                                    help=_('URL to check with cURL, for example https://www.example.com'),
+                                    allow_empty=False,
+                                    size=90,
+                                    placeholder='https://www.example.com',
+                                    # forbidden_chars=forbidden_chars,
+                                ),
+                            ],
+                            orientation='horizontal',
+                        ))
+
+
+def _transform_forth_verify_remote_host(params):
+    if type(params) == tuple:
+        if len(params) == 4:  # added 2022-03-23
+            params = (params[0], params[1], params[2], params[3], None, None, None)
+    return params
+
+
+_option_verify_remote_host = ('cert_verify',
+                              Transform(
+                                  Tuple(
+                                      title='Configure verification of remote host (certificate/pub key)',
+                                      elements=[
+                                          # Checkbox('Don\'t verify certificate/pub key'),
+                                          Checkbox('Don\'t stop at verify errors (certificate/pub key)'),
+                                          Checkbox('Use OCSP to check certificate status'),
+                                          Checkbox('Disable cert revocation checks (WinSSL)'),
+                                          Optional(Foldable(CAorCAChain()), label='Certificate to verify against', ),
+                                          Optional(TextUnicode(size=40, minlen=32, maxlen=32, regex='[0-9a-fA-F]', ),
+                                                   label='Expected MD5 hash of pub key'),
+                                          Optional(TextUnicode(size=60, allow_empty=False),
+                                                   label='Expected SHA256 hash of pub key'),
+                                          Optional(Foldable(UploadOrPasteTextFile(title='Public key'), ),
+                                                   label='Expected public key'),
+                                      ]
+                                  ),
+                                  forth=_transform_forth_verify_remote_host
+                              ))
+
+_option_redirects = ('redirects',
+                     Tuple(
+                         title='Configure redirects',
+                         elements=[
+                             Checkbox('Follow redirects'),
+                             Checkbox('Use authentication on redirects'),
+                             Optional(Integer(minvalue=-1, default_value=10), label='Max. redirects', sameline=True)
+                         ]
+                     ))
+
+_option_regex_response = ('regex_response',
+                          Tuple(
+                              title=_('Regular expression to expect in content'),
+                              elements=[
+                                  TextUnicode(
+                                      label=_('Regular expression'),
+                                      placeholder=_('If empty regex search will be disabled')
+                                  ),
+                                  Checkbox('Case insensitive'),
+                                  Checkbox('Multiline string matching'),
+                              ]
+                          ))
+
+_option_advanced_settings = ('advanced_settings',
+                             Tuple(
+                                 title='Advanced settings',
+                                 elements=[
+                                     Checkbox('Allow SSL beast security flaw to improve interoperability'),
+                                     Checkbox('Convert LF to CRLF in upload'),
+                                     Checkbox('Disable Application Layer Protocol Negotiation (ALPN)'),
+                                     Checkbox('Disable buffering of the output stream'),
+                                     Checkbox('Disable Next Protocol Negotiation (NPN)'),
+                                     Checkbox('Disable SSL session-ID reusing'),
+                                     Checkbox('Disable TCP keep alive on the connection'),
+                                     Checkbox('Do not squash .. sequences in URL path'),
+                                     Checkbox('Use TCP fast open option'),
+                                     Checkbox('Use TCP no delay option'),
+                                 ]
+                             ))
+
+_options_get_header_only = ('get_header_only',
+                            FixedValue(
+                                '--head',
+                                title=_('Get header only'),
+                                totext=_('Only headers will be downloaded'),
+                                help=_('cURL will will only download headers. Implements the "--head" option'),
+                            ))
+_url_get_header_only = ('get_header_only',
+                        DropdownChoice(
+                            title=_('Get Header only'),
+                            choices=[
+                                ('--head', _('Get header only')),
+                                ('', _('Get the hole document')),
+                            ],
+                        ))
+
+_option_auth_user = ('user_auth',
+                     _('Username/Password'),
+                     Tuple(
+                         title=_('Configure user authentication'),
+                         help=_(
+                             'The password entered here is stored in plain text within the monitored host. '
+                             'This is needed because the agent plugin needs to have access to the unencrypted '
+                             'password to authenticate with the server.'
+                         ),
+                         elements=[
+                             TextUnicode(
+                                 title=_('Username'),
+                                 allow_empty=False,
+                                 forbidden_chars=forbidden_chars,
+                                 placeholder='username',
+                             ),
+                             PasswordFromStore(
+                                 title=_('Password of the user'),
+                                 allow_empty=False,
+                             ),
+                             DropdownChoice(
+                                 title=_('Authentication method'),
+                                 choices=[
+                                     ('', _('Use cURL default')),
+                                     ('--basic', _('Basic authentication')),
+                                     ('--digest', _('Digest authentication')),
+                                     ('--ntlm', _('NTLM authentication')),
+                                     ('--ntlm-wb', _('NTLM authentication with winbind')),
+                                     ('--negotiate', _('HTTP Negotiate (SPNEGO) authentication')),
+                                     ('--anyauth', _('Any authentication')),
+                                 ]),
+                         ],
+                     ))
+_option_auth_priv_key = ('priv_key_auth',
+                         _('Private/public key'),
+                         Tuple(
+                             elements=[
+                                 TextUnicode(
+                                     title=_('Username'),
+                                     allow_empty=False,
+                                     forbidden_chars=forbidden_chars,
+                                     placeholder='username',
+                                 ),
+                                 PasswordFromStore(
+                                     title=_('Pass phrase'),
+                                     allow_empty=False,
+                                 ),
+                                 Foldable(UploadOrPasteTextFile(title='Private key', file_title='Private key (PEM)'),
+                                          title='Private key'),
+                             ]
+                         ))
+_option_auth = ('user_auth',
+                CascadingDropdown(
+                    title=_('Configure authentication'),
+                    sorted=False,
+                    choices=[
+                        _option_auth_user,
+                        _option_auth_priv_key,
+                        (None, _('No authentication')),
+                    ],
+                ))
+
+_option_proxy_server = ('proxy_server',
+                        Tuple(
+                            title=_('Proxy server'),
+                            show_titles=False,
+                            elements=[
+                                DropdownChoice(
+                                    title=_('Protocol'),
+                                    choices=[
+                                        ('--proxy', _('HTTP')),
+                                        ('--socks4', _('SOCKS4')),
+                                        ('--socks4a', _('SOCKS4a')),
+                                        ('--socks5', _('SOCKS5')),
+                                        ('--socks5-hostname', _('SOCKS5 hostname')),
+                                    ]),
+                                TextUnicode(
+                                    label=_('Server'),
+                                    help=_('Name or IP-address of the proxy server.'),
+                                    allow_empty=False,
+                                    size=40,
+                                    placeholder='your.proxy.server',
+                                    forbidden_chars=forbidden_chars,
+                                ),
+                                Integer(
+                                    label=_('Port'),
+                                    default_value=3128,
+                                    minvalue=1,
+                                    maxvalue=65565,
+                                ),
+                            ],
+                            orientation='horizontal',
+                        ))
+
+_option_proxy_auth = ('proxy_auth',
+                      Tuple(
+                          title=_('Proxy authentication'),
+                          help=_(
+                              'The password entered here is stored in plain text within the monitored host. '
+                              'This is needed because the agent plugin needs to have access to the unencrypted '
+                              'password to authenticate with the proxy.'
+                          ),
+                          elements=[
+                              TextUnicode(
+                                  title=_('Proxy username'),
+                                  allow_empty=False,
+                                  forbidden_chars=forbidden_chars,
+                                  placeholder='proxyusername',
+                              ),
+                              PasswordFromStore(
+                                  title=_('Password of the user'),
+                                  allow_empty=False,
+                              ),
+                              DropdownChoice(
+                                  title=_('Authentication method'),
+                                  choices=[
+                                      ('--proxy-basic', _('Basic authentication')),
+                                      ('--proxy-digest', _('Digest authentication')),
+                                      ('--proxy-ntlm', _('NTLM authentication')),
+                                      ('--proxy-negotiate', _('HTTP Negotiate (SPNEGO) authentication')),
+                                      ('--proxy-anyauth', _('Any authentication')),
+                                      ('--socks5-basic', _('SOCKS5 basic authentication')),
+                                  ]),
+                          ],
+                      ))
+
+_options_proxy = ('http_proxy',
+                  Alternative(
+                      title=_('Configure proxy server'),
+                      elements=[
+                          Dictionary(
+                              title='Use proxy',
+                              elements=[
+                                  _option_proxy_server,
+                                  _option_proxy_auth,
+                              ],
+                              required_keys=['proxy_server'],
+                          ),
+                          FixedValue('--noproxy', title=_('Don\'t use any proxy'), totext=_('')),
+                          FixedValue(None, title=_('Don\'t configure an proxy (use system settings)'), totext=_('')),
+                      ],
+                  ))
+
+_option_tls_ssl_version = ('tls_ssl_version',
+                           DropdownChoice(
+                               title=_('Use TLS/SSL version'),
+                               choices=[
+                                   ('', _('cURL default')),
+                                   ('--ssl', _('Try TLS/SSL')),
+                                   ('--ssl-reqd', _('Require TLS/SSL')),
+                                   ('--tlsv1.3', _('Use TLS 1.3')),
+                                   ('--tlsv1.2', _('Use TLS 1.2')),
+                                   ('--tlsv1.1', _('Use TLS 1.1')),
+                                   ('--tlsv1.0', _('Use TLS 1.0')),
+                                   ('--tlsv1', _('Use TLS1.0 or greater')),
+                                   ('--sslv3', _('Use SSLv3')),
+                                   ('--sslv2', _('Use SSLv2')),
+                               ]),)
+
+_option_http_version = ('http_version',
+                        DropdownChoice(
+                            title=_('Use HTTP version'),
+                            choices=[
+                                ('', _('cURL preferred version')),
+                                ('--http2', _('Use HTTP/2')),
+                                ('--http1.1', _('Use HTTP 1.1')),
+                                ('--http1.0', _('Use HTTP 1.0')),
+                            ]),)
+
+
+def _transform_forth_address_resolution(params):
+    if not type(params) == dict:
+        if params == '':
+            params = None
+        params = {'dns_resolve_names': params}
+    return params
+
+
+def _validate_ipaddress(pattern, varprefix):
+    if pattern:
+        try:
+            ipaddress.ip_address(pattern)
+        except ValueError:
+            raise MKUserError(varprefix, _(f'{pattern} is not a valid IP address'))
+
+
+_option_address_resolution = ('ip_address_resolution',
+                              Transform(
+                                  Foldable(
+                                      Dictionary(
+                                          title=_('DNS options'),
+                                          elements=[
+                                              ('dns_resolve_names', DropdownChoice(
+                                                  title=_('Resolve names'),
+                                                  choices=[
+                                                      (None, _('IPv4/IPv6')),
+                                                      ('--ipv4', _('IPv4 only')),
+                                                      ('--ipv6', _('IPv6 only')),
+                                                  ])),
+                                              ('dns_source_interface', TextUnicode(
+                                                  title=_('Source interface'),
+                                                  regex='[0-9a-zA-Z]',
+                                                  size=15,
+                                              )),
+                                              ('dns_source_ipv4', TextUnicode(
+                                                  title=_('IPv4 source address'),
+                                                  validate=_validate_ipaddress,
+                                                  size=15,
+                                              )),
+                                              ('dns_source_ipv6', TextUnicode(
+                                                  title=_('IPv6 source address'),
+                                                  validate=_validate_ipaddress,
+                                                  size=42
+                                              )),
+                                              ('dns_servers', ListOfStrings(
+                                                  title=_('DNS servers'),
+                                                  valuespec=TextInput(validate=_validate_ipaddress, size=42),
+                                                  orientation='horizontal',
+
+                                              )),
+                                          ],
+                                      ),
+                                      forth=_transform_forth_address_resolution
+                                  ),
+                                  title=_('Set DNS options'),
+                              ))
+
+_option_ftp_settings = ('ftp_settings',
+                        Foldable(
+                            Dictionary(
+                                title=_('FTP/SCP/SFTP options'),
+                                elements=[
+                                    ('ftp_account', TextUnicode(title=_('Account data string')),),
+                                    ('ftp_alternate_to_user', TextUnicode(title=_('String to replace USER command'))),
+                                    ('ftp_create_dirs', FixedValue(
+                                        True,
+                                        title=_('Create remote dir(s)'),
+                                        totext=_('enabled')
+                                    )),
+                                    ('ftp_change_cwd_method', DropdownChoice(
+                                        title=_('Change working directory method'),
+                                        choices=[
+                                            ('multicwd', 'one CD for each directory'),
+                                            ('nocdw', 'No CD. Use full path in SIZE, RETR, STOR etc.'),
+                                            ('singlecwd', 'use one CD with full path')
+                                        ]
+                                    )),
+                                    ('ftp_mode',
+                                     CascadingDropdown(
+                                         title=_('Passive/Actrive mode'),
+                                         sorted=False,
+                                         choices=[
+                                             ('ftp_pass',
+                                              _('FTP passive mode'),
+                                              Tuple(
+                                                  elements=[
+                                                      Checkbox(label=_('Don\'t send EPSV command')),
+                                                      Checkbox(label=_('Send PRET before PASV')),
+                                                      Checkbox(
+                                                          label=_('Use remote IP form control channel for data chanel'))
+                                                  ]
+                                              )),
+                                             ('ftp_active',
+                                              _('FTP active mode'),
+                                              Tuple(
+                                                  elements=[
+                                                      Checkbox(label=_('Don\'t send EPRT command')),
+                                                      TextUnicode(
+                                                          label=_('Address to use'),
+                                                          help=_(
+                                                              'Can be the interface name ie "eth0", a exact ip address, a '
+                                                              'hostname/FQDN or "-" to use the same address used for the '
+                                                              'control connection'
+                                                          ),
+                                                          default_value='-',
+                                                          regex='[0-9a-zA-Z\\.:\\-_]',
+                                                      ),
+                                                  ]
+                                              ))
+                                         ]
+                                     )),
+                                    ('ftp_ssl_control',
+                                     Tuple(
+                                         title=_('Require SSL/TLS for FTP login'),
+                                         elements=[
+                                             Checkbox(label=_('Send CCC after authenticating')),
+                                             DropdownChoice(
+                                                 label=_('Set CCC mode'),
+                                                 choices=[
+                                                     ('active', 'Active'),
+                                                     ('passive', 'Passive'),
+                                                 ]
+                                             )
+                                         ]
+                                     )),
+                                    ('compressed_ssh', FixedValue(
+                                        True,
+                                        title=_('Enable ssh compression'),
+                                        totext=_('enabled'),
+                                    )),
+                                    ('list_only', FixedValue(
+                                        True,
+                                        title=_('Enable list only'),
+                                        totext=_('enabled'),
+                                    )),
+                                    ('use_ascii', FixedValue(
+                                        True,
+                                        title=_('Enable ASCII transfer'),
+                                        totext=_('enabled'),
+                                    )),
+                                ],
+                            ),
+                            title=_('Set FTP/SCP/SFTP options'),
+                        ))
+
+_option_expected_strings = ('expected_strings',
+                            ListOfStrings(
+                                title=_('Strings to expect in response'),
+                                # orientation='horizontal',
+                                allow_empty=False,
+                                valuespec=TextInput(allow_empty=False, regex='[a-zA-Z0-9\.]'),
+                            ))
+_url_expected_strings = ('expected_strings',
+                         Alternative(
+                             title=_('Override strings to expect in response'),
+                             elements=[
+                                 _option_expected_strings[1],
+                                 FixedValue(None, title=_('Don\'t expect any strings in the response'), totext=_('')),
+                             ],
+                         ))
+
+_option_header_strings = ('header_strings',
+                          ListOfStrings(
+                              title=_('Strings to expect in header'),
+                              # orientation='horizontal',
+                              allow_empty=False,
+                              valuespec=TextInput(allow_empty=False, regex='[a-zA-Z0-9\\.]'),
+                          ))
+_url_header_strings = ('header_strings',
+                       Alternative(
+                           title=_('Override strings to expect in header'),
+                           elements=[
+                               _option_expected_strings[1],
+                               FixedValue(None, title=_('Don\'t expect any strings in the header'), totext=_('')),
+                           ],
+                       ))
+
+_option_request_headers = ('request_headers',
+                           ListOf(
+                               Tuple(
+                                   title=_('Set headers'),
+                                   orientation='horizontal',
+                                   elements=[
+                                       TextUnicode(
+                                           label=_('Header'),
+                                           allow_empty=False,
+                                           placeholder='X-your-header',
+                                           regex='[a-zA-Z0-9_\\-]',
+                                           # size=30,
+                                       ),
+                                       TextUnicode(
+                                           label=_('Value'),
+                                           # allow_empty=False,
+                                           placeholder='value of header',
+                                           # regex='[a-zA-Z0-9_ :;.,=<>#\\-@\\+\\*\'/\\?!\\(\\)\\{\\}\\[\\]\\$\\&~\\^%|"`\\]',
+                                           size=50,
+                                           empty_text=';'
+                                       ),
+                                   ]
+                               ),
+                               allow_empty=False,
+                               title=_('Set headers'),
+                               add_label=_('Add header'),
+                               movable=True,
+                           ))
+_url_request_headers = ('request_headers',
+                        Alternative(
+                            title=_('Override default headers'),
+                            elements=[
+                                _option_request_headers[1],
+                                FixedValue(None, title=_('Don\'t configure request headers'), totext=_(''))
+                            ]
+                        ))
+
+_option_mail_settings = ('mail_settings',
+                         Foldable(
+                             Dictionary(
+                                 title=_('SMTP settings'),
+                                 elements=[
+                                     ('mail_from', TextUnicode(
+                                         title=_('Mail from address'),
+                                         allow_empty=False,
+                                     )),
+                                     ('mail_rcpt', ListOfStrings(
+                                         title=_('Mail to address'),
+                                         allow_empty=False,
+                                         max_entries=5,
+                                     )),
+                                     ('mail_auth', TextUnicode(
+                                         title=_('Mail originator address'),
+                                     )),
+                                     # ('oauth2_header', TextUnicode(
+                                     #      title=_('Oauth2 token'),
+                                     #  )),
+                                     ('request', TextUnicode(
+                                         title=_('REQUEST command'),
+                                         help=_('Send this command instead of LIST (POP3/IMAP) or HELP/VRFY (SMTP).')
+                                     )),
+                                     _option_request_headers,
+                                     ('message', UploadOrPasteTextFile(
+                                         title=_('Message to send'),
+                                     )),
+                                     ('mail_rpct_allowfail', FixedValue(
+                                         True,
+                                         title=_('Allow some mail to addresses to fail'),
+                                         totext=_('enabled')
+                                     ))
+                                 ]
+                             ),
+                             title=_('Set SMTP options'),
+                         ))
+
+_option_api_key_header = ('api_key_header',
+                          Tuple(
+                              title=_('Set API key header'),
+                              help=_(
+                                  'The password entered here is stored in plain text within the monitored host. '
+                                  'This is needed because the agent plugin needs to have access to the unencrypted '
+                                  'password to authenticate with the server.'
+                              ),
+                              elements=[
+                                  TextUnicode(
+                                      title=_('API Key header'),
+                                      allow_empty=False,
+                                      forbidden_chars='|"',
+                                      placeholder='X-API-Key: ',
+                                  ),
+                                  PasswordFromStore(
+                                      title=_('API Key'),
+                                      allow_empty=False,
+                                  ),
+                              ],
+                          ))
+_url_api_key_header = ('api_key_header',
+                       Alternative(
+                           title=_('Set API key header'),
+                           elements=[
+                               _option_api_key_header[1],
+                               FixedValue(None, title=_('Don\'t configure an API key header'), totext=_('')),
+                           ],
+                       ))
+
+_option_limit_rate = ('limit_rate',
+                      Tuple(
+                          title=_('Maximum UP-/Download rate'),
+                          # show_titles=False,
+                          elements=[
+                              Integer(
+                                  label=_('Speed'),
+                                  # default_value=3128,
+                                  minvalue=1,
+                                  # maxvalue=65565,
+                              ),
+                              DropdownChoice(
+                                  default_value='M',
+                                  choices=[
+                                      ('B', _('Byte/s')),
+                                      ('K', _('KByte/s')),
+                                      ('M', _('MByte/s')),
+                                      ('G', _('GByte/s')),
+                                  ]),
+                          ],
+                          orientation='horizontal',
+                      ))
+_url_limit_rate = ('limit_rate',
+                   Alternative(
+                       title=_('Maximum UP-/Download rate'),
+                       elements=[
+                           _option_limit_rate[1],
+                           FixedValue(None, title=_('Don\'t configure a rate limit'), totext=_('')),
+                       ],
+                   ))
+
+_option_max_file_size = ('max_file_size',
+                         Tuple(
+                             title=_('Maximum file size'),
+                             # show_titles=False,
+                             elements=[
+                                 Integer(
+                                     label=_('Size'),
+                                     # default_value=3128,
+                                     minvalue=1,
+                                     # maxvalue=65565,
+                                 ),
+                                 DropdownChoice(
+                                     # title=_('Unit'),
+                                     choices=[
+                                         ('B', _('Byte')),
+                                         ('K', _('KByte')),
+                                         ('M', _('MByte')),
+                                         ('G', _('GByte')),
+                                     ]),
+                             ],
+                             orientation='horizontal',
+                         ))
+_url_max_file_size = ('max_file_size',
+                      Alternative(
+                          title=_('Maximum file size'),
+                          elements=[
+                              _option_max_file_size[1],
+                              FixedValue(None, title=_('Don\'t configure a file size limit'), totext=_('')),
+                          ],
+                      ))
+
+_option_max_time = ('max_time',
+                    Integer(
+                        title=_('Maximum transfer time'),
+                        default_value=10,
+                        minvalue=1,
+                        unit='s',
+                    ))
+_url_max_time = ('max_time',
+                 Alternative(
+                     title=_('Maximum transfer time'),
+                     elements=[
+                         _option_max_time[1],
+                         FixedValue(None, title=_('Don\'t configure a transfer time limit'), totext=_('')),
+                     ],
+                 ))
+
+_option_speed_limit = ('speed_limit',
+                       Tuple(
+                           title=_('Minimum speed'),
+                           # show_titles=False,
+                           elements=[
+                               Integer(
+                                   label=_('Speed'),
+                                   minvalue=1,
+                               ),
+                               DropdownChoice(
+                                   default_value=1024,
+                                   choices=[
+                                       (1, _('Byte/s')),
+                                       (1024, _('KByte/s')),
+                                       (1048576, _('MByte/s')),
+                                       (1073741824, _('GByte/s')),
+                                   ]),
+                           ],
+                           orientation='horizontal', ))
+_url_speed_limit = ('speed_limit',
+                    Alternative(
+                        title=_('Minimum speed'),
+                        elements=[
+                            _option_speed_limit[1],
+                            FixedValue(None, title=_('Don\'t configure a lower speed limit'), totext=_('')),
+                        ],
+                    ))
+
+_option_speed_time = ('speed_time',
+                      Integer(
+                          title=_('Minimum speed time'),
+                          default_value=30,
+                          minvalue=1,
+                          unit='s', ))
+_url_speed_time = ('speed_time',
+                   Alternative(
+                       title=_('Minimum speed time'),
+                       elements=[
+                           _option_speed_time[1],
+                           FixedValue(None, title=_('Don\'t configure a minimum speed time limit'), totext=_('')),
+                       ],
+                   ))
+
+_option_connect_timeout = ('connect_timeout',
+                           Integer(
+                               title=_('Maximum time to connect'),
+                               default_value=1,
+                               minvalue=1,
+                               unit='s', ))
+_url_connect_timeout = ('connect_timeout',
+                        Alternative(
+                            title=_('Maximum time to connect'),
+                            elements=[
+                                _option_connect_timeout[1],
+                                FixedValue(None, title=_('Don\'t configure a maximum time to connect'), totext=_('')),
+                            ],
+                        ))
+
+_option_limits = ('limits',
+                  Foldable(
+                      Dictionary(
+                          title=_('Limits'),
+                          elements=[
+                              _option_limit_rate,
+                              _option_max_file_size,
+                              _option_connect_timeout,
+                              _option_max_time,
+                              _option_speed_limit,
+                              _option_speed_time,
+                          ]
+                      ),
+                      title=_('Set connection limits')
+                  ))
+_url_limits = ('limits',
+               Foldable(
+                   Dictionary(
+                       title=_('Limits'),
+                       elements=[
+                           _url_limit_rate,
+                           _url_max_file_size,
+                           _url_connect_timeout,
+                           _url_max_time,
+                           _url_speed_limit,
+                           _url_speed_time,
+                       ]
+                   ),
+                   title=_('Override connection limits')
+               ))
+
+_option_user_agent = ('user_agent',
+                      TextUnicode(
+                          title=_('Set user agent'),
+                          allow_empty=False,
+                          placeholder='your user agent',
+                          # forbidden_chars=forbidden_chars,
+                          forbidden_chars='"|'
+                      ))
+_url_user_agent = ('user_agent',
+                   CascadingDropdown(
+                       title=_('Set user agent'),
+                       sorted=False,
+                       choices=[
+                           ('user_agent', _('Override default user agent'),
+                            _option_user_agent[1],),
+                           ('', _('Don\'t configure a user agent')),
+                       ],
+                   ))
+
+_option_referer = ('referer',
+                   TextUnicode(
+                       title=_('Set referer'),
+                       allow_empty=False,
+                       placeholder='http://your.referer.url/',
+                       # forbidden_chars=forbidden_chars,
+                       forbidden_chars='|" ',
+                   ))
+_url_referer = ('referer',
+                Alternative(
+                    title=_('Override default referer'),
+                    elements=[
+                        _option_referer[1],
+                        FixedValue(None, title=_('Don\'t configure a referer'), totext=_(''))
+                    ]
+                ))
+
+_options_compressed = ('compressed',
+                       FixedValue(
+                           '--compressed',
+                           title=_('Request compressed response'),
+                           totext=_('Request compressed response enabled'),
+                       ))
+_url_compressed = ('compressed',
+                   DropdownChoice(
+                       title=_('Request compressed response'),
+                       choices=[
+                           ('--compressed', _('Request compressed response')),
+                           ('', _('Don\'t Request compressed response')),
+                       ],
+                   ))
+
+_option_post = ('post_binary',
+                Tuple(
+                    title=_('Send HTTP POST data'),
+                    elements=[
+                        TextUnicode(
+                            label=_('Content-Type'),
+                            allow_empty=False,
+                            forbidden_chars=forbidden_chars,
+                            default_value='text/html'
+                        ),
+                        UploadOrPasteTextFile(
+                            # title=_('HTTP POST data'),
+                            allow_empty=False,
+                            default_value=_(
+                                'This posts data exactly as specified with no extra processing whatsoever.\n\n'
+                                'To disable HTTP POST data in per URL settings leave this empty.'
+                            ),
+                        ),
+                    ]
+                ))
+
+_option_url_settings = ('url_settings',
+                        Foldable(
+                            Dictionary(
+                                title=_('Per URL settings'),
+                                elements=[
+                                    _option_verify_remote_host,
+                                    _options_proxy,
+                                    _option_redirects,
+                                    _option_auth,
+                                    _url_get_header_only,
+                                    _option_regex_response,
+                                    _url_compressed,
+                                    _option_post,
+                                    _url_api_key_header,
+                                    _url_referer,
+                                    _url_request_headers,
+                                    _url_user_agent,
+                                    _url_header_strings,
+                                    _url_expected_strings,
+                                    _url_limits,
+                                    _option_address_resolution,
+                                    _option_ftp_settings,
+                                    _option_mail_settings,
+                                    _option_tls_ssl_version,
+                                    _option_http_version,
+                                    _option_advanced_settings,
+                                ],
+                            ),
+                            title=_('Override default settings'),
+                        ))
+
+
+def _validate_service_names(pattern, varprefix):
+    service_names = []
+
+    for url in pattern:
+        service_names.append(url['curl_service'][0])
+    duplicates = [service_name for service_name in service_names if service_names.count(service_name) > 1]
+    duplicates = list(set(duplicates))
+    if duplicates:
+        raise MKUserError(
+            varprefix,
+            _(f'There are duplicate service names. Please check the following service names: {", ".join(duplicates)}')
+        )
+
+
+def _option_url_transform_curl_service(params):
+    # transform form separate dict entries to tuple
+    # added in version 20220314.v0.1.0
+    # {'url': 'https://excample.com', 'service_name': 'example'}
+    # {'curl_service': ('example', 'https://eaxample.com')}
+    if type(params) == dict:
+        try:
+            url = params['url']
+            service_name = params['service_name']
+            params.pop('url'),
+            params.pop('service_name')
+            params.update({'curl_service': (service_name, url)})
+        except KeyError:
+            pass
+    return params
+
+
+_option_url = ('url_list',
+               Foldable(
+                   ListOf(
+                       Transform(
+                           Dictionary(
+                               elements=[
+                                   _option_curl_service,
+                                   _option_url_settings,
+                               ],
+                               required_keys=['curl_service', ],
+                           ),
+                           forth=_option_url_transform_curl_service
+                       ),
+                       add_label=_('Add URL'),
+                       movable=True,
+                       title=_('URLs to check'),
+                       allow_empty=False,
+                       validate=_validate_service_names,
+                   )))
+
+_option_default_settings = ('default_settings',
+                            Foldable(
+                                Dictionary(
+                                    title=_('Plugin settings'),
+                                    elements=[
+                                        _option_verify_remote_host,
+                                        _options_proxy,
+                                        _option_redirects,
+                                        _option_auth,
+                                        _options_get_header_only,
+                                        _option_regex_response,
+                                        _options_compressed,
+                                        _option_post,
+                                        _option_api_key_header,
+                                        _option_referer,
+                                        _option_request_headers,
+                                        _option_user_agent,
+                                        _option_header_strings,
+                                        _option_expected_strings,
+                                        _option_limits,
+                                        _option_address_resolution,
+                                        _option_ftp_settings,
+                                        _option_mail_settings,
+                                        _option_http_version,
+                                        _option_tls_ssl_version,
+                                        _option_advanced_settings,
+                                    ],
+                                ),
+                                title='Default setting',
+                            ))
+
+_option_plugin_interval = ('interval',
+                           Integer(
+                               title=_('Plugin run interval'),
+                               minvalue=1,
+                               unit=_('min'),
+                               # default_value=1,
+                               help=_(
+                                   'This is the interval at witch the plugin runs. If not set the plugin will '
+                                   'run with every cycle of the agent (By default every 1 minute).'
+                               ),
+                           ),)
+
+_option_plugin_timeout = ('timeout',
+                          Integer(
+                              title=_('Plugin timeout'),
+                              minvalue=1,
+                              unit=_('min'),
+                              # default_value=300,
+                              help=_(
+                                  'This is the maximum run time for the plugin. If not set the timeout for '
+                                  'the plugin is 1 minute by default.'
+                              ),
+                          ),)
+
+_option_curl_executable = ('curl_executable',
+                           DropdownChoice(
+                               title=_('cURL executable to use'),
+                               help=_(
+                                   'By default this plugin will use the system provided cURL executable. You can '
+                                   'decide to deploy a separate cURL executable. If you do so you need to install the '
+                                   'optional CMK package curl_executable<version>.mkp.'
+                               ),
+                               choices=[
+                                   (None, _('Use system provided cURL executable')),
+                                   ('64bit', _('Deploy 64bit cURL version')),
+                                   ('32bit', _('Deploy 32bit cURL version')),
+                               ]
+                           ))
+
+
+def _transform_forth_agent_config_curl(params):
+    # transform added 20220410 on removing os specific rules
+    if type(params) == tuple:
+        if params[0] in ['linux', 'windows', 'deploy']:
+            params = params[1]
+        else:
+            params = None
+    return params
+
+
+def _valuespec_agent_config_curl():
+    return Transform(
+        Alternative(
+            title=_('cURL'),
+            elements=[
+                Dictionary(
+                    title=_('Deploy cURL agent plugin'),
+                    elements=[
+                        _option_url,
+                        _option_plugin_interval,
+                        _option_plugin_timeout,
+                        _option_curl_executable,
+                        _option_default_settings,
+                    ],
+                    required_keys=['url_list'],
+                ),
+                FixedValue(
+                    None,
+                    title=_('Do not deploy the cURL agent plugin'),
+                    totext=_('The cURL agent plugin will not be deployed')
+                ),
+            ],
+        ),
+        forth=_transform_forth_agent_config_curl,
+    )
+
+
+rulespec_registry.register(
+    HostRulespec(
+        group=RulespecGroupMonitoringAgentsAgentPlugins,
+        name='agent_config:curl',
+        valuespec=_valuespec_agent_config_curl,
+    )
+)
diff --git a/packages/curl b/packages/curl
index 84453ca91784da2657f9a96f69432ed52986a965..24e5b6d3f89ec1f6169ba16f3129e7401b7bcb6a 100644
--- a/packages/curl
+++ b/packages/curl
@@ -22,11 +22,10 @@
  'download_url': 'https://thl-cmk.hopto.org/gitlab/checkmk/vendor-independent/curl',
  'files': {'agent_based': ['curl.py'],
            'agents': ['bakery/curl.py', 'plugins/curl.sh', 'plugins/curl.ps1'],
-           'web': ['plugins/wato/curl.py', 'plugins/metrics/curl.py']},
+           'gui': ['metrics/curl.py', 'wato/curl.py']},
  'name': 'curl',
- 'num_files': 6,
  'title': 'cURL agent plugin',
- 'version': '20220515.v0.1.8c',
- 'version.min_required': '2.0.0',
- 'version.packaged': '2021.09.20',
+ 'version': '0.1.9-20230607',
+ 'version.min_required': '2.1.0b1',
+ 'version.packaged': '2.1.0p21',
  'version.usable_until': None}
\ No newline at end of file