Page MenuHomePhorge

No OneTemporary

diff --git a/conf/kolab.conf b/conf/kolab.conf
index 4b590b9..afe318f 100644
--- a/conf/kolab.conf
+++ b/conf/kolab.conf
@@ -1,452 +1,494 @@
[kolab]
; Set this to the primary domain name space served within this Kolab Groupware
; deployment.
primary_domain = example.org
; This is the primary authentication mechanism used, and contains the list of
; domain name spaces for this deployment. Each domain name space may have its
; own auth_mechanism setting.
;
; Valid options currently include only 'ldap'.
auth_mechanism = ldap
; The IMAP backend to use - currently supported values include only
; 'cyrus-imap'.
imap_backend = cyrus-imap
; The default locale for this Kolab Groupware installation
default_locale = en_US
; Synchronization interval - describes the number of seconds to wait in
; between non-persistent synchronization attempts. Relevant only for
; deployments that lack persistent search and syncrepl ldap controls.
sync_interval = 300
; Synchronization interval for domains - describes the number of seconds
; to wait in between polls for new and deleted domain name spaces.
domain_sync_interval = 600
; The policy to use when originally composing the uid attribute value.
; Normally '%(surname)s.lower()', the transliterated value of the 'sn',
; in all lower-case.
;
; Other examples include:
;
; policy_uid = '%(givenname)s'[0:1]%(surname)s.lower()
; policy_uid = %(givenname)s
policy_uid = %(surname)s.lower()
; Primary and secondary recipient address policies. This is called the
; recipient policy as documented in:
;
; http://docs.kolab.org/administrator-guide/configuring-the-kolab-server.html#recipient-policy
;
; Note this is the global default, and each [$domain] section can have
; their own (as in this default configuration, see [example.org]).
primary_mail = %(surname)s@%(domain)s
secondary_mail = {
0: {
"{0}.{1}@{2}": "format('%(givenname)s'[0:1].capitalize(), '%(surname)s', '%(domain)s')"
},
1: {
"{0}@{1}": "format('%(uid)s', '%(domain)s')"
},
2: {
"{0}@{1}": "format('%(givenname)s.%(surname)s', '%(domain)s')"
}
}
; To disable the application of the recipient policy by the daemon ('kolabd' service),
; uncomment the next line.
;daemon_rcpt_policy = False
; A global default for folders to create in addition to the INBOX
; folder.
autocreate_folders = {
'Archive': {
'quota': 0,
'partition': 'archive'
},
'Calendar': {
'annotations': {
'/private/vendor/kolab/folder-type': "event.default",
'/shared/vendor/kolab/folder-type': "event",
},
},
'Calendar/Personal Calendar': {
'annotations': {
'/shared/vendor/kolab/folder-type': "event",
},
},
'Configuration': {
'annotations': {
'/private/vendor/kolab/folder-type': "configuration.default",
'/shared/vendor/kolab/folder-type': "configuration",
},
},
'Contacts': {
'annotations': {
'/private/vendor/kolab/folder-type': "contact.default",
'/shared/vendor/kolab/folder-type': "contact",
},
},
'Contacts/Personal Contacts': {
'annotations': {
'/shared/vendor/kolab/folder-type': "contact",
},
},
'Drafts': {
'annotations': {
'/private/vendor/kolab/folder-type': "mail.drafts",
},
},
'Files': {
'annotations': {
'/private/vendor/kolab/folder-type': "file.default",
'/shared/vendor/kolab/folder-type': "file",
},
},
'Journal': {
'annotations': {
'/private/vendor/kolab/folder-type': "journal.default",
'/shared/vendor/kolab/folder-type': "journal",
},
},
'Notes': {
'annotations': {
'/private/vendor/kolab/folder-type': 'note.default',
'/shared/vendor/kolab/folder-type': 'note',
},
},
'Sent': {
'annotations': {
'/private/vendor/kolab/folder-type': "mail.sentitems",
},
},
'Spam': {
'annotations': {
'/private/vendor/kolab/folder-type': "mail.junkemail",
},
},
'Tasks': {
'annotations': {
'/private/vendor/kolab/folder-type': "task.default",
'/shared/vendor/kolab/folder-type': "task",
},
},
'Trash': {
'annotations': {
'/private/vendor/kolab/folder-type': "mail.wastebasket",
},
},
}
[autodiscover]
; service hosts (%d will be replaced by user domain)
; for imap/pop3/smtp protocol prefix and port is required
activesync = activesync.%d
imap = ssl://imap.%d:993
pop3 = ssl://pop3.%d:995
smtp = ssl://smtp.%d:465
; LDAP attribute used as login
login_attribute = mail
; optional service name
service_name = Kolab Groupware
service_short = Kolab
; enables HTTP/LDAP debugging
;debug_mode = trace
[imap]
virtual_domains = userid
[ldap]
; The URI to LDAP
ldap_uri = ldap://localhost:389
; A list of integers containing supported controls, to increase the efficiency
; of individual short-lived connections with LDAP.
supported_controls = 0,2,3
; The base dn for the deployment. Note that this is the highest level in the
; tree Kolab will ever go. Should your OU structure allow it, you could set this
; to ou=Kolab,ou=Not-So-Private,dc=example,dc=org.
base_dn = dc=example,dc=org
; The (administrative) bind dn and corresponding password.
;
; Feel free to set this to a DN with only read permissions on the tree. These
; credentials are used by the Kolab Daemon only, as it might need to set
; additional attributes in order to apply plugins successfully. Such attributes
; could include the first two values in the 'mail_attributes' list (see further
; down) to complete the 'recipient_policy' (see further down), mail quota,
; the mail server attribute, and others.
bind_dn = cn=Directory Manager
bind_pw = Welcome123
; Bind DN and password used for services. The DN should have read and search
; privileges only, but should be able to read all relevant parts of the tree.
;
; These credentials are used by, among others, Postfix, Wallace, programs that
; need to find the user DN before binding as the user (including the webadmin
; API, Roundcube, Syncroton).
service_bind_dn = uid=kolab-service,ou=Special Users,%(base_dn)s
service_bind_pw = wc18bqshFmifGtN
; The base DN, search scope and filter to use when searching for users of any
; type. User types are of primary purpose to the web admin (API), but the
; generic base DN, scope and filter allow us to configure other services as
; well, including Address Books in Roundcube and for Syncroton, the list of
; users in the web admin (API), etc.
user_base_dn = ou=People,%(base_dn)s
user_scope = sub
user_filter = (objectclass=inetorgperson)
; The base DN, scope and filter to use when searching for users of the 'kolab'
; type. This filter is preferred when searching for Kolab users specifically,
; such as in the synchronisation between LDAP and IMAP. Also, it is
; (preferrably) only Kolab users that are allowed to login, use the SMTP server,
; etc.
;
; Note that all user_* settings are valid, and those not available with a kolab_
; prefix fall back to using the generic user_* equivalent setting.
kolab_user_base_dn = ou=People,%(base_dn)s
kolab_user_filter = (objectclass=kolabinetorgperson)
; Add additional <key>_user_base_dn, <key>_user_scope and <key>_user_filter.
; Useful for configuring sub-address books, and for the webadmin API when adding
; new users of the example type key 'posix' - the new user will be added in the
; OU configured below.
;posix_user_base_dn = ou=POSIX Accounts,ou=People,%(base_dn)s
;posix_user_scope = one
;posix_user_filter = (&(objectclass=posixaccount)(uidnumber>=1000))
; The same as for users, but applicable to groups
group_base_dn = ou=Groups,%(base_dn)s
group_filter = (|(objectclass=groupofuniquenames)(objectclass=groupofurls))
group_scope = sub
kolab_group_filter = (|(objectclass=kolabgroupofuniquenames)(objectclass=kolabgroupofurls))
; Same again
sharedfolder_base_dn = ou=Shared Folders,%(base_dn)s
sharedfolder_filter = (objectclass=kolabsharedfolder)
; The attribute entry name that controls the ACLs set on a shared folder
sharedfolder_acl_entry_attribute = acl
; Same again. Resources live in a different OU structure or;
;
; - They would appear in the address book(s) as distribution lists or individual contacts,
; - Groups or individual users would appear to be Resources.
;
resource_base_dn = ou=Resources,%(base_dn)s
resource_filter = (|%(group_filter)s(objectclass=kolabsharedfolder))
; The base DN, scope and filter to use when searching for additional domain
; name spaces in this environment.
domain_base_dn = cn=kolab,cn=config
domain_filter = (&(associatedDomain=*))
domain_name_attribute = associateddomain
; Attribute that holds the root dn for the domain name space. If this attribute
; does not exist, a standard root dn is formed from the primary domain name
; space (the value in the RDN), as follows:
;
; 'dc=' + ',dc='.join(domainname.split('.'))
;
; or, in example:
;
; domain: example.org
; root dn: dc=example,dc=org
domain_rootdn_attribute = inetdomainbasedn
; The attribute that holds the quota.
quota_attribute = mailquota
; The format of the modifytimestamp attribute values
modifytimestamp_format = %Y%m%d%H%M%SZ
; A unique attribute that can be used to identify the entry beyond renames and
; moves. Note that 'nsuniqueid' is specific to all Netscape-based directory
; services.
;
; For OpenLDAP, use 'entrydn' - the 'entryUUID' can regrettably not be searched
; with.
;
; For Active Directory, use 'objectsid'.
unique_attribute = nsuniqueid
; Attribute names that hold valid, internal recipient addresses. Note the use
; of mail and alias frees up the use of mailAlternateAddress to contain a user's
; external email address.
;
; Syntax is a comma- or comma-space separated list.
;
; The first value is used for the purpose of a single "primary" email address,
; that could be subject to a recipient policy, the second is used for the
; purpose of one or more secondary mail addresses, that could also be subject to
; a recipient policy.
mail_attributes = mail, alias
; The attribute that holds the FQDN to the mail server the folder exists on
mailserver_attribute = mailhost
; Attributes that hold valid authentication login names. Use 'mail', 'alias' and
; optionally 'uid' (the uid is marked as an auth_attribute automatically), so
; that a user can login with;
;
; - uid (i.e. 'jdoe'),
; - mail, fully qualified and localpart only (i.e. "john.doe" and
; "john.doe@example.org"),
; - alias, fully qualified and localpart only (i.e. "j.doe" and
; "j.doe@example.org).
auth_attributes = mail, alias, uid
; Virtual List View control, and Server-Side Sorting control configuration.
;
; Configure these to allow the Web Administration Panel (API) to not have to
; search a non-database cn=config for the VLV configuration.
;
;vlv = [
; {
; 'ou=People,dc=example,dc=org': {
; 'scope': 'sub',
; 'filter': '(objectclass=inetorgperson)',
; 'sort' : [
; [
; 'displayname',
; 'sn',
; 'givenname',
; 'cn'
; ]
; ]
; }
; },
; {
; 'ou=Groups,dc=example,dc=org': {
; 'scope': 'sub',
; 'filter': '(objectclass=groupofuniquenames)',
; 'sort' : [
; [
; 'cn'
; ]
; ]
; }
; },
; ]
[kolab_smtp_access_policy]
cache_uri = mysql://user:pass@localhost/database
cache_retention = 86400
; To allow users to also send using email addresses in domain name spaces not
; in their own parent and/or alias domains, add 'mailalternateaddress' to this
; list.
address_search_attrs = mail, alias
; Prepend the Sender: and/or X-Sender header(s) if the user authenticated is a
; designated delegatee of the envelope sender address?
delegate_sender_header = True
; Prepend the Sender: and/or X-Sender header(s) if the user authenticated
; is using an envelope sender address that is a secondary recipient email
; address (attached to the object entry) of the user authenticated?
alias_sender_header = True
; Prepend the Sender: header? Only relevant if delegate_sender_header or
; alias_sender_header is set to True.
sender_header = True
; Prepend the X-Sender: header? Only relevant if delegate_sender_header or
; alias_sender_header is set to True.
xsender_header = True
; "Encrypt" -- read, "obscure" -- the contents of the 'Sender:' and/or
; 'X-Sender:' header(s). Note that this invalidates client's use of the header
; value, and therefore replaces both headers with 'X-Authenticated-As'.
;
; Example: 'vanmeeuwen@kolabsys.com' becomes '6crb3dHK6ODS3qzQ4tXO0t_e5pfQ39k='
;
; sender_header_enc_key = 'simple'
; Allow hosts in these networks to submit messages with empty envelope senders,
; such as web-clients responding to MDN requests.
empty_sender_hosts = 3.2.1.0/24, 6.6.6.0/24
; Section for Hosted client interface settings. This is not enabled by default.
;[kolab_hosting]
;
;; Set the default domain name space for the list of domain name spaces (if more
;; than one) that new users that register are allowed to select.
;primary_domain = somedomain.tld
;
;; The following bind credentials should be allowed to search
;; "ldap/domain_base_dn" (i.e. cn=kolab,cn=config), but should not be allowed to
;; read any domain name space LDAP entry that users are not eligible to select.
;;
;; Note that the bind credentials usually live in the upper
;; "kolab/primary_domain".
;bind_dn = uid=hosted-service,ou=Special Users,dc=kolab,dc=net
;bind_pw = bla
;recaptcha_private_key = bla
;recaptcha_public_key = bla
[kolab_wap]
skin = default
sql_uri = mysql://user:pass@localhost/database
; Use the following setting to indicate the API is installed on a different
; system, or in a non-standard location.
;api_url = http://localhost/kolab-webadmin/api
; Configure SSL should you want to have the web admin panel (client interface)
; use the API over HTTPS.
;
; By default, httpd and coconspirators are setup to use self-signed certificates,
; so the following two settings are set to false by default.
ssl_verify_peer = false
ssl_verify_host = false
;ssl_cafile = /path/to/ca/file
;ssl_capath = /path/to/ca/dir
;ssl_local_cert = /path/to/local/cert
;ssl_passphrase = MyPassword
[cyrus-imap]
; The URI to use to connect to IMAP. Note that pykolab itself can detect whether
; or not Cyrus IMAP is deployed in a Murder topology, and should be able to
; connect to individual backends as well.
uri = imaps://localhost:993
; The login username to use for global administration.
admin_login = cyrus-admin
; The corresponding password.
admin_password = Welcome123
[cyrus-sasl]
; The user canonification result attribute.
result_attribute = mail
[wallace]
-modules = resources, invitationpolicy, footer
-footer_text = /etc/kolab/footer.text
-footer_html = /etc/kolab/footer.html
+; List the modules to load and apply, in order.
+;
+; Available modules include;
+;
+; * resources
+; * invitationpolicy
+; * footer
+; * signature
+;
+modules = resources, invitationpolicy
+
+; Footer module settings
+;footer_text = /etc/kolab/footer.text
+;footer_html = /etc/kolab/footer.html
+
+; Signature module settings
+;
+; Two modes: write out the exact signature in /etc/kolab/ as html and/or text,
+; or use rules.
+;
+; If files are configured, rules do not apply. If files are configured, a
+; fallback is /etc/kolab/signature_default.{html,txt}.
+;
+; signature_file_html = /etc/kolab/signature.d/%(mail)s.html
+; signature_file_text = /etc/kolab/signature.d/%(mail)s.txt
+;
+; A list of dicts, with each dict holding an attribute name ("o", "cn",
+; "entrydn"), and a regular expression to be matched against the attribute
+; value.
+;
+; The module takes the first match, and uses the "html" and "text" files as
+; templates.
+;
+;signature_rules = [
+; {
+; "entrydn": "uid=.*,ou=IT,ou=People,dc=example,dc=org",
+; "html": "/etc/kolab/signature_IT.html",
+; "text": "/etc/kolab/signature_IT.txt"
+; },
+; {
+; "entrydn": "uid=.*,ou=Finance,ou=People,dc=example,dc=org",
+; "html": "/etc/kolab/signature_Finance.html",
+; "text": "/etc/kolab/signature_Finance.txt"
+; }
+; ]
; default settings for kolabInvitationPolicy LDAP attribute on user records
kolab_invitation_policy = ACT_ACCEPT_IF_NO_CONFLICT:example.org, ACT_MANUAL
; automatically update the participant status from iTip REPLY messages
; in the personal calendars of all other listed participants.
invitationpolicy_autoupdate_other_attendees_on_reply = false
; number of days past their end resource calendar events should be kept
resource_calendar_expire_days = 100
; This is a domain name space specific section, that enables us to override
; all settings, for example, the LDAP URI, base and bind DNs, scopes, filters,
; etc. Note that overriding the LDAP settings for the primary domain name space
; does not make any sense.
[example.org]
default_quota = 1048576
primary_mail = %(givenname)s.%(surname)s@%(domain)s
diff --git a/conf/signature_IT.html b/conf/signature_IT.html
new file mode 100644
index 0000000..07ad4dd
--- /dev/null
+++ b/conf/signature_IT.html
@@ -0,0 +1,13 @@
+<br clear="all"/>
+<hr>
+This is an example HTML signature.
+
+<p style="font-size: small; color: gray;">
+%(o)s
+
+%(manager:cn)s
+
+M: %(mobile)s
+T: %(telephonenumber)s
+W: https://it.services.inc
+</p>
diff --git a/conf/signature_IT.txt b/conf/signature_IT.txt
new file mode 100644
index 0000000..53fd640
--- /dev/null
+++ b/conf/signature_IT.txt
@@ -0,0 +1,9 @@
+This is an example TEXT signature.
+
+%(o)s
+
+%(manager:cn)s
+
+M: %(mobile)s
+T: %(telephonenumber)s
+W: https://it.services.inc
diff --git a/wallace/module_signature.py b/wallace/module_signature.py
new file mode 100644
index 0000000..5098120
--- /dev/null
+++ b/wallace/module_signature.py
@@ -0,0 +1,248 @@
+# -*- coding: utf-8 -*-
+# Copyright 2010-2019 Kolab Systems AG (http://www.kolabsys.com)
+#
+# Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen a kolabsys.com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# 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/>.
+#
+
+import json
+import os
+import re
+import tempfile
+
+from email.encoders import encode_quopri
+from email.parser import Parser
+from email.utils import getaddresses
+
+import modules
+import pykolab
+
+from pykolab.auth import Auth
+from pykolab.translate import _
+
+# pylint: disable=invalid-name
+log = pykolab.getLogger('pykolab.wallace')
+conf = pykolab.getConf()
+
+mybasepath = '/var/spool/pykolab/wallace/signature/'
+
+
+def __init__():
+ modules.register('signature', execute, description=description())
+
+
+def description():
+ return """Append a signature to messages."""
+
+
+def set_part_content(part, content):
+ # Reset old encoding and use quoted-printable (#5414)
+ del part['Content-Transfer-Encoding']
+ part.set_payload(content)
+ encode_quopri(part)
+
+ return True
+
+
+def attr_resolve(sender_info, attr):
+ try:
+ attr, attr_val = attr.split(':')
+ except ValueError:
+ return None
+
+ auth = Auth()
+ auth.connect()
+
+ values = []
+
+ if not isinstance(sender_info[attr], list):
+ sender_info[attr] = [sender_info[attr]]
+
+ for sender_attr_val in sender_info[attr]:
+ values.append(auth.get_entry_attribute(None, sender_attr_val, attr_val))
+
+ return ", ".join(values)
+
+
+# pylint: disable=too-many-branches,too-many-locals,too-many-statements
+def execute(*args, **kw): # noqa: C901
+ if not os.path.isdir(mybasepath):
+ os.makedirs(mybasepath)
+
+ for stage in ['incoming', 'ACCEPT']:
+ if not os.path.isdir(os.path.join(mybasepath, stage)):
+ os.makedirs(os.path.join(mybasepath, stage))
+
+ # TODO: Test for correct call.
+ filepath = args[0]
+
+ if 'stage' in kw:
+ log.debug(_("Issuing callback after processing to stage %s") % (kw['stage']), level=8)
+ log.debug(_("Testing cb_action_%s()") % (kw['stage']), level=8)
+ if hasattr(modules, 'cb_action_%s' % (kw['stage'])):
+ log.debug(_("Attempting to execute cb_action_%s()") % (kw['stage']), level=8)
+ exec('modules.cb_action_%s(%r, %r)' % (kw['stage'], 'signature', filepath))
+ return
+
+ log.debug(_("Executing module signature for %r, %r") % (args, kw), level=8)
+
+ new_filepath = os.path.join(
+ '/var/spool/pykolab/wallace/signature/incoming',
+ os.path.basename(filepath)
+ )
+
+ os.rename(filepath, new_filepath)
+ filepath = new_filepath
+
+ # parse message
+ message = Parser().parse(open(filepath, 'r'))
+
+ sender_address = [
+ address for displayname, address in getaddresses(message.get_all('X-Kolab-From'))
+ ][0]
+
+ auth = Auth()
+ auth.connect()
+
+ sender_dn = auth.find_recipient(sender_address)
+ if not sender_dn:
+ exec('modules.cb_action_%s(%r, %r)' % ('ACCEPT', 'signature', filepath))
+ return
+
+ sender_info = auth.get_entry_attributes(None, sender_dn, ['*', 'entrydn', 'manager'])
+
+ log.debug("Sender info: %r" % (sender_info), level=7)
+
+ signature_rules = conf.get_raw('wallace', 'signature_rules')
+
+ if signature_rules:
+ signature_rules = json.loads(signature_rules)
+
+ log.debug("Signature rules: %r" % (signature_rules), level=7)
+
+ signature_html = None
+ signature_text = None
+
+ sig_html_conf = conf.get_raw('wallace', 'signature_file_html')
+ sig_text_conf = conf.get_raw('wallace', 'signature_file_text')
+
+ if sig_html_conf and sig_text_conf:
+ _sig_html_conf = sig_html_conf % sender_info
+ _sig_text_conf = sig_text_conf % sender_info
+
+ if not os.path.exists(_sig_html_conf):
+ _sig_html_conf = '/etc/kolab/signature.d/default.html'
+
+ if not os.path.exists(_sig_text_conf):
+ _sig_text_conf = '/etc/kolab/signature.d/default.txt'
+
+ if os.path.exists(_sig_html_conf):
+ signature_html = open(_sig_html_conf, 'r').read()
+
+ if os.path.exists(_sig_text_conf):
+ signature_text = open(_sig_text_conf, 'r').read()
+
+ if not signature_html and not signature_text:
+ for signature_rule in signature_rules:
+ try:
+ for attr, regex in signature_rule.iteritems():
+ if attr == "html":
+ if not os.path.exists(signature_rule['html']):
+ raise ValueError
+ continue
+
+ if attr == "text":
+ if not os.path.exists(signature_rule['text']):
+ raise ValueError
+ continue
+
+ if attr in sender_info and re.match(regex, sender_info[attr], flags=re.IGNORECASE):
+ success = False
+
+ while not success:
+ try:
+ signature_html = open(signature_rule['html'], 'r').read() % sender_info
+ signature_text = open(signature_rule['text'], 'r').read() % sender_info
+
+ success = True
+
+ except KeyError as errmsg:
+ sender_info[errmsg] = attr_resolve(sender_info, errmsg)
+ except ValueError:
+ continue
+
+ if signature_html is None and signature_text is None:
+ exec('modules.cb_action_%s(%r, %r)' % ('ACCEPT', 'signature', filepath))
+ return
+
+ signature_added = False
+
+ try:
+ _signature_added = message.get("X-Wallace-Signature")
+
+ # pylint: disable=broad-except
+ except Exception:
+ pass
+
+ if _signature_added == "YES":
+ exec('modules.cb_action_%s(%r, %r)' % ('ACCEPT','signature', filepath))
+ return
+
+ for part in message.walk():
+ disposition = None
+
+ try:
+ content_type = part.get_content_type()
+
+ # pylint: disable=broad-except
+ except Exception:
+ continue
+
+ try:
+ disposition = part.get("Content-Disposition")
+
+ # pylint: disable=broad-except
+ except Exception:
+ pass
+
+ log.debug("Walking message part: %s; disposition = %r" % (content_type, disposition), level=8)
+
+ if disposition is not None:
+ continue
+
+ if content_type == "text/plain":
+ content = part.get_payload(decode=True)
+ content += "\n\n-- \n%s" % (signature_text)
+ signature_added = set_part_content(part, content)
+
+ elif content_type == "text/html":
+ content = part.get_payload(decode=True)
+ append = "\n<!-- signature appended by Wallace -->\n" + signature_html
+ if "</body>" in content:
+ content = content.replace("</body>", append + "</body>")
+ else:
+ content = "<html><body>" + content + append + "</body></html>"
+ signature_added = set_part_content(part, content)
+
+ if signature_added:
+ log.debug("Signature attached.", level=8)
+ message.add_header("X-Wallace-Signature", "YES")
+
+ (fp, new_filepath) = tempfile.mkstemp(dir="/var/spool/pykolab/wallace/signature/ACCEPT")
+ os.write(fp, message.as_string())
+ os.close(fp)
+ os.unlink(filepath)
+
+ exec('modules.cb_action_%s(%r, %r)' % ('ACCEPT','signature', new_filepath))

File Metadata

Mime Type
text/x-diff
Expires
Fri, Nov 1, 8:07 AM (1 d, 5 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
10074750
Default Alt Text
(27 KB)

Event Timeline