diff --git a/endpoints/misc.py b/endpoints/misc.py index 9a8dcf0..c8e1211 100644 --- a/endpoints/misc.py +++ b/endpoints/misc.py @@ -12,7 +12,7 @@ from orm import DB from services import Service -from tools import formats +from tools import formats, mconf from tools.tasq import TasQServer @@ -152,3 +152,19 @@ def getDisabledPluginsOfUser(): disabledPlugins = [p[0] for p in disabledPlugins] return jsonify({ "data": disabledPlugins }) + + +@API.route(api.BaseRoute+"/oofSubjectPrefix", methods=["GET"]) +@secure(requireAuth=False) +def getOofSubjectPrefix(): + """Report the gromox.cfg autoreply_subject_prefix directive. + + A client offering an out-of-office form needs it to tell the user what an + empty subject will send. An unset directive is reported as + configured=false rather than guessed at, because the default that then + applies is compiled into the running gromox build. + """ + prefix, error = mconf.readGromoxDirective("autoreply_subject_prefix") + if error is not None: + return jsonify(message=error), 500 + return jsonify({"data": {"prefix": prefix, "configured": prefix is not None}}) diff --git a/res/openapi.yaml b/res/openapi.yaml index 857b442..c39e754 100644 --- a/res/openapi.yaml +++ b/res/openapi.yaml @@ -2293,6 +2293,41 @@ paths: '503': $ref: '#/components/responses/DatabaseError' + /oofSubjectPrefix: + get: + summary: Get the configured out-of-office reply subject prefix + description: > + Reports the gromox.cfg autoreply_subject_prefix directive, which gromox + prepends to the subject of the incoming message when a mailbox has no + out-of-office subject of its own. Clients offering an out-of-office form + use it to show what an empty subject will send. + operationId: oofSubjectPrefix + tags: + - Misc + responses: + '200': + description: Prefix state returned + content: + application/json: + schema: + type: object + properties: + data: + type: object + properties: + prefix: + type: string + nullable: true + description: The configured prefix, or null when the directive is not set + configured: + type: boolean + description: > + Whether the directive is set. When false, gromox applies the + default compiled into the running build, which cannot be read + from the configuration file. + '500': + $ref: '#/components/responses/ServerError' + /domains/{domainID}/users: get: summary: Get lists of users diff --git a/tools/config.py b/tools/config.py index 41ad2ae..1a86778 100644 --- a/tools/config.py +++ b/tools/config.py @@ -96,7 +96,8 @@ def _defaultConfig(): }, "mconf": { "ldapPath": "/etc/gromox/ldap_adaptor.cfg", - "authmgrPath": "/etc/gromox/authmgr.cfg" + "authmgrPath": "/etc/gromox/authmgr.cfg", + "gromoxPath": "/etc/gromox/gromox.cfg" }, "logs": {}, "sync": { diff --git a/tools/mconf.py b/tools/mconf.py index f612ada..1a64525 100644 --- a/tools/mconf.py +++ b/tools/mconf.py @@ -9,6 +9,8 @@ from .misc import setDirectoryOwner, setDirectoryPermission from services import Service +from os.path import exists + import logging logger = logging.getLogger("mconf") @@ -235,6 +237,32 @@ def dumpAuthmgr(conf=None, file=None, reloadServices=False): ############################################################################### +def readGromoxDirective(name): + """Read a single directive from the main gromox configuration file. + + Not cached, so an admin editing gromox.cfg need not restart the API. + gromox trims trailing whitespace off every configuration line and + _loadConf does too, so this returns the value gromox itself sees. + + Returns + ------- + tuple + (value, error). value is None when the directive is not set. + """ + if "gromoxPath" not in Config["mconf"]: + return None, "mconf.gromoxPath not set" + path = Config["mconf"]["gromoxPath"] + if not exists(path): + return None, "'{}' does not exist".format(path) + try: + return _loadConf(path).get(name), None + except Exception as err: + return None, " - ".join((str(arg) for arg in err.args)) + + +############################################################################### + + def load(): error = loadLdap() if error: