# -*- coding: utf-8 -*-
#
# UCS test
#
# Copyright 2013-2022 Univention GmbH
#
# https://www.univention.de/
#
# All rights reserved.
#
# The source code of this program is made available
# under the terms of the GNU Affero General Public License version 3
# (GNU AGPL V3) as published by the Free Software Foundation.
#
# Binary versions of this program provided by Univention to you as
# well as other copyrighted, protected or trademarked materials like
# Logos, graphics, fonts, specific documentations and configurations,
# cryptographic keys etc. are subject to a license agreement between
# you and Univention and not subject to the GNU AGPL V3.
#
# In the case you use this program under the terms of the GNU AGPL V3,
# the program is provided 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 Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public
# License with the Debian GNU/Linux or Univention distribution in file
# /usr/share/common-licenses/AGPL-3; if not, see
# <https://www.gnu.org/licenses/>.
from __future__ import print_function
import os
import pwd
import subprocess
import sys
import time
from types import TracebackType # noqa: F401
from typing import Optional, Set, Type # noqa: F401
[docs]class MailSinkGuard(object):
"""
This class is a simple context manager that stops all attached mail sinks
if the context is left.
with MaiLSinkGuard() as msg:
sink = MailSink(......)
msg.add(sink)
....use sink....
"""
def __init__(self):
# type: () -> None
self.mail_sinks = set() # type: Set[MailSink]
[docs] def add(self, sink): # type: (MailSink) -> None
self.mail_sinks.add(sink)
def __enter__(self):
# type: () -> MailSinkGuard
return self
def __exit__(self, exc_type, exc_value, etraceback):
# type: (Optional[Type[BaseException]], Optional[Exception], Optional[TracebackType]) -> None
for mail_sink in self.mail_sinks:
mail_sink.stop()
[docs]class MailSink(object):
"""
This class starts an SMTP sink on the specified address/port.
Each incoming mail will be written to a single file if target_dir is used.
To write all incoming mails into one file, use filename.
>>> ms = MailSink('127.0.0.1', 12345, target_dir='/tmp/')
>>> ms.start()
<do some stuff>
>>> ms.stop()
>>> ms = MailSink('127.0.0.1', 12345, filename='/tmp/sinkfile.eml')
>>> ms.start()
<do some stuff>
>>> ms.stop()
>>> with MailSink('127.0.0.1', 12345, filename='/tmp/sinkfile.eml') as ms:
>>> <do some stuff>
"""
def __init__(self, address, port, filename=None, target_dir=None, fqdn=None):
# type: (str, int, Optional[str], Optional[str], Optional[str]) -> None
self.address = address
self.port = port
self.filename = filename
self.target_dir = target_dir
self.process = None # type: Optional[subprocess.Popen]
self.fqdn = fqdn
def __enter__(self):
# type: () -> MailSink
self.start()
return self
def __exit__(self, exc_type, exc_value, etraceback):
# type: (Optional[Type[BaseException]], Optional[Exception], Optional[TracebackType]) -> None
self.stop()
[docs] def start(self):
# type: () -> None
print('*** Starting SMTPSink at %s:%s' % (self.address, self.port))
cmd = ['/usr/sbin/smtp-sink'] # use postfix' smtp-sink tool
if self.filename is not None:
cmd.extend(['-D', self.filename])
elif self.target_dir is not None:
cmd.extend(['-d', os.path.join(self.target_dir, '%Y%m%d-%H%M%S.')])
else:
cmd.extend(['-d', os.path.join('./%Y%m%d-%H%M%S.')])
if self.fqdn:
cmd.extend(['-h', self.fqdn])
if os.geteuid() == 0:
cmd.extend(['-u', pwd.getpwuid(os.getuid()).pw_name])
cmd.append('{}:{}'.format(self.address, self.port))
cmd.append('10')
print('*** {!r}'.format(cmd))
self.process = subprocess.Popen(cmd, stderr=sys.stdout, stdout=sys.stdout)
[docs] def stop(self):
# type: () -> None
if self.process is not None:
self.process.terminate()
time.sleep(1)
self.process.kill()
print('*** SMTPSink at %s:%s stopped' % (self.address, self.port))
self.process = None
if __name__ == '__main__':
# ms = MailSink('127.0.0.1', 12345, target_dir='/tmp/')
ms = MailSink('127.0.0.1', 12345, filename='/tmp/sink.eml')
print('Starting sink')
ms.start()
print('Waiting')
time.sleep(25)
print('Stopping sink')
ms.stop()
print('Waiting')
time.sleep(5)