import psycopg2
import re
import datetime
+import argparse
+
+parser = argparse.ArgumentParser(description='Process DMARC records.')
+parser.add_argument('-c', '--config', action='store',
+ default='', dest='config_file',
+ help='Path to config file')
+parser.add_argument('-t', '--test', action='store_true',
+ default=False,
+ help='Test, but do not add records to the database')
+args = parser.parse_args()
def fetch_msg(num):
return mailbox.uid('FETCH', num, '(RFC822)')[1][0][1]
def xml_of_part(part):
- with zipfile.ZipFile(io.BytesIO(part.get_payload(decode=True))) as zf:
+ try:
+ with zipfile.ZipFile(io.BytesIO(part.get_payload(decode=True))) as zf:
fn = zf.infolist()[0].filename
contents = zf.read(fn).decode('utf-8')
return xml.etree.ElementTree.fromstring(contents)
+ except zipfile.BadZipFile:
+ return None
def xml_of(message):
field_names += [field_maps[f]['pg_field_name']]
if field_maps[f]['pg_type'] == 'int':
values[field_maps[f]['pg_field_name']] = int(report.find(fp).text)
- elif field_maps[f]['pg_type'] == 'timestamp':
+ elif field_maps[f]['pg_type'] == 'timestamptz':
# values[field_maps[f]['pg_field_name']] = datetime.datetime.utcfromtimestamp(int(report.find(fp).text))
values[field_maps[f]['pg_field_name']] = \
datetime.datetime.fromtimestamp(int(report.find(fp).text),
def write_report(connection, cursor, report):
- insert_string, values = build_insert_command('reports', report)
- # print(insert_string, values)
- cursor.execute(insert_string, values)
-
- for i in range(1, len(report.findall('./record'))+1):
- field_names = []
- cursor.execute('select id, report_metadata_report_id from reports where report_metadata_report_id = %s;',
- [report.find('./report_metadata/report_id').text])
- results = cursor.fetchall()
- if len(results) != 1:
- raise RuntimeError('Could not find report record for report item')
- else:
- report_id = results[0][0]
- insert_string, values = build_insert_command('report_items', report, i=i,
- preamble_values={'report_id': report_id})
+ try:
+ insert_string, values = build_insert_command('reports', report)
# print(insert_string, values)
cursor.execute(insert_string, values)
- connection.commit()
+
+ for i in range(1, len(report.findall('./record'))+1):
+ field_names = []
+ cursor.execute('select id, report_metadata_report_id from reports where report_metadata_report_id = %s;',
+ [report.find('./report_metadata/report_id').text])
+ results = cursor.fetchall()
+ if len(results) != 1:
+ raise RuntimeError('Could not find report record for report item')
+ else:
+ report_id = results[0][0]
+ insert_string, values = build_insert_command('report_items', report, i=i,
+ preamble_values={'report_id': report_id})
+ # print(insert_string, values)
+ cursor.execute(insert_string, values)
+ connection.commit()
+ except AttributeError:
+ pass
config = configparser.ConfigParser()
-config.read('dmarc.ini')
+if args.config_file:
+ config.read(args.config_file)
+else:
+ config.read(['/etc/dmarc_to_database.ini', './dmarc_to_database.ini'])
+
+if not config.sections():
+ raise RuntimeError('Could not find configuration file')
conn = psycopg2.connect(host=config['database']['server'],
database=config['database']['database'],
dmarc_reports = [report for report_set in [extract_report(fetch_msg(n)) for n in nums[0].split()]
- for report in report_set]
+ for report in report_set
+ if report]
mailbox.close()
mailbox.logout()
results = cur.fetchall()
if not results:
print('write', report.find('./report_metadata/report_id').text)
- write_report(conn, cur, report)
+ if not args.test:
+ write_report(conn, cur, report)
conn.close()