File automx-1.1.3pre.patch of Package automx1
diff --git a/CHANGES b/CHANGES
index 3575762..b520894 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,8 @@
+* Version 1.1.2
+---------------------------------
+- Added support for cal/carddav
+- Added support for eMClient for OX
+
* Version 1.1.1
---------------------------------
- Added service_domain_required option for Outlook
diff --git a/INSTALL b/INSTALL
index 2c61b4f..c4ed76f 100644
--- a/INSTALL
+++ b/INSTALL
@@ -115,7 +115,8 @@ If you install automx on an existing host, which has it's own domain-name, then
it is also possible to use above entries as nicknames:
somehost.example.com. IN A 192.168.2.1
- autoconfig IN CNAME somehost autodiscover IN CNAME somehost
+autoconfig IN CNAME somehost.example.com.
+autodiscover IN CNAME somehost.example.com.
Web Server Configuration
diff --git a/README.md b/README.md
index 2e9c454..d8821fd 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,7 @@ various autoconfiguration techniques in one webservice.
## Mailclients
automx can provision Outlook, Thunderbird, iOS devices and other clients that
-support either Microsofts autodiscover mechanism or Mozillas autoconfig.
+support either Microsoft's autodiscover mechanism or Mozilla's autoconfig.
## Backends
automx can either statically or dynamically generate email account information
diff --git a/src/automx-test b/src/automx-test
index d62f8d0..079731c 100755
--- a/src/automx-test
+++ b/src/automx-test
@@ -31,7 +31,7 @@ function clean_exit() {
# We need a mail address
if [[ $1 ]]; then
PROFILE="$1"
-else
+else
echo "Provide the mail address for which configuration settings should be retrieved."
read -ep "Mail address: " PROFILE
fi
@@ -43,17 +43,32 @@ MBREQUEST="$(mktemp /tmp/${PROGRAM_NAME}.XXXXXX)"
MBCRESPONSE="$(mktemp /tmp/${PROGRAM_NAME}.XXXXXX)"
# Test Mozilla schema
+MOZFOUND=0
AUTOCONF="autoconfig.$DOMAIN"
-if [[ $(dig +short $AUTOCONF) ]]; then
+WELL_KNOWN="$DOMAIN/.well-known/autoconfig"
+if [[ ! $(dig +short $AUTOCONF) ]]; then
+ echo
+ echo "Autodiscovery domain for Mozilla Thunderbird not found ($AUTOCONF)"
+ echo
+else
CON="http://$AUTOCONF/mail/config-v1.1.xml?emailaddress=$PROFILE"
echo
echo "Testing Autoconfig ..."
echo "Connecting to $CON ..."
echo
- wget -S -O - -q --no-check-certificate $CON
-else
+ wget -S -O - -q --no-check-certificate $CON && MOZFOUND=1
+fi
+if [ $MOZFOUND -ne 1 ]; then
+ # some error happened; try fallback URL
+ echo "Trying fallback URL ..."
+ CON="http://$WELL_KNOWN/mail/config-v1.1.xml?emailaddress=$PROFILE"
+ echo "Connecting to $CON ..."
echo
- echo "Autodiscovery domain for Mozilla Thunderbird not found ($AUTOCONF)"
+ wget -S -O - -q --no-check-certificate $CON && MOZFOUND=1
+fi
+if [ $MOZFOUND -eq 0 ]; then
+ # no supported autoconfig information
+ echo "No autoconfig endpoint found."
echo
fi
@@ -78,14 +93,14 @@ if [[ $AUTODISC ]]; then
</Request>
</Autodiscover>
REQ
-
+
echo
echo "Testing Autodiscover (Microsoft Outlook(tm)) ..."
echo "Connecting to $CON ..."
echo
wget -S -O - -q --post-file=$OLREQUEST --no-check-certificate $CON
rm $OLREQUEST
-
+
# Test Microsoft Mobile schema
cat <<-REQ >$MBREQUEST
<?xml version="1.0" encoding="utf-8"?>
@@ -96,7 +111,7 @@ if [[ $AUTODISC ]]; then
</Request>
</Autodiscover>
REQ
-
+
echo
echo "Testing Autodiscover (mobilesync) ..."
echo "Connecting to $CON ..."
diff --git a/src/automx/config.py b/src/automx/config.py
index 9c78b94..0c4b83b 100644
--- a/src/automx/config.py
+++ b/src/automx/config.py
@@ -15,13 +15,24 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
import os
import sys
import shlex
import re
import logging
+# noinspection PyCompatibility
import ipaddress
-import configparser
+
+try:
+ import configparser
+except ImportError:
+ # noinspection PyPep8Naming
+ import ConfigParser as configparser
try:
# noinspection PyUnresolvedReferences
@@ -31,9 +42,12 @@ try:
except ImportError:
use_memcache = False
+# noinspection PyCompatibility
from configparser import NoOptionError, NoSectionError
from dateutil import parser
from collections import OrderedDict
+# noinspection PyCompatibility
+from builtins import dict, int, str
__version__ = '1.1.1'
@@ -58,47 +72,47 @@ class Config(configparser.RawConfigParser):
independend from the view. It may query different backends to gather all
required information needed to generate XML output later on in the view
class.
-
+
It uses a OrderdDict to guarentee the correct service order that is needed
in the XML output. This said means that it is a difference, if a service
like IMAP is configured before POP3 or upside down, because a MUA follows
this order.
-
- The class currently support smtp, pop and imap services.
-
+
+ The class currently support smtp, pop, imap, carddav, caldav and ox services.
+
The class currently supports the following backends:
-
+
-> global - This backend tells automx to use the global section
-
+
-> static - all kind of service information that can be sent directly to
the MUA
-
+
-> filter - This backend can execute commands and collects results from
stdout. The result may be "", which means we skip further
searching. It may return data, which should point to a section
that we try to follow.
-
+
-> ldap - Read all kind of information from LDAP servers. The result
attributes are stored in an internal dictionary and if options
later on in this backend section (is read as static backend)
do contain variables in the form ${attributename}, these are
expanded to the collected data.
-
+
-> sql - Read all kind of information from SQL servers. The result
attributes are stored in an internal dictionary. See ldpa
-
+
-> script - Execute a script and split a result into attributes, which are
stored in an internal dictionary, See ldap
-
+
-> file - Provide static files. If present, all collected data are
discarded and only the static file is sent to the remote
client. This may change in future releases.
-
+
Note: There may exist a DEFAULT section that is appended to _all_ sections
in the configuration file. That said you can do really complex
configurations that on the other hand make life easier. This section also
may contain variables, which, if found in the vars-dictionary, are used.
-
+
"""
def __init__(self, environ):
@@ -245,6 +259,12 @@ class Config(configparser.RawConfigParser):
service = self.__service(section, "imap")
elif opt == "pop":
service = self.__service(section, "pop")
+ elif opt == "carddav":
+ service = self.__service(section, "carddav")
+ elif opt == "caldav":
+ service = self.__service(section, "caldav")
+ elif opt == "ox":
+ service = self.__service(section, "ox")
elif opt == "sign_mobileconfig":
try:
settings[opt] = self.getboolean(section, opt)
@@ -260,7 +280,7 @@ class Config(configparser.RawConfigParser):
else:
pass
- if opt in ("smtp", "imap", "pop"):
+ if opt in ("smtp", "imap", "pop", "caldav", "carddav", "ox"):
if backend == "static_append":
if opt in settings:
if self.debug:
@@ -636,7 +656,7 @@ class Config(configparser.RawConfigParser):
got_data = True
- # we replace our search_domain
+ # we replace our search_domain
self.__search_domain = special_opt
self.__emailaddress = new_emailaddress
@@ -973,7 +993,10 @@ class Memcache(object):
else:
networks = ("127.0.0.1", "::1/128")
- a = ipaddress.ip_address(self.__client)
+ if sys.version_info < (3,):
+ a = ipaddress.ip_address(self.__client.decode("utf-8"))
+ else:
+ a = ipaddress.ip_address(self.__client)
for network in iter(networks):
n = ipaddress.ip_network(network)
if a in n:
diff --git a/src/automx/view.py b/src/automx/view.py
index 823fc18..d83aa10 100644
--- a/src/automx/view.py
+++ b/src/automx/view.py
@@ -15,6 +15,11 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
import sys
import uuid
import logging
@@ -22,7 +27,13 @@ import logging
from lxml import etree
from lxml.etree import XMLSyntaxError
from xml.parsers.expat import ExpatError
-from plistlib import load, dumps, FMT_XML
+
+try:
+ # noinspection PyUnresolvedReferences
+ from plistlib import load, dumps, FMT_XML
+except ImportError:
+ # noinspection PyPep8Naming
+ from plistlib import readPlist, writePlistToString
__version__ = '1.1.1'
@@ -38,7 +49,7 @@ class View(object):
is used in Mozilla Thunderbird and several other open-source MUAs. It also
supports .mobileconfig profile support as found on iOS devices. These
profiles can also be used on Mac OS X Mail.app
-
+
"""
def __init__(self, model, schema, subschema):
@@ -64,7 +75,10 @@ class View(object):
elif self.__schema == "mobileconfig":
path = self.__model.domain[self.__schema]
try:
- plist_tmp = load(path)
+ if sys.version_info < (3,):
+ plist_tmp = readPlist(path)
+ else:
+ plist_tmp = load(path)
plist = plist_tmp.copy()
self.__plist = plist
except ExpatError:
@@ -119,7 +133,7 @@ class View(object):
raise Exception("Missing attribute <action>")
for key, value in self.__model.domain.items():
- if key in ("smtp", "imap", "pop"):
+ if key in ("smtp", "imap", "pop", "caldav", "carddav", "ox"):
if len(value) != 0:
protocol = etree.SubElement(account, "Protocol")
self.__service(key, protocol)
@@ -291,6 +305,12 @@ class View(object):
s_type = service.upper()
elif service in "pop":
s_type = "POP3"
+ elif service in "caldav":
+ s_type = "CalDAV"
+ elif service in "carddav":
+ s_type = "CardDAV"
+ elif service in "ox":
+ s_type = "X-OX-APPSUITE"
c.text = s_type
@@ -450,19 +470,19 @@ class View(object):
if service + "_server" in elem:
if service in ("imap", "pop"):
proto["in_server"] = elem[service + "_server"]
- else:
+ elif service == "smtp":
proto["out_server"] = elem[service + "_server"]
if service + "_port" in elem:
if service in ("imap", "pop"):
proto["in_port"] = int(elem[service + "_port"])
- else:
+ elif service == "smtp":
proto["out_port"] = int(elem[service + "_port"])
if service + "_auth_identity" in elem:
if service in ("imap", "pop"):
proto["in_username"] = elem[service + "_auth_identity"]
- else:
+ elif service == "smtp":
proto["out_username"] = elem[service + "_auth_identity"]
if service + "_auth" in elem:
@@ -490,7 +510,7 @@ class View(object):
if service in ("imap", "pop"):
proto["in_auth"] = result
- else:
+ elif service == "smtp":
proto["out_auth"] = result
if service + "_encryption" in elem:
@@ -499,12 +519,12 @@ class View(object):
if value in ("ssl", "starttls"):
if service in ("imap", "pop"):
proto["in_encryption"] = True
- else:
+ elif service == "smtp":
proto["out_encryption"] = True
else:
if service in ("imap", "pop"):
proto["in_encryption"] = False
- else:
+ elif service == "smtp":
proto["out_encryption"] = False
def render(self):
@@ -520,7 +540,11 @@ class View(object):
pretty_print=True)
elif self.__plist is not None:
- plist_unsigned = dumps(self.__plist, fmt=FMT_XML)
+ if sys.version_info < (3,):
+ plist_unsigned = writePlistToString(self.__plist)
+ else:
+ # noinspection PyArgumentList
+ plist_unsigned = dumps(self.__plist, fmt=FMT_XML)
# Old M2Crypto that is not ported yet to Python3
"""
@@ -566,7 +590,7 @@ class View(object):
sign_cert = self.__model.domain["sign_cert"]
sign_key = self.__model.domain["sign_key"]
-
+
if "sign_more_certs" in self.__model.domain:
extra = " -certfile " + self.__model.domain[
"sign_more_certs"]
diff --git a/src/automx_wsgi.py b/src/automx_wsgi.py
index f38b3be..ea80a7f 100755
--- a/src/automx_wsgi.py
+++ b/src/automx_wsgi.py
@@ -15,20 +15,37 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
import os
import sys
import traceback
import logging
+# noinspection PyCompatibility
from html import escape
from io import StringIO
from lxml import etree
from lxml.etree import XMLSyntaxError
+# noinspection PyCompatibility
from builtins import int, str
-from urllib.parse import urlparse, urlencode, parse_qs, unquote
-from urllib.request import urlopen, Request
-from urllib.error import HTTPError
+try:
+ # noinspection PyCompatibility
+ from urllib.parse import urlparse, urlencode, parse_qs, unquote
+ # noinspection PyCompatibility
+ from urllib.request import urlopen, Request
+ # noinspection PyCompatibility
+ from urllib.error import HTTPError
+except ImportError:
+ # noinspection PyCompatibility
+ from urlparse import urlparse, parse_qs
+ from urllib import urlencode, unquote
+ # noinspection PyCompatibility
+ from urllib2 import urlopen, Request, HTTPError
from automx.config import Config
from automx.config import DataNotFoundException
@@ -262,25 +279,43 @@ def application(environ, start_response):
data.domain["sign_mobileconfig"] is True):
logging.debug("No debugging output for signed mobileconfig!")
else:
- logging.debug(str("Response:\n%s" % response_body))
+ if sys.version_info < (3,):
+ logging.debug("Response:\n" + response_body.decode('utf-8'))
+ else:
+ logging.debug(str("Response:\n%s" % response_body))
body_len = str(len(response_body))
+ def aenc(key, value):
+ """Auto-enocde to ascii; Make headers compatible for Py2/Py3
+
+ :param key: header key
+ :param value: header value
+ :return: auto encoded tuple
+ """
+ if sys.version_info < (3,):
+ return key.encode("ascii"), value.encode("ascii")
+ else:
+ return key, value
+
if schema in ('autoconfig', "autodiscover"):
- response_headers = [('Content-Type', 'text/xml'),
- ('Content-Length', body_len)]
+ response_headers = [aenc('Content-Type', 'text/xml'),
+ aenc('Content-Length', body_len)]
elif schema == "mobileconfig":
- response_headers = [('Content-Type',
- 'application/x-apple-aspen-config'
- '; charset=utf-8'),
- ('Content-Disposition',
- 'attachment; '
- 'filename="company.mobileconfig'),
- ('Content-Length', body_len)]
+ response_headers = [aenc('Content-Type',
+ 'application/x-apple-aspen-config'
+ '; charset=utf-8'),
+ aenc('Content-Disposition',
+ 'attachment; '
+ 'filename="company.mobileconfig'),
+ aenc('Content-Length', body_len)]
else:
# Failure?
- response_headers = [('Content-Type', 'text/html'),
- ('Content-Length', body_len)]
+ response_headers = [aenc('Content-Type', 'text/html'),
+ aenc('Content-Length', body_len)]
+
+ if sys.version_info < (3,):
+ status = status.encode("ascii")
start_response(status, response_headers)
diff --git a/src/doc/automx.conf.5.rst b/src/doc/automx.conf.5.rst
index 35a0893..e9271c1 100644
--- a/src/doc/automx.conf.5.rst
+++ b/src/doc/automx.conf.5.rst
@@ -67,6 +67,28 @@ smtp
protocol to connect to this server is SMTP. Specifying this name is
only applicable for account_type = email.
+caldav
+ This name specifies a CalDAV service as defined in RFC 4791. The
+ protocol to connect to this server is HTTP. The server definition expects
+ a URL like https://caldav.example.com/. Specifying this name is only
+ applicable for account_type = email currently.
+ This service only affects autodiscover view.
+
+carddav
+ This name specifies a CardDAV service as defined in RFC 6352. The
+ protocol to connect to this server is HTTP. The server definition expects
+ a URL like https://carddav.example.com/. Specifying this name is only
+ applicable for account_type = email currently.
+ This service only affects autodiscover view.
+
+ox
+ This name specifies an existing OX App Suite service. Some clients
+ need to know where to access the OX App Suite HTTP API. The server
+ definition expects a URL like https://ox.example.com/. Specifying
+ this name is only applicable for account_type = email currently.
+ This service only affects autodiscover view.
+
+
Parameters
''''''''''
@@ -74,7 +96,7 @@ autoconfig (no default)
Specifies a path to a file that contains static autoconfiguration
options following to the Mozilla schema.
- .. NOTE::
+ .. NOTE::
This parameter is valid only if backend = file has been specified.
@@ -194,7 +216,7 @@ mobileconfig (no default)
Specifies a path to a file that contains static mobileconfiguration
options following to the Mozilla schema.
- .. NOTE::
+ .. NOTE::
This parameter is valid only if backend = file has been specified.
@@ -390,5 +412,3 @@ See also
.. _automx_sql(5): automx_sql.5.html
.. _automx_script(5): automx_script.5.html
.. _automx-test(1): automx-test.1.html
-
-
diff --git a/src/html/index.html.de b/src/html/index.html.de
index 4954fd9..030e4a5 100644
--- a/src/html/index.html.de
+++ b/src/html/index.html.de
@@ -42,11 +42,11 @@
</div>
<div id="footer-desktop" class="hide-for-small">
- <a class="right automx-powered" href="http://automx.org" target="_blank">Powered by <img src="img/automx-banner.png" width="126" height="20" alt="automx banner" /></a>
+ <a class="right automx-powered" href="https://automx.org" target="_blank">Powered by <img src="img/automx-banner.png" width="126" height="20" alt="automx banner" /></a>
</div>
<div id="footer-mobile" class="show-for-small row">
<div class="small-12 columns">
- <a class="right automx-powered" href="http://automx.org" target="_blank">Powered by <img src="img/automx-banner.png" width="126" height="20" alt="automx banner" /></a>
+ <a class="right automx-powered" href="https://automx.org" target="_blank">Powered by <img src="img/automx-banner.png" width="126" height="20" alt="automx banner" /></a>
</div>
</div>
diff --git a/src/html/index.html.en b/src/html/index.html.en
index a88f043..1acb53a 100644
--- a/src/html/index.html.en
+++ b/src/html/index.html.en
@@ -43,11 +43,11 @@
</div>
<div id="footer-desktop" class="hide-for-small">
- <a class="right automx-powered" href="http://automx.org" target="_blank">Powered by <img src="img/automx-banner.png" width="126" height="20" alt="automx banner" /></a>
+ <a class="right automx-powered" href="https://automx.org" target="_blank">Powered by <img src="img/automx-banner.png" width="126" height="20" alt="automx banner" /></a>
</div>
<div id="footer-mobile" class="show-for-small row">
<div class="small-12 columns">
- <a class="right automx-powered" href="http://automx.org" target="_blank">Powered by <img src="img/automx-banner.png" width="126" height="20" alt="automx banner" /></a>
+ <a class="right automx-powered" href="https://automx.org" target="_blank">Powered by <img src="img/automx-banner.png" width="126" height="20" alt="automx banner" /></a>
</div>
</div>