1
0
mirror of https://github.com/mail-in-a-box/mailinabox.git synced 2025-04-07 00:47:05 +00:00
mailinabox/management/reporting/capture/mail/PostfixLogParser.py
2022-09-19 14:45:11 -04:00

135 lines
4.1 KiB
Python

#####
##### This file is part of Mail-in-a-Box-LDAP which is released under the
##### terms of the GNU Affero General Public License as published by the
##### Free Software Foundation, either version 3 of the License, or (at
##### your option) any later version. See file LICENSE or go to
##### https://github.com/downtownallday/mailinabox-ldap for full license
##### details.
#####
class PostfixLogParser(object):
@staticmethod
def split_host(str):
''' split string in form HOST[IP] and return HOST and IP '''
ip_start = str.find('[')
ip_end = -1
if ip_start>=0:
ip_end = str.find(']', ip_start)
if ip_start<0 or ip_end<0:
return str, str
return str[0:ip_start], str[ip_start+1:ip_end]
@staticmethod
def strip_brackets(str, bracket_l='<', bracket_r='>'):
# strip enclosing '<>'
if len(str)>=2 and str[0]==bracket_l and str[-1]==bracket_r:
return str[1:-1]
return str
class SplitList(object):
''' split a postfix name=value list. For example:
"delay=4.7, to=<alice@post.com>, status=sent (250 2.0.0 <user@domain.tld> YB5nM1eS01+lSgAAlWWVsw Saved)"
returns: {
"delay": {
"name": "delay",
"value": "4.7"
},
"to": {
"name": "to",
"value": "alice@post.com"
},
"status": {
"name": "status",
"value": "sent",
"comment": "250 2.0.0 <user@domain.tld> YB5nM1eS01+lSgAAlWWVsw Saved"
}
}
'''
def __init__(self, str, delim=',', strip_brackets=True):
self.str = str
self.delim = delim
self.strip_brackets = True
self.pos = 0
def asDict(self):
d = {}
for pair in self:
d[pair['name']] = pair
return d
def __iter__(self):
self.pos = 0
return self
def __next__(self):
if self.pos >= len(self.str):
raise StopIteration
# name
eq = self.str.find('=', self.pos)
if eq<0:
self.pos = len(self.str)
raise StopIteration
name = self.str[self.pos:eq].strip()
# value and comment
self.pos = eq+1
value = []
comment = []
while self.pos < len(self.str):
c = self.str[self.pos]
self.pos += 1
if c=='<':
idx = self.str.find('>', self.pos)
if idx>=0:
value.append(self.str[self.pos-1:idx+1])
self.pos = idx+1
continue
if c=='(':
# parens may be nested...
open_count = 1
begin = self.pos
while self.pos < len(self.str) and open_count>0:
c = self.str[self.pos]
self.pos += 1
if c=='(':
open_count += 1
elif c==')':
open_count -= 1
if open_count == 0:
comment.append(self.str[begin:self.pos-1])
else:
comment.append(self.str[begin:len(self.str)])
continue
if c==self.delim:
break
begin = self.pos-1
while self.pos < len(self.str):
lookahead = self.str[self.pos]
if lookahead in [self.delim,'<','(']:
break
self.pos += 1
value.append(self.str[begin:self.pos])
if self.strip_brackets and len(value)==1:
value[0] = PostfixLogParser.strip_brackets(value[0])
return {
'name': name,
'value': ''.join(value),
'comment': None if len(comment)==0 else '; '.join(comment)
}