Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F16569000
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
27 KB
Referenced Files
None
Subscribers
None
View Options
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
Details
Attached
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)
Attached To
Mode
rP pykolab
Attached
Detach File
Event Timeline
Log In to Comment