Coder Social home page Coder Social logo

pymilter's Introduction

  • 👋 Hi, I’m @sdgathman
  • 👀 I’m interested in decentralized protocols
  • 🌱 I’m currently learning rust build system
  • 💞️ I’m looking to collaborate on Scuttlebot that isn't javascript
  • 📫 How to reach me ... mxid:@stuart:gathman.org

pymilter's People

Contributors

barrydegraaff avatar dkg avatar jaimemf avatar jayvdb avatar jcea avatar jymigeon avatar pinotree avatar rseichter avatar sdgathman avatar whyscream avatar yudai09 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pymilter's Issues

Support chgfrom in TestMilter

Yudai Kato wrote over on sf.net:

An exception occurred when I wrote some test using chgfrom.
It seems test class doen't have _ctx.
Could fix it?

essmilter: ERROR 'TestMilter' object has no attribute '_ctx'
Traceback (most recent call last):
File "/home/sci01436/ess/ESS-Modules/ess_milter/ess_milter/essmilter.py", line 36, in wrapper
return handler(self, args, *kwargs)
File "/home/sci01436/ess/ESS-Modules/ess_milter/ess_milter/essmilter.py", line 192, in eom
if self.chgfrom_repica() is False:
File "/home/sci01436/ess/ESS-Modules/ess_milter/ess_milter/essmilter.py", line 292, in chgfrom_repica
self.chgfrom(self.ENVFROM_FOR_REPICA)
File "build/bdist.linux-x86_64/egg/Milter/init.py", line 551, in chgfrom
return self._ctx.chgfrom(sender,params)

StringIO and BytesIO with pymilter

In the MilterBase class the body function receives the content (as string?) from the milter interface. But in py3 the StringIO/BytesIO pops up. My fist assumption was I've to switch from the "old" StringIO to BytesIO - but the milter interfaces provides strings. So I switched back to StringIO. But then I receive a TypeError: string argument expected, got 'bytes' in the body function if I send a mail with an attachment.

So in my opinion I must decode/encode the string/bytes. But where and how?

Code (same as your milter-template.py):

     def envform (self, mailfrom, *str):
         [....]
         self.messageToParse = io.StringIO()
[...]
    def body(self, chunk):
	self.messageToParse.write(chunk)
	return Milter.CONTINUE

Running Python version 3.6.8

compiling fails with python3.6 and python3.7

Is there a patch somewhere I need to apply? Here's the error I get:

x86_64-linux-gnu-gcc -pthread -DNDEBUG -g -fwrapv -O2 -Wall -g -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -fPIC -DMAX_ML_REPLY=32 -I/usr/include/python3.6m -c miltermodule.c -o build/temp.linux-x86_64-3.6/miltermodule.o
miltermodule.c:346:14: error: expected ';' before 'struct'
staticforward struct smfiDesc description; /* forward declaration */
^~~~~~~
;
miltermodule.c:358:1: error: unknown type name 'staticforward'; did you mean 'static_assert'?
staticforward PyTypeObject milter_ContextType;
^~~~~~~~~~~~~
static_assert
miltermodule.c:358:28: error: expected '=', ',', ';', 'asm' or 'attribute' before 'milter_ContextType'
staticforward PyTypeObject milter_ContextType;
^~~~~~~~~~~~~~~~~~
In file included from /usr/include/python3.6m/Python.h:81,
from miltermodule.c:259:
miltermodule.c: In function '_get_context':
miltermodule.c:383:47: error: 'milter_ContextType' undeclared (first use in this function); did you mean 'milter_ContextObject'?
self = PyObject_New(milter_ContextObject,&milter_ContextType);
^~~~~~~~~~~~~~~~~~
/usr/include/python3.6m/objimpl.h:137:42: note: in definition of macro 'PyObject_New'
( (type *) _PyObject_New(typeobj) )
^~~~~~~
miltermodule.c:383:47: note: each undeclared identifier is reported only once for each function it appears in
self = PyObject_New(milter_ContextObject,&milter_ContextType);
^~~~~~~~~~~~~~~~~~
/usr/include/python3.6m/objimpl.h:137:42: note: in definition of macro 'PyObject_New'
( (type *) _PyObject_New(typeobj) )
^~~~~~~
miltermodule.c: In function '_find_context':
miltermodule.c:410:22: error: 'milter_ContextType' undeclared (first use in this function); did you mean 'milter_ContextObject'?
if (c->ob_type == &milter_ContextType) {
^~~~~~~~~~~~~~~~~~
milter_ContextObject
miltermodule.c: In function '_generic_wrapper':
miltermodule.c:703:8: warning: implicit declaration of function 'PyInt_Check'; did you mean 'PySet_Check'? [-Wimplicit-function-declaration]
if (!PyInt_Check(result)) {
^~~~~~~~~~~
PySet_Check
miltermodule.c:718:12: warning: implicit declaration of function 'PyInt_AS_LONG'; did you mean 'PyLong_AS_LONG'? [-Wimplicit-function-declaration]
retval = PyInt_AS_LONG(result);
^~~~~~~~~~~~~
PyLong_AS_LONG
miltermodule.c: In function 'makeipaddr':
miltermodule.c:735:9: warning: implicit declaration of function 'PyString_FromString'; did you mean 'PyLong_FromString'? [-Wimplicit-function-declaration]
return PyString_FromString(buf);
^~~~~~~~~~~~~~~~~~~
PyLong_FromString
miltermodule.c:735:9: warning: returning 'int' from a function with return type 'PyObject *' {aka 'struct _object *'} makes pointer from integer without a cast [-Wint-conversion]
return PyString_FromString(buf);
^~~~~~~~~~~~~~~~~~~~~~~~
miltermodule.c: In function 'makeip6addr':
miltermodule.c:743:16: warning: returning 'int' from a function with return type 'PyObject *' {aka 'struct _object *'} makes pointer from integer without a cast [-Wint-conversion]
if (s) return PyString_FromString(s);
^~~~~~~~~~~~~~~~~~~~~~
miltermodule.c:744:9: warning: returning 'int' from a function with return type 'PyObject *' {aka 'struct _object *'} makes pointer from integer without a cast [-Wint-conversion]
return PyString_FromString("inet6:unknown");
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
miltermodule.c: In function 'generic_env_wrapper':
miltermodule.c:835:20: warning: implicit declaration of function 'PyString_FromStringAndSize'; did you mean 'PyBytes_FromStringAndSize'? [-Wimplicit-function-declaration]
PyObject *o = PyString_FromStringAndSize(argv[i], strlen(argv[i]));
^~~~~~~~~~~~~~~~~~~~~~~~~~
PyBytes_FromStringAndSize
miltermodule.c:835:20: warning: initialization of 'PyObject *' {aka 'struct _object *'} from 'int' makes pointer from integer without a cast [-Wint-conversion]
miltermodule.c: In function 'milter_wrap_negotiate':
miltermodule.c:966:10: warning: implicit declaration of function 'PyInt_AsUnsignedLongMask'; did you mean 'PyLong_AsUnsignedLongMask'? [-Wimplicit-function-declaration]
? PyInt_AsUnsignedLongMask(PyList_GET_ITEM(optlist,i))
^~~~~~~~~~~~~~~~~~~~~~~~
PyLong_AsUnsignedLongMask
miltermodule.c: In function 'milter_Context_getattr':
miltermodule.c:1556:10: warning: implicit declaration of function 'Py_FindMethod'; did you mean 'Py_tp_methods'? [-Wimplicit-function-declaration]
return Py_FindMethod(context_methods, self, name);
^~~~~~~~~~~~~
Py_tp_methods
miltermodule.c:1556:10: warning: returning 'int' from a function with return type 'PyObject *' {aka 'struct _object '} makes pointer from integer without a cast [-Wint-conversion]
return Py_FindMethod(context_methods, self, name);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
miltermodule.c: At top level:
miltermodule.c:1559:24: error: static declaration of 'description' follows non-static declaration
static struct smfiDesc description = { /
Set some reasonable defaults /
^~~~~~~~~~~
miltermodule.c:346:31: note: previous declaration of 'description' was here
staticforward struct smfiDesc description; /
forward declaration */
^~~~~~~~~~~
miltermodule.c:1606:42: warning: missing braces around initializer [-Wmissing-braces]
static PyTypeObject milter_ContextType = {
^
miltermodule.c:1609:3: warning: initialization of 'long int' from 'char ' makes integer from pointer without a cast [-Wint-conversion]
"milterContext",
^~~~~~~~~~~~~~~
miltermodule.c:1609:3: note: (near initialization for 'milter_ContextType.tp_basicsize')
miltermodule.c:1612:9: warning: initialization of 'int (
)(PyObject *, FILE , int)' {aka 'int ()(struct _object *, struct _IO_FILE , int)'} from incompatible pointer type 'void ()(PyObject )' {aka 'void ()(struct _object )'} [-Wincompatible-pointer-types]
milter_Context_dealloc, /
tp_dealloc /
^~~~~~~~~~~~~~~~~~~~~~
miltermodule.c:1612:9: note: (near initialization for 'milter_ContextType.tp_print')
miltermodule.c:1614:9: warning: initialization of 'int (
)(PyObject *, char *, PyObject )' {aka 'int ()(struct _object *, char *, struct _object )'} from incompatible pointer type 'PyObject * ()(PyObject *, char )' {aka 'struct _object * ()(struct _object *, char )'} [-Wincompatible-pointer-types]
milter_Context_getattr, /
tp_getattr */
^~~~~~~~~~~~~~~~~~~~~~
miltermodule.c:1614:9: note: (near initialization for 'milter_ContextType.tp_setattr')
In file included from /usr/include/python3.6m/pytime.h:6,
from /usr/include/python3.6m/Python.h:77,
from miltermodule.c:259:
/usr/include/python3.6m/object.h:659:29: warning: initialization of 'const char ' from 'long unsigned int' makes pointer from integer without a cast [-Wint-conversion]
#define Py_TPFLAGS_DEFAULT (
^
miltermodule.c:1627:9: note: in expansion of macro 'Py_TPFLAGS_DEFAULT'
Py_TPFLAGS_DEFAULT, /
tp_flags /
^~~~~~~~~~~~~~~~~~
/usr/include/python3.6m/object.h:659:29: note: (near initialization for 'milter_ContextType.tp_doc')
#define Py_TPFLAGS_DEFAULT (
^
miltermodule.c:1627:9: note: in expansion of macro 'Py_TPFLAGS_DEFAULT'
Py_TPFLAGS_DEFAULT, /
tp_flags */
^~~~~~~~~~~~~~~~~~
miltermodule.c:1606:42: warning: missing braces around initializer [-Wmissing-braces]
static PyTypeObject milter_ContextType = {
^
miltermodule.c: In function 'setitem':
miltermodule.c:1637:17: warning: implicit declaration of function 'PyInt_FromLong'; did you mean 'PyLong_FromLong'? [-Wimplicit-function-declaration]
PyObject *v = PyInt_FromLong(val);
^~~~~~~~~~~~~~
PyLong_FromLong
miltermodule.c:1637:17: warning: initialization of 'PyObject *' {aka 'struct _object *'} from 'int' makes pointer from integer without a cast [-Wint-conversion]
miltermodule.c: In function 'initmilter':
miltermodule.c:1646:8: warning: implicit declaration of function 'Py_InitModule4'; did you mean 'Py_Initialize'? [-Wimplicit-function-declaration]
m = Py_InitModule4("milter", milter_methods, milter_documentation,
^~~~~~~~~~~~~~
Py_Initialize
miltermodule.c:1646:6: warning: assignment to 'PyObject *' {aka 'struct _object '} from 'int' makes pointer from integer without a cast [-Wint-conversion]
m = Py_InitModule4("milter", milter_methods, milter_documentation,
^
At top level:
miltermodule.c:1606:21: warning: 'milter_ContextType' defined but not used [-Wunused-variable]
static PyTypeObject milter_ContextType = {
^~~~~~~~~~~~~~~~~~
miltermodule.c:1559:24: warning: 'description' defined but not used [-Wunused-variable]
static struct smfiDesc description = { /
Set some reasonable defaults */
^~~~~~~~~~~
error: command 'x86_64-linux-gnu-gcc' failed with exit status 1
ro

FAIL: testPolicy (testpolicy.PolicyTestCase.testPolicy)

This is not a new issue, but the test still fails on my system with 1.0.6. I have gotten as far as it's failing because of a key error (the one at the end of Milter.policy.MTAPolicy.getPolicy). I assume that there's something specific to the ancient BDB version we have in Debian due to licensing issues with newer versions, but I'm not sure. This is using bsddb3. I've attached a gzipped copy of the access.db created when I run the test. Suggestions?
access.tar.gz

MANIFEST.in updates needed

Looks like these should be removed:

reading manifest template 'MANIFEST.in'
warning: no files found matching 'milter-template.py'
warning: no files found matching 'start.sh

Unable to install

$ pip3 install pymilter
Collecting pymilter
  Using cached pymilter-1.0.5.tar.gz (1.0 MB)
  Preparing metadata (setup.py) ... done
Building wheels for collected packages: pymilter
  Building wheel for pymilter (setup.py) ... error
  ERROR: Command errored out with exit status 1:
   command: /usr/local/bin/python3 -u -c 'import io, os, sys, setuptools, tokenize; sys.argv[0] = '"'"'/usr/local/tmp/pip-install-a_x3x3fl/pymilter_fbc361fe804f4e638e421f466a547c54/setup.py'"'"'; __file__='"'"'/usr/local/tmp/pip-install-a_x3x3fl/pymilter_fbc361fe804f4e638e421f466a547c54/setup.py'"'"';f = getattr(tokenize, '"'"'open'"'"', open)(__file__) if os.path.exists(__file__) else io.StringIO('"'"'from setuptools import setup; setup()'"'"');code = f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' bdist_wheel -d /usr/local/tmp/pip-wheel-m3n_jb9f
       cwd: /usr/local/tmp/pip-install-a_x3x3fl/pymilter_fbc361fe804f4e638e421f466a547c54/
  Complete output (32 lines):
  running bdist_wheel
  running build
  running build_py
  creating build
  creating build/lib.linux-x86_64-cpython-310
  copying mime.py -> build/lib.linux-x86_64-cpython-310
  creating build/lib.linux-x86_64-cpython-310/Milter
  copying Milter/testctx.py -> build/lib.linux-x86_64-cpython-310/Milter
  copying Milter/config.py -> build/lib.linux-x86_64-cpython-310/Milter
  copying Milter/unsign.py -> build/lib.linux-x86_64-cpython-310/Milter
  copying Milter/plock.py -> build/lib.linux-x86_64-cpython-310/Milter
  copying Milter/dns.py -> build/lib.linux-x86_64-cpython-310/Milter
  copying Milter/greysql.py -> build/lib.linux-x86_64-cpython-310/Milter
  copying Milter/sgmllib.py -> build/lib.linux-x86_64-cpython-310/Milter
  copying Milter/pyip6.py -> build/lib.linux-x86_64-cpython-310/Milter
  copying Milter/policy.py -> build/lib.linux-x86_64-cpython-310/Milter
  copying Milter/test.py -> build/lib.linux-x86_64-cpython-310/Milter
  copying Milter/dsn.py -> build/lib.linux-x86_64-cpython-310/Milter
  copying Milter/dynip.py -> build/lib.linux-x86_64-cpython-310/Milter
  copying Milter/utils.py -> build/lib.linux-x86_64-cpython-310/Milter
  copying Milter/__init__.py -> build/lib.linux-x86_64-cpython-310/Milter
  copying Milter/greylist.py -> build/lib.linux-x86_64-cpython-310/Milter
  copying Milter/cache.py -> build/lib.linux-x86_64-cpython-310/Milter
  running build_ext
  building 'milter' extension
  creating build/temp.linux-x86_64-cpython-310
  x86_64-cros-linux-gnu-gcc -pthread -Wno-unused-result -Wsign-compare -DNDEBUG -g -fwrapv -O3 -Wall -O2 -pipe -ffat-lto-objects -fPIC -fuse-ld=mold -flto -I/usr/local/include/ncursesw -march=x86-64 -march=x86-64 -fPIC -DMAX_ML_REPLY=32 -I/usr/local/include/python3.10 -c miltermodule.c -o build/temp.linux-x86_64-cpython-310/miltermodule.o -Werror=implicit-function-declaration
  miltermodule.c:50:10: fatal error: libmilter/mfapi.h: No such file or directory
     50 | #include <libmilter/mfapi.h>    // libmilter API
        |          ^~~~~~~~~~~~~~~~~~~
  compilation terminated.
  error: command '/usr/local/bin/x86_64-cros-linux-gnu-gcc' failed with exit code 1
  ----------------------------------------
  ERROR: Failed building wheel for pymilter

What dependency is missing and shouldn't pip3 resolve anything missing?

Instance destruction postponed

Hi,

I added a __del__(self) method to my milter class to log a message when an instance is destroyed, and I noticed that if libmilter triggers a warning, like
milter claimed not to reply in state 7 but did anyway 4
or
st_optionneg[34386130944]: xxfi_negotiate returned 1 (protocol options=0x1fffff, actions=0x1ff)
the instance is not destroyed until another instance triggers a libmilter warning.
I was wondering if this could pose a problem on a server that's busier than mine, where milter instances could 'overlap' (to me it looks like a variable reference that is not released, and can only be bound to a single instance at a time).

And I have a question that is somewhat related.
The first warning mentioned above is probably triggered by return Milter.CONTINUE in combination with the @Milter.noreply decorator. Is there a way to find out whether noreply negotiation succeeded, so that I can make the CONTINUE conditional?

Thanks in advance,
Rob

setUp method in testPolicy test case doesn't catch pipe errors

I run into the following test failure:

======================================================================
ERROR: testPolicy (testpolicy.PolicyTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/var/tmp/portage/dev-python/pymilter-1.0.5/work/pymilter-pymilter-1.0.5/testpolicy.py", line 26, in testPolicy
    with MTAPolicy('[email protected]',conf=self.config) as p:
  File "/var/tmp/portage/dev-python/pymilter-1.0.5/work/pymilter-pymilter-1.0.5/Milter/policy.py", line 43, in __enter__
    self.acf = dbmopen(self.access_file,'r')
  File "/var/tmp/portage/dev-python/pymilter-1.0.5/work/pymilter-pymilter-1.0.5/Milter/policy.py", line 17, in dbmopen
    f.open(fname,mode)
  File "/var/tmp/portage/dev-python/pymilter-1.0.5/work/pymilter-pymilter-1.0.5/Milter/policy.py", line 8, in open
    self.f.open(fname,flags=flags)
bsddb3.db.DBNoSuchFileError: (2, 'No such file or directory')                                                           

That's because I had no makemap command available on the box where I run this test. I think

pymilter/testpolicy.py

Lines 19 to 21 in 7deec90

cmd = 'tr : ! <test/access | makemap hash test/access.db'
if os.system(cmd):
print('failed!')
is invalid because it won't catch pipe errors.

Back out docs dir commits

I tried out github pages for hosting documentation, adding a docs dir. I hate it, since the docs dir is all generated. I'd like to "back out" the commits that added the docs dir. I don't even want it in the history. But I need to study up on git and practice on a clone ...

Since the pymilter docs are mostly generated (DoxyGen), I think I should create a separate repo for github pages. Or use another documentation host. I've registered pymilter.org.

Additional deprecation warnings with python3.9 and 3.10

It might be nice if these could be cleaned up for the release so it's more future proof:

creating build/temp.linux-x86_64-3.10
x86_64-linux-gnu-gcc -pthread -Wno-unused-result -Wsign-compare -DNDEBUG -g -fwrapv -O2 -Wall -g -fstack-protector-strong -Wformat -Werror=format-security -g -fwrapv -O2 -g -O2 -ffile-prefix-map=/build/pymilter-1.0.4=. -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -fPIC -DMAX_ML_REPLY=32 -I/usr/include/python3.10 -c miltermodule.c -o build/temp.linux-x86_64-3.10/miltermodule.o -Werror=implicit-function-declaration
miltermodule.c: In function '_generic_wrapper':
miltermodule.c:494:3: warning: 'PyEval_CallObjectWithKeywords' is deprecated [-Wdeprecated-declarations]
494 | result = PyEval_CallObject(cb, arglist);
| ^~~~~~
In file included from /usr/include/python3.10/Python.h:131,
from miltermodule.c:49:
/usr/include/python3.10/ceval.h:17:43: note: declared here
17 | Py_DEPRECATED(3.9) PyAPI_FUNC(PyObject *) PyEval_CallObjectWithKeywords(
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
miltermodule.c: In function 'milter_main':
miltermodule.c:902:3: warning: 'PyEval_InitThreads' is deprecated [-Wdeprecated-declarations]
902 | PyEval_InitThreads();
| ^~~~~~~~~~~~~~~~~~
In file included from /usr/include/python3.10/Python.h:131,
from miltermodule.c:49:
/usr/include/python3.10/ceval.h:122:37: note: declared here
122 | Py_DEPRECATED(3.9) PyAPI_FUNC(void) PyEval_InitThreads(void);
| ^~~~~~~~~~~~~~~~~~

Bug. Typo in setsymlist.

File Milter/__init__.py:462
It is
return self._ctx.setsmlist(stage,' '.join(a))
Should be
return self._ctx.setsymlist(stage,' '.join(a))

Python 3 email package binary file handling is inconsistent

Once again, we are back to python2.2 levels of bugginess in the email package for python3. Here is a basic test that needs to work:

import email

with open('test/zip1','r') as fp:
  msg = email.message_from_file(fp)

Apparently all the test cases I provided for python2.2 with Evil™ emails have been dropped.

We'll have to debug the email package in python3, then dynamically patch it like we had to for 2.2 and 2.3.

TypeError: 'bytes' object is not callable

for some of the emails i get below error

Traceback (most recent call last):
File "/usr/local/lib/python3.8/dist-packages/pymilter-1.0.5-py3.8-linux-x86_64.egg/Milter/init.py", line 854, in
milter.set_body_callback(lambda ctx,chunk: ctx.getpriv().body(chunk))
TypeError: 'bytes' object is not callable

In Python 3.10, PY_SSIZE_T_CLEAN must be defined before including Python.h

Issue was reported against dkimpy-milter, but I think this is in pymilter:

2021-11-02T15:56:39.946644-04:00 mx dkimpy-milter[30551]: SystemError: PY_SSIZE_T_CLEAN macro must be defined for '#' formats
2021-11-02T15:56:39.946668-04:00 mx dkimpy-milter[30551]: SystemError: PY_SSIZE_T_CLEAN macro must be defined for '#' formats
2021-11-02T15:56:39.946688-04:00 mx dkimpy-milter[30551]: dkimpy-filter: milter claimed not to reply in state 9 but did anyway 4

noting

Python 3.10: SystemError: PY_SSIZE_T_CLEAN macro must be defined for '#' formats
https://gitlab.gnome.org/GNOME/libxml2/-/issues/203

Parsing arguments and building values
https://docs.python.org/3/c-api/arg.html
"For all # variants of formats (s#, y#, etc.), the macro PY_SSIZE_T_CLEAN must be defined before including Python.h. On Python 3.9 and older, the type of the length argument is Py_ssize_t if the PY_SSIZE_T_CLEAN macro is defined, or int otherwise."

See https://bugs.launchpad.net/dkimpy-milter/+bug/1949520 for details.

Don't put sgmllib back in public namespace

Since sgmllib was removed in Py3K, it would be better not to add it back as an external module. If you move it from the top level directory into the Milter sub-directory and then apply the attached patch, the public sgmllib will be used for python2 and the internal one will be used for python3.

str vs bytes decisions

It is fairly easy to chose between str and bytes in the C API, it is typically choosing s or y in the format strings for PyArg_Parse and Py_BuildValue. One exception is that there is no equivalent of z (allow None and convert to NULL) for y. This prevents simply making everything bytes, even though the C side does everything in 8-bits.

Obviously, body and replacebody are bytes. Pathname (from connect callback for unix socket) is recommended by C-API docs to be str, converted by a standard pathname converter (which handles unix vs windows, etc).

The header and addheader I made bytes, but then chgheader has to deal with passing None, so I can't simply use the y format, and making chgheader str while the other two are bytes would be inconsistent.

memory leak storing message on self.fp

Hi,

I use the milter-template.py to process messages and sign messages with dkim. I can store the message on memory, or disk or wherever using the "self.fp" and it works nice, using string or bytes.
The problem I'm having is that there seems to be a memory leak when doing "self.ftp.write(chunk)" - storing the body part in "self.fp" in the "body" function. Memory grows progressively while the milter processes emails messages.
If I comment "self.ftp.write(chunk)" in body function, the memory usage stays stable.

I've tryed to "del" the variable, explicit close or flush the file descriptor, saving in disk, variables, using garbage collector, but nothing seems to work. I need the "body" part to sign with DKIM.

any ideas?

mime.py

News file for 0.8.0 says

Move /mime/ and dynip to Milter subpackage

dynip was moved but not mime.py

Should mime.py be moved into Milter/mime.py?

Its ending up in /usr/lib/python3.11/site-packages/mime.py which feels wrong.

Doxyfile updates needed

From my Debian build log:

doxygen
warning: Tag 'SYMBOL_CACHE_SIZE' at line 289 of file 'Doxyfile' has become obsolete.
To avoid this warning please remove this line from your configuration file or upgrade it using "doxygen -u"
warning: Tag 'SHOW_DIRECTORIES' at line 477 of file 'Doxyfile' has become obsolete.
To avoid this warning please remove this line from your configuration file or upgrade it using "doxygen -u"
warning: Tag 'COLS_IN_ALPHA_INDEX' at line 751 of file 'Doxyfile' has become obsolete.
To avoid this warning please remove this line from your configuration file or upgrade it using "doxygen -u"
warning: Tag 'HTML_ALIGN_MEMBERS' at line 811 of file 'Doxyfile' has become obsolete.
To avoid this warning please remove this line from your configuration file or upgrade it using "doxygen -u"
warning: Tag 'USE_INLINE_TREES' at line 964 of file 'Doxyfile' has become obsolete.
To avoid this warning please remove this line from your configuration file or upgrade it using "doxygen -u"
warning: Tag 'XML_SCHEMA' at line 1157 of file 'Doxyfile' has become obsolete.
To avoid this warning please remove this line from your configuration file or upgrade it using "doxygen -u"
warning: Tag 'XML_DTD' at line 1163 of file 'Doxyfile' has become obsolete.
To avoid this warning please remove this line from your configuration file or upgrade it using "doxygen -u"
warning: Tag 'PERL_PATH' at line 1328 of file 'Doxyfile' has become obsolete.
To avoid this warning please remove this line from your configuration file or upgrade it using "doxygen -u"
warning: Tag 'MSCGEN_PATH' at line 1350 of file 'Doxyfile' has become obsolete.
To avoid this warning please remove this line from your configuration file or upgrade it using "doxygen -u"
warning: doxygen no longer ships with the FreeSans font.
You may want to clear or change DOT_FONTNAME.
Otherwise you run the risk that the wrong font is being used for dot generated graphs.
Doxygen version used: 1.9.1

quarantine() not working?

Hi. I am running self.quarantine("some reason") on the eom() hook. I configured my milter like this, in postfix 3.5.24, python 3.9, pymilter 1.0.5

# postconf -n|grep milter
milter_default_action = accept
milter_protocol = 6
non_smtpd_milters = $smtpd_milters
smtpd_milters = inet:localhost:10669

If I do 'return Milter.DISCARD' it works perfectly, but if I do:

self.quarantine(reason)
return Milter.QUARANTINE

then nothing happens. Am I incorrect in calling self.quarantine() ? should I just be returning Milter.QUARANTINE?

Strange line

Hello,

I have tested a spf record and I wonder from where the line beginning with D= could be retrieve ?

The TXT records found for your domain are:
D=landerneau.bzh
v=spf1 ip4:90.102.97.217 ip4:90.63.167.244 include:bluecom.fr ~all

Checking to see if there is a valid SPF record.

Found v=spf1 record for mairie-landerneau.fr:
v=spf1 ip4:90.102.97.217 ip4:90.63.167.244 include:bluecom.fr ~all

evaluating...
Results - record processed without error.

pymilter is not detected in fuglu

i am gentoo maintainer on fuglu, while its installed fuglu says its not installed, and i dont know how to find or resolve the problem, so adding it here in hope some can help me resolve it

fuglu is in ::fidonet overlay

Include notes from smfi_setconn in setconn(...) documentation

In the libmilter documentation distributed with Sendmail (libmilter/html/smfi_setconn.html) there are the following notes:

    If possible, filters should not run as root when communicating over unix/local domain sockets.
    Unix/local sockets should have their permissions set to 0600 (read/write permission only for the socket's owner) or 0660 (read/write permission for the socket's owner and group) which is useful if the sendmail RunAsUser option is used. The permissions for a unix/local domain socket are determined as usual by umask, which should be set to 007 or 077. Note some operating systems (e.g, Solaris) don't use the permissions of the socket. On those systems, place the socket in a protected directory. 

I think it would be useful to include these in the documentation for the equivalent pymilter documentation, in particular I just had to explain how setting umask affects Unix domain sockets to a user of dkimpy-milter and it would have been easier to point to the pymilter documentation if the information was there.

BytesIO exception thrown on run with Python3.6-3.7

I have a milter with which I've been working with Python 2.7 for the last few months. It's very similar in structure to the example code given in this repository, and I've had no issues with it thus far. Having seen the new versions which has compatibility with Python 3, I've upgraded the milter package along with my code. I've read the issues in relation to the new use of BytesIO where StringIO previously was sufficient, and I believe I've updated all of my own code as necessary. However, upon running my milter I receive the following error, which appears according to the stack trace to be pymilter related:

Traceback (most recent call last):
File "/home/joshua/.virtualenvs/y4project36/lib/python3.6/site-packages/Milter/__init__.py", line 771, in <lambda> milter.set_body_callback(lambda ctx,chunk: ctx.getpriv().body(chunk)) TypeError: '_io.BytesIO' object is not callable

I'm wondering if there's something I've missed, or if this is a legitimate issue with the latest release? Thanks!

implicit declaration of function 'inet_ntop' on BSD/Hurd

x86_64-kfreebsd-gnu-gcc -pthread -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fno-strict-aliasing -g -O2 -fdebug-prefix-map=/<>=. -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -fPIC -DMAX_ML_REPLY=32 -I/usr/include/python2.7 -c miltermodule.c -o build/temp.gnukfreebsd-10.3-0-amd64-x86_64-2.7/miltermodule.o
miltermodule.c: In function 'makeip6addr':
miltermodule.c:742:18: warning: implicit declaration of function 'inet_ntop' [-Wimplicit-function-declaration]
const char *s = inet_ntop(AF_INET6, &addr->sin6_addr, buf, sizeof buf);
^~~~~~~~~
miltermodule.c:742:18: warning: initialization of 'const char *' from 'int' makes pointer from integer without a cast [-Wint-conversion]
x86_64-kfreebsd-gnu-gcc -pthread -shared -Wl,-O1 -Wl,-Bsymbolic-functions -Wl,-z,relro -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -Wdate-time -D_FORTIFY_SOURCE=2 -g -fdebug-prefix-map=/build/python2.7-prcMRy/python2.7-2.7.15=. -fstack-protector-strong -Wformat -Werror=format-security -Wl,-z,relro -Wl,-z,now -g -O2 -fdebug-prefix-map=/<>=. -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 build/temp.gnukfreebsd-10.3-0-amd64-x86_64-2.7/miltermodule.o -L/usr/lib/libmilter -lmilter -o build/lib.gnukfreebsd-10.3-0-amd64-x86_64-2.7/milter.so

C API changes in Python 3

There were several C API changes in Python 3, as mentioned at Supporting Python 3: An in-depth guide. When I try to build pymilter in Fedora 24, there are following errors reported from C compiler related to Python 3 version:

$ mock -r fedora-24-x86_64 rebuild python-pymilter-1.0-5.fc24.src.rpm
INFO: mock.py version 1.2.21 starting (python version = 3.5.1)...
Start: init plugins
...
creating build/temp.linux-x86_64-3.5
gcc -pthread -DDYNAMIC_ANNOTATIONS_ENABLED=1 -DNDEBUG -O2 -g -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -m64 -mtune=generic -D_GNU_SOURCE -fPIC -fwrapv -O2 -g -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -m64 -mtune=generic -fPIC -DMAX_ML_REPLY=32 -I/usr/include/python3.5m -c miltermodule.c -o build/temp.linux-x86_64-3.5/miltermodule.o
miltermodule.c:349:15: error: expected '=', ',', ';', 'asm' or '__attribute__' before 'struct'
 staticforward struct smfiDesc description; /* forward declaration */
               ^~~~~~
miltermodule.c:361:1: error: unknown type name 'staticforward'
 staticforward PyTypeObject milter_ContextType;
 ^~~~~~~~~~~~~
miltermodule.c:361:28: error: expected '=', ',', ';', 'asm' or '__attribute__' before 'milter_ContextType'
 staticforward PyTypeObject milter_ContextType;
                            ^~~~~~~~~~~~~~~~~~
In file included from /usr/include/python3.5m/Python.h:69:0,
                 from miltermodule.c:262:
miltermodule.c: In function '_get_context':
miltermodule.c:386:47: error: 'milter_ContextType' undeclared (first use in this function)
     self = PyObject_New(milter_ContextObject,&milter_ContextType);
                                               ^
/usr/include/python3.5m/objimpl.h:133:42: note: in definition of macro 'PyObject_New'
                 ( (type *) _PyObject_New(typeobj) )
                                          ^~~~~~~
miltermodule.c:386:47: note: each undeclared identifier is reported only once for each function it appears in
     self = PyObject_New(milter_ContextObject,&milter_ContextType);
                                               ^
/usr/include/python3.5m/objimpl.h:133:42: note: in definition of macro 'PyObject_New'
                 ( (type *) _PyObject_New(typeobj) )
                                          ^~~~~~~
miltermodule.c: In function '_find_context':
miltermodule.c:413:22: error: 'milter_ContextType' undeclared (first use in this function)
   if (c->ob_type == &milter_ContextType) {
                      ^~~~~~~~~~~~~~~~~~
miltermodule.c: In function 'milter_set_flags':
miltermodule.c:470:47: error: 'description' undeclared (first use in this function)
   if (!PyArg_ParseTuple(args, "i:set_flags", &description.xxfi_flags))
                                               ^~~~~~~~~~~
miltermodule.c: In function '_report_exception':
miltermodule.c:673:4: error: 'description' undeclared (first use in this function)
    description.xxfi_name);
    ^~~~~~~~~~~
miltermodule.c: In function '_generic_wrapper':
miltermodule.c:706:8: warning: implicit declaration of function 'PyInt_Check' [-Wimplicit-function-declaration]
   if (!PyInt_Check(result)) {
        ^~~~~~~~~~~
miltermodule.c:721:12: warning: implicit declaration of function 'PyInt_AS_LONG' [-Wimplicit-function-declaration]
   retval = PyInt_AS_LONG(result);
            ^~~~~~~~~~~~~
miltermodule.c: In function 'makeipaddr':
miltermodule.c:738:9: warning: implicit declaration of function 'PyString_FromString' [-Wimplicit-function-declaration]
  return PyString_FromString(buf);
         ^~~~~~~~~~~~~~~~~~~
miltermodule.c:738:9: warning: return makes pointer from integer without a cast [-Wint-conversion]
  return PyString_FromString(buf);
         ^~~~~~~~~~~~~~~~~~~~~~~~
miltermodule.c: In function 'makeip6addr':
miltermodule.c:746:16: warning: return makes pointer from integer without a cast [-Wint-conversion]
  if (s) return PyString_FromString(s);
                ^~~~~~~~~~~~~~~~~~~~~~
miltermodule.c:747:9: warning: return makes pointer from integer without a cast [-Wint-conversion]
  return PyString_FromString("inet6:unknown");
         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
miltermodule.c: In function 'generic_env_wrapper':
miltermodule.c:838:20: warning: implicit declaration of function 'PyString_FromStringAndSize' [-Wimplicit-function-declaration]
      PyObject *o = PyString_FromStringAndSize(argv[i], strlen(argv[i]));
                    ^~~~~~~~~~~~~~~~~~~~~~~~~~
miltermodule.c:838:20: warning: initialization makes pointer from integer without a cast [-Wint-conversion]
miltermodule.c: In function 'milter_wrap_negotiate':
miltermodule.c:969:10: warning: implicit declaration of function 'PyInt_AsUnsignedLongMask' [-Wimplicit-function-declaration]
        ? PyInt_AsUnsignedLongMask(PyList_GET_ITEM(optlist,i))
          ^~~~~~~~~~~~~~~~~~~~~~~~
miltermodule.c: In function 'milter_register':
miltermodule.c:1030:5: error: 'description' undeclared (first use in this function)
    &description.xxfi_name, &cb[0],&cb[1],&cb[2]))
     ^~~~~~~~~~~
miltermodule.c: In function 'milter_Context_getattr':
miltermodule.c:1559:10: warning: implicit declaration of function 'Py_FindMethod' [-Wimplicit-function-declaration]
   return Py_FindMethod(context_methods, self, name);
          ^~~~~~~~~~~~~
miltermodule.c:1559:10: warning: return makes pointer from integer without a cast [-Wint-conversion]
   return Py_FindMethod(context_methods, self, name);
          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from /usr/include/python3.5m/pytime.h:6:0,
                 from /usr/include/python3.5m/Python.h:65,
                 from miltermodule.c:262:
miltermodule.c: At top level:
/usr/include/python3.5m/object.h:86:5: warning: missing braces around initializer [-Wmissing-braces]
     { _PyObject_EXTRA_INIT              \
     ^
miltermodule.c:1610:3: note: in expansion of macro 'PyObject_HEAD_INIT'
   PyObject_HEAD_INIT(&PyType_Type)
   ^~~~~~~~~~~~~~~~~~
/usr/include/python3.5m/object.h:86:5: note: (near initialization for 'milter_ContextType.ob_base')
     { _PyObject_EXTRA_INIT              \
     ^
miltermodule.c:1610:3: note: in expansion of macro 'PyObject_HEAD_INIT'
   PyObject_HEAD_INIT(&PyType_Type)
   ^~~~~~~~~~~~~~~~~~
miltermodule.c:1612:3: warning: initialization makes integer from pointer without a cast [-Wint-conversion]
   "milterContext",
   ^~~~~~~~~~~~~~~
miltermodule.c:1612:3: note: (near initialization for 'milter_ContextType.tp_basicsize')
miltermodule.c:1615:9: warning: initialization from incompatible pointer type [-Wincompatible-pointer-types]
         milter_Context_dealloc,            /* tp_dealloc */
         ^~~~~~~~~~~~~~~~~~~~~~
miltermodule.c:1615:9: note: (near initialization for 'milter_ContextType.tp_print')
miltermodule.c:1617:9: warning: initialization from incompatible pointer type [-Wincompatible-pointer-types]
         milter_Context_getattr,           /* tp_getattr */
         ^~~~~~~~~~~~~~~~~~~~~~
miltermodule.c:1617:9: note: (near initialization for 'milter_ContextType.tp_setattr')
In file included from /usr/include/python3.5m/pytime.h:6:0,
                 from /usr/include/python3.5m/Python.h:65,
                 from miltermodule.c:262:
/usr/include/python3.5m/object.h:651:29: warning: initialization makes pointer from integer without a cast [-Wint-conversion]
 #define Py_TPFLAGS_DEFAULT  ( \
                             ^
miltermodule.c:1630:9: note: in expansion of macro 'Py_TPFLAGS_DEFAULT'
         Py_TPFLAGS_DEFAULT,                     /* tp_flags */
         ^~~~~~~~~~~~~~~~~~
/usr/include/python3.5m/object.h:651:29: note: (near initialization for 'milter_ContextType.tp_doc')
 #define Py_TPFLAGS_DEFAULT  ( \
                             ^
miltermodule.c:1630:9: note: in expansion of macro 'Py_TPFLAGS_DEFAULT'
         Py_TPFLAGS_DEFAULT,                     /* tp_flags */
         ^~~~~~~~~~~~~~~~~~
miltermodule.c:1609:42: warning: missing braces around initializer [-Wmissing-braces]
 static PyTypeObject milter_ContextType = {
                                          ^
miltermodule.c:1609:42: note: (near initialization for 'milter_ContextType')
miltermodule.c: In function 'setitem':
miltermodule.c:1640:17: warning: implicit declaration of function 'PyInt_FromLong' [-Wimplicit-function-declaration]
   PyObject *v = PyInt_FromLong(val);
                 ^~~~~~~~~~~~~~
miltermodule.c:1640:17: warning: initialization makes pointer from integer without a cast [-Wint-conversion]
miltermodule.c: In function 'initmilter':
miltermodule.c:1649:8: warning: implicit declaration of function 'Py_InitModule4' [-Wimplicit-function-declaration]
    m = Py_InitModule4("milter", milter_methods, milter_documentation,
        ^~~~~~~~~~~~~~
miltermodule.c:1649:6: warning: assignment makes pointer from integer without a cast [-Wint-conversion]
    m = Py_InitModule4("milter", milter_methods, milter_documentation,
      ^
miltermodule.c: In function 'milter_register':
miltermodule.c:1060:1: warning: control reaches end of non-void function [-Wreturn-type]
 }
 ^
At top level:
miltermodule.c:1609:21: warning: 'milter_ContextType' defined but not used [-Wunused-variable]
 static PyTypeObject milter_ContextType = {
                     ^~~~~~~~~~~~~~~~~~
miltermodule.c:1562:24: warning: 'description' defined but not used [-Wunused-variable]
 static struct smfiDesc description = {  /* Set some reasonable defaults */
                        ^~~~~~~~~~~
error: command 'gcc' failed with exit status 1
error: Bad exit status from /var/tmp/rpm-tmp.YowpBR (%build)
    Bad exit status from /var/tmp/rpm-tmp.YowpBR (%build)


RPM build errors:
ERROR: Exception(python-pymilter-1.0-5.fc24.src.rpm) Config(fedora-24-x86_64) 1 minutes 36 seconds
INFO: Results and/or logs in: /var/lib/mock/fedora-24-x86_64/result
ERROR: Command failed. See logs for output.
 # bash --login -c /usr/bin/rpmbuild -bb --target x86_64 --nodeps /builddir/build/SPECS/python-pymilter.spec

coding style

It's a matter of personal preference, but I thinks coding style, e.g. PEP8, should be applied.

Not setting client_* symbols when using Postfix

Hello,

I'm currently testing pymilter with Postfix and have noticed that the client_* symbols are not being set:

self.getsymval('{client_addr}') None
self.getsymval('{client_name}') None
self.getsymval('{client_port}') None

Postfix states that the symbols are set:

http://www.postfix.org/MILTER_README.html

Is this something that's introduced by pymilter or do I need to dig into postfix/libmilter? Thanks.

implicit declaration of function 'inet_ntop' (macOS 10.14)

I'm trying to use pymilter on macOS 10.14.4 (Mojave). Both libmilter and Python 3.7 have been installed with MacPorts, and I use a venv.

> env C_INCLUDE_PATH=/opt/local/include pip install pymilter

This generates the following output:

Collecting pymilter
  Using cached https://files.pythonhosted.org/packages/c8/02/a9672a027c20fa7fadc0ba653e3777aed7e2cc9fbf8533aa7a57637d65c6/pymilter-1.0.3.tar.gz
Installing collected packages: pymilter
  Running setup.py install for pymilter ... error
    Complete output from command /Users/foo/bar/venv/bin/python -u -c "import setuptools, tokenize;__file__='/private/var/folders/m_/w5lk3r_1495dhnl4l0s96pr00000gn/T/pip-install-t80rjzho/pymilter/setup.py';f=getattr(tokenize, 'open', open)(__file__);code=f.read().replace('\r\n', '\n');f.close();exec(compile(code, __file__, 'exec'))" install --record /private/var/folders/m_/w5lk3r_1495dhnl4l0s96pr00000gn/T/pip-record-xrnw52od/install-record.txt --single-version-externally-managed --compile --install-headers /Users/foo/bar/venv/include/site/python3.7/pymilter:
    running install
    running build
    running build_py
    creating build
    creating build/lib.macosx-10.14-x86_64-3.7
    copying mime.py -> build/lib.macosx-10.14-x86_64-3.7
    creating build/lib.macosx-10.14-x86_64-3.7/Milter
    copying Milter/config.py -> build/lib.macosx-10.14-x86_64-3.7/Milter
    copying Milter/greysql.py -> build/lib.macosx-10.14-x86_64-3.7/Milter
    copying Milter/dns.py -> build/lib.macosx-10.14-x86_64-3.7/Milter
    copying Milter/pyip6.py -> build/lib.macosx-10.14-x86_64-3.7/Milter
    copying Milter/cache.py -> build/lib.macosx-10.14-x86_64-3.7/Milter
    copying Milter/__init__.py -> build/lib.macosx-10.14-x86_64-3.7/Milter
    copying Milter/sgmllib.py -> build/lib.macosx-10.14-x86_64-3.7/Milter
    copying Milter/unsign.py -> build/lib.macosx-10.14-x86_64-3.7/Milter
    copying Milter/dynip.py -> build/lib.macosx-10.14-x86_64-3.7/Milter
    copying Milter/test.py -> build/lib.macosx-10.14-x86_64-3.7/Milter
    copying Milter/testctx.py -> build/lib.macosx-10.14-x86_64-3.7/Milter
    copying Milter/utils.py -> build/lib.macosx-10.14-x86_64-3.7/Milter
    copying Milter/plock.py -> build/lib.macosx-10.14-x86_64-3.7/Milter
    copying Milter/dsn.py -> build/lib.macosx-10.14-x86_64-3.7/Milter
    copying Milter/greylist.py -> build/lib.macosx-10.14-x86_64-3.7/Milter
    running build_ext
    building 'milter' extension
    creating build/temp.macosx-10.14-x86_64-3.7
    /usr/bin/clang -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -pipe -Os -isysroot/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk -DMAX_ML_REPLY=32 -I/Users/foo/bar/venv/include -I/opt/local/Library/Frameworks/Python.framework/Versions/3.7/include/python3.7m -c miltermodule.c -o build/temp.macosx-10.14-x86_64-3.7/miltermodule.o -Werror=implicit-function-declaration
    miltermodule.c:551:18: error: implicit declaration of function 'inet_ntop' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
            const char *s = inet_ntop(AF_INET6, &addr->sin6_addr, buf, sizeof buf);
                            ^
    miltermodule.c:551:14: warning: incompatible integer to pointer conversion initializing 'const char *' with an expression of type 'int' [-Wint-conversion]
            const char *s = inet_ntop(AF_INET6, &addr->sin6_addr, buf, sizeof buf);
                        ^   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    1 warning and 1 error generated.
    error: command '/usr/bin/clang' failed with exit status 1
    
    ----------------------------------------
Command "/Users/foo/bar/venv/bin/python -u -c "import setuptools, tokenize;__file__='/private/var/folders/m_/w5lk3r_1495dhnl4l0s96pr00000gn/T/pip-install-t80rjzho/pymilter/setup.py';f=getattr(tokenize, 'open', open)(__file__);code=f.read().replace('\r\n', '\n');f.close();exec(compile(code, __file__, 'exec'))" install --record /private/var/folders/m_/w5lk3r_1495dhnl4l0s96pr00000gn/T/pip-record-xrnw52od/install-record.txt --single-version-externally-managed --compile --install-headers /Users/foo/bar/venv/include/site/python3.7/pymilter" failed with error code 1 in /private/var/folders/m_/w5lk3r_1495dhnl4l0s96pr00000gn/T/pip-install-t80rjzho/pymilter/

I have seen #23 and I thought I'd report the issue for macOS.

Test failures with master

When I run the test suite with master, I get the following failures. Are any of these real? I think I'm down to pretty much the same failures in my local python3 attempt and I'd like to know how much of this needs fixing too.

Your branch is up-to-date with 'origin/master'.
~/devel/pymilter/pymilter$ python test.py

.................FE..F..

ERROR: testParseHeader (testutils.AddrCacheTestCase)

Traceback (most recent call last):
File "/~/devel/pymilter/pymilter/testutils.py", line 14, in tearDown
os.remove(self.fname)
OSError: [Errno 2] No such file or directory: 'test.dat'

FAIL: testParseHeader (testutils.AddrCacheTestCase)

Traceback (most recent call last):
File "~/devel/pymilter/pymilter/testutils.py", line 44, in testParseHeader
self.assertEqual(s,'Last Few Coldplay Album Artworks Available\x00')
AssertionError: '=?UTF-8?B?TGFzdCBGZXcgQ29sZHBsYXkgQWxidW0gQXJ0d29ya3MgQXZhaWxhYmxlAA?=' != 'Last Few Coldplay Album Artworks Available\x00'

FAIL: parseaddr (Milter.utils)

Doctest: Milter.utils.parseaddr

Traceback (most recent call last):
File "/usr/lib/python2.7/doctest.py", line 2226, in runTest
raise self.failureException(self.format_failure(new.getvalue()))
AssertionError: Failed doctest test for Milter.utils.parseaddr
File "~/devel/pymilter/pymilter/Milter/utils.py", line 126, in parseaddr


File "/home/kitterma/devel/pymilter/pymilter/Milter/utils.py", line 137, in Milter.utils.parseaddr
Failed example:
parseaddr('Real Name ((comment)) [email protected]')
Expected:
('Real Name', '[email protected]')
Got:

('Real Name (comment)', '[email protected]')

File "~/devel/pymilter/pymilter/Milter/utils.py", line 139, in Milter.utils.parseaddr
Failed example:
parseaddr('a(WRONG)@b')
Expected:
('WRONG', 'a@b')
Got:
('WRONG WRONG', 'a@b')


Ran 23 tests in 0.288s

FAILED (failures=2, errors=1)

python 3.11 compatibility in setup - deprecation warning

Running:

python setup.py install

Gives this warning:

/usr/lib/python3.11/site-packages/setuptools/command/install.py:34: SetuptoolsDeprecationWarning: setup.py install is deprecated. Use build and pip and other standards-based tools.

doco nit for miltermodule.c

static const char milter_set_flags__doc__[] =
"set_flags(int) -> None\n
Set flags for filter capabilities; OR of one or more of:\n
ADDHDRS - filter may add headers\n
CHGBODY - filter may replace body\n
CHGFROM - filter may replace body\n
ADDRCPT - filter may add recipients\n
DELRCPT - filter may delete recipients\n
CHGHDRS - filter may change/delete headers";

pretty sure the CHGFROM description is just a copy&paste-o.
perhaps "filter may change the envelope sender"?

pymilter reports TypeError: 'str' object is not callable when sending multiple MAIL FROM in single session

pymilter 1.0.3 is reporting a traceback when a second mail is send in the same session.

e.g. remote server does EHLO, MAIL FROM, RCPT TO, DATA, RSET, MAIL FROM at which point the traceback is thrown:

Traceback (most recent call last):
  File "/usr/lib64/python2.7/site-packages/Milter/__init__.py", line 767, in <lambda>
    milter.set_envfrom_callback(lambda ctx,*str: ctx.getpriv().envfrom(*str))
TypeError: 'str' object is not callable

A super-simple milter that is reproducing the error could look like this:

#!/usr/bin/python

from multiprocessing import Process
import Milter
from Milter.utils import parse_addr

class crashMilter(Milter.Base):
  def __init__(self):
    self.id = Milter.uniqueID()
    self.queue_id = None

  def envfrom(self, envfrom, *str):
    self.envfrom = envfrom
    return Milter.CONTINUE

def main():
  job = Process()
  job.start()
  Milter.factory = crashMilter
  timeout = 60
  Milter.runmilter('crashMilter', 'inet:10000@localhost', timeout)
  job.join()

if __name__ == "__main__":
  main()

This behavior was first noticed running a milter written using pymilter against a copy of life smtp traffic but a simple test case which reproduces the problem is this:

#!/usr/bin/python

import smtplib
import email.utils
import sys
import os.path

MX = 'localhost'
TO = 'root@localhost'
FROM = '[email protected]'

def get_msg():
  msg = '''Date: %s
To: %s
From: %s
Subject: test %s
Message-Id: %s
X-Mailer: %s

This is a test mailing

''' % (email.utils.formatdate(localtime=True), TO, FROM, email.utils.formatdate(localtime=True), email.utils.make_msgid(), os.path.basename(sys.argv[0]))
  return msg

server = smtplib.SMTP(MX)
server.set_debuglevel(1)
server.sendmail(FROM, TO, get_msg())
server.sendmail(FROM, TO, get_msg())
server.quit()

It is also possible to reproduce the problem without an MTA by using Perl's Net::Milter:

#!/usr/bin/perl

use Email::Date::Format qw(email_date);
use Email::MessageID;
use Email::Simple;
use File::Basename;
use Net::Milter;
use strict;
no strict 'refs';

my (@results);

my $TO = '[email protected]';
my $FROM = '[email protected]';

our $milter = new Net::Milter;

sub get_msg {
  my $msg = << 'EOF';
Date: %s
To: %s
From: %s
Subject: test %s
Message-Id: %s
X-Mailer: %s

This is a test mailing

EOF

  $msg = sprintf($msg, email_date, $TO, $FROM, email_date, Email::MessageID->new->in_brackets, basename($0));

  return $msg
}

sub pr {
    foreach (@_) {
        print "\n".'returned command : '.$$_{command}."\n";
        print 'explanation : '.$$_{explanation}."\n";
        print 'action : '.$$_{action}."\n";
        if ($$_{action} eq 'reject') {$milter->send_quit;exit;}
    }
}

sub feed_milter {
    my $email = $_[0];

    $milter->send_macros(
                     'i' => 'queueid',
                     '{mail_mailer}'   => 'local',
                     '{mail_host}'   => '',
                     '{mail_addr}'   => (split /@/, $email->header_raw('from'))[0],
                     );
    pr($milter->send_mail_from($email->header_raw('from')));
    $milter->send_macros(
                     '{rcpt_mailer}' => 'local',
                     '{rcpt_host}'   => '',
                     '{rcpt_addr}'   => (split /@/, $email->header_raw('to'))[0],
                     );
    pr($milter->send_rcpt_to(sprintf('<%s>', $email->header_raw('to'))));
    foreach ($email->headers) {
        pr($milter->send_header(lc $_, $email->header($_)));
    }
    pr($milter->send_end_headers());
    pr($milter->send_body($email->body));
    pr($milter->send_end_body());
}


# connect to the milter via tcp on port 10000
$milter->open('127.0.0.1',10000,'tcp');

my ($ret_version,$returned_actions_ref,$returned_protocol_ref) = $milter->protocol_negotiation();

my $mail_text = get_msg();
my $email = Email::Simple->new($mail_text);

$milter->send_macros(
                     j => 'localhost.localdomain',
                     _ => 'localhost [127.0.0.1]',
                     '{daemon_name}' => 'MTA',
                     '{if_name}'     => 'localhost'
                     );
pr($milter->send_connect('localhost','tcp4','12345','127.0.0.1'));
pr($milter->send_helo('localhost'));

feed_milter($email);

$mail_text = get_msg();
$email = Email::Simple->new($mail_text);
feed_milter($email);

pr($milter->send_quit());

This sends two similar mails to the milter, the second mail generating the traceback.

Make dsn.py RFC3464 compliant

Currently, dsn.py generates a text/plain message. RFC3464 wants us to use multipart/report.

Defined in RFC3461 (and described in RFC3464 and RFC3462).

Docummentation about python support

Hello,

I don't think if this can/should be handled as an issue, but I guess that it would be a nice way to document something that I think might also be a doubt for other people: what are the currently supported python versions in this project?

And about the recent releases, can I safely upgrade my python2.7 project safely? What were the main changes included in those releases? I searched for a changelog in this project but haven't found one yet.

Thanks for the help!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.