2023-04-10 15:07:53 +02:00
|
|
|
#!/usr/bin/python3
|
|
|
|
import sqlite3
|
|
|
|
from pathlib import Path
|
|
|
|
from sqlite3 import Error
|
|
|
|
import urllib.request
|
|
|
|
import json
|
|
|
|
import logging
|
|
|
|
import argparse
|
|
|
|
import requests
|
|
|
|
import os
|
|
|
|
import time
|
|
|
|
import sys
|
|
|
|
from types import SimpleNamespace
|
|
|
|
from datetime import datetime
|
|
|
|
from string import ascii_letters, digits
|
|
|
|
from rich import print
|
|
|
|
from argparse import RawTextHelpFormatter
|
2023-04-12 11:57:35 +02:00
|
|
|
#from urllib import Request, urlopen
|
|
|
|
from urllib.request import urlopen
|
2023-04-10 15:07:53 +02:00
|
|
|
|
|
|
|
# Info pages for dev
|
|
|
|
# https://mailcow.docs.apiary.io/#reference/aliases/get-aliases/get-aliases
|
|
|
|
# https://demo.mailcow.email/api/#/Aliases
|
|
|
|
|
|
|
|
|
|
|
|
homefilepath = Path.home()
|
|
|
|
filepath = homefilepath.joinpath('.config/malias')
|
|
|
|
database = filepath.joinpath('malias.db')
|
|
|
|
logfile = filepath.joinpath('malias.log')
|
|
|
|
Path(filepath).mkdir(parents=True, exist_ok=True)
|
|
|
|
logging.basicConfig(filename=logfile,level=logging.INFO,format='%(message)s')
|
|
|
|
app_version = '0.1'
|
|
|
|
|
|
|
|
|
|
|
|
def connect_database():
|
|
|
|
Path(filepath).mkdir(parents=True, exist_ok=True)
|
|
|
|
conn = None
|
|
|
|
try:
|
|
|
|
conn = sqlite3.connect(database)
|
|
|
|
except Error as e:
|
|
|
|
logging.error(time.strftime("%Y-%m-%d %H:%M") + ' - Error : ' + str(e))
|
|
|
|
print(e)
|
|
|
|
finally:
|
|
|
|
if conn:
|
|
|
|
c = conn.cursor()
|
|
|
|
c.execute('''CREATE TABLE IF NOT EXISTS apikey
|
|
|
|
(id integer NOT NULL PRIMARY KEY,
|
|
|
|
api text NOT NULL)''')
|
2023-04-11 13:01:37 +02:00
|
|
|
c.execute('''CREATE TABLE IF NOT EXISTS settings (
|
|
|
|
id INTEGER NOT NULL PRIMARY KEY,
|
|
|
|
first_run INTEGER DEFAULT 0,
|
|
|
|
server TEXT DEFAULT "TEST"
|
|
|
|
)''')
|
2023-04-10 15:07:53 +02:00
|
|
|
c.execute('''CREATE TABLE IF NOT EXISTS aliases
|
2023-04-11 13:01:37 +02:00
|
|
|
(id integer NOT NULL PRIMARY KEY,
|
|
|
|
alias text NOT NULL,
|
|
|
|
goto text NOT NULL,
|
|
|
|
created text NOT NULL)''')
|
2023-04-10 15:07:53 +02:00
|
|
|
|
2023-04-11 13:01:37 +02:00
|
|
|
conn.commit()
|
|
|
|
first_run(conn)
|
2023-04-10 15:07:53 +02:00
|
|
|
return conn
|
2023-04-11 13:01:37 +02:00
|
|
|
|
|
|
|
|
|
|
|
def first_run(conn):
|
|
|
|
now = datetime.now().strftime("%m-%d-%Y %H:%M")
|
2023-04-10 15:07:53 +02:00
|
|
|
cursor = conn.cursor()
|
2023-04-11 13:01:37 +02:00
|
|
|
cursor.execute('SELECT count(*) FROM settings')
|
2023-04-10 15:07:53 +02:00
|
|
|
count = cursor.fetchone()[0]
|
|
|
|
if count == 0:
|
2023-04-11 13:01:37 +02:00
|
|
|
logging.error(now + ' - First run!')
|
|
|
|
cursor.execute('INSERT INTO settings values(?,?,?)', (1, 1, 'dummy.server'))
|
|
|
|
cursor.execute('INSERT INTO apikey values(?,?)', (1, 'DUMMY_KEY'))
|
|
|
|
conn.commit()
|
2023-04-10 15:07:53 +02:00
|
|
|
return None
|
2023-04-11 13:01:37 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_settings(kind):
|
|
|
|
cursor = conn.cursor()
|
|
|
|
cursor.execute('SELECT * FROM settings')
|
|
|
|
data = cursor.fetchall()
|
|
|
|
first_run_status = data[0][1]
|
|
|
|
mail_server = data[0][2]
|
|
|
|
if kind == 'mail_server':
|
|
|
|
if mail_server == 'dummy.server':
|
|
|
|
print('Error: No MailCow server active. Please add one with [b]malias -m [i]your.server[/i][/b]')
|
|
|
|
exit(0)
|
|
|
|
else:
|
|
|
|
return mail_server
|
|
|
|
if kind == 'first_run_status':
|
|
|
|
return first_run_status
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_api():
|
|
|
|
cursor = conn.cursor()
|
|
|
|
cursor.execute('SELECT api FROM apikey')
|
|
|
|
apikey = cursor.fetchone()[0]
|
|
|
|
if apikey == 'DUMMY_KEY':
|
|
|
|
print('Missing API key. Please add with [b]malias -k [i]YOUR-API-KEY[/i][/b]')
|
|
|
|
exit(0)
|
2023-04-10 15:07:53 +02:00
|
|
|
else:
|
2023-04-11 13:01:37 +02:00
|
|
|
return apikey
|
2023-04-10 15:07:53 +02:00
|
|
|
|
|
|
|
|
2023-04-11 13:01:37 +02:00
|
|
|
def set_mailserver(server):
|
|
|
|
now = datetime.now().strftime("%m-%d-%Y %H:%M")
|
|
|
|
cursor = conn.cursor()
|
|
|
|
cursor.execute('UPDATE settings SET server = ? WHERE id = 1',(server,))
|
|
|
|
logging.info(now + ' - Info : MailCow server updated')
|
|
|
|
print('Your mail server has been updated.')
|
|
|
|
conn.commit()
|
|
|
|
|
|
|
|
|
2023-04-10 15:07:53 +02:00
|
|
|
|
|
|
|
def apikey(key):
|
2023-04-11 13:01:37 +02:00
|
|
|
now = datetime.now().strftime("%m-%d-%Y %H:%M")
|
2023-04-10 15:07:53 +02:00
|
|
|
cursor = conn.cursor()
|
2023-04-11 13:01:37 +02:00
|
|
|
cursor.execute('UPDATE apikey SET api = ? WHERE id = 1',(key,))
|
|
|
|
logging.info(now + ' - Info : API key updated')
|
|
|
|
print('Your API key has been updated.')
|
|
|
|
conn.commit()
|
|
|
|
|
|
|
|
|
|
|
|
def create(alias,to_address):
|
|
|
|
now = datetime.now().strftime("%m-%d-%Y %H:%M")
|
|
|
|
server = get_settings('mail_server')
|
|
|
|
apikey = get_api()
|
|
|
|
if checklist(alias) == True:
|
|
|
|
logging.error(now + ' - Error : alias %s exists on the MailCow instance %s ' %(alias,server))
|
|
|
|
print('\n[b]Error[/b] : alias %s exists on the MailCow instance %s \n' %(alias,server))
|
|
|
|
exit(0)
|
2023-04-10 15:07:53 +02:00
|
|
|
else:
|
2023-04-12 11:57:35 +02:00
|
|
|
data = {'address': alias,'goto': to_address,'active': "1"}
|
|
|
|
headers = {'X-API-Key': apikey, "Content-Type": "application/json"}
|
|
|
|
response = requests.post('https://'+server+'/api/v1/add/alias',
|
|
|
|
data=json.dumps(data), headers=headers)
|
|
|
|
mail_id = alias_id(alias)
|
|
|
|
if mail_id == None:
|
|
|
|
logging.error(now + ' - Error : alias %s not created on the MailCow instance %s ' %(alias,server))
|
|
|
|
print('\n[b]Error[/b] : alias %s exists on the MailCow instance %s \n' %(alias,server))
|
|
|
|
else:
|
|
|
|
cursor = conn.cursor()
|
|
|
|
cursor.execute('INSERT INTO aliases values(?,?,?,?)', (mail_id, alias,to_address,now))
|
|
|
|
conn.commit()
|
|
|
|
|
2023-04-10 15:07:53 +02:00
|
|
|
|
2023-04-12 11:57:35 +02:00
|
|
|
|
2023-04-10 15:07:53 +02:00
|
|
|
def delete(alias):
|
|
|
|
print('Delete : ' + alias)
|
|
|
|
|
|
|
|
|
|
|
|
def checklist(alias):
|
|
|
|
apikey = get_api()
|
2023-04-11 13:01:37 +02:00
|
|
|
mail_server = get_settings('mail_server')
|
|
|
|
req = urllib.request.Request('https://'+mail_server+'/api/v1/get/alias/all')
|
2023-04-10 15:07:53 +02:00
|
|
|
req.add_header('Content-Type', 'application/json')
|
|
|
|
req.add_header('X-API-Key', apikey)
|
|
|
|
current = urllib.request.urlopen(req)
|
|
|
|
remote = current.read().decode('utf-8')
|
|
|
|
remoteData = json.loads(remote)
|
|
|
|
i = 0
|
|
|
|
for search in remoteData:
|
2023-04-12 11:57:35 +02:00
|
|
|
if alias in remoteData[i]['address']:
|
2023-04-10 15:07:53 +02:00
|
|
|
return True
|
|
|
|
i=i+1
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
2023-04-12 11:57:35 +02:00
|
|
|
def list_alias():
|
2023-04-11 13:01:37 +02:00
|
|
|
apikey = get_api()
|
|
|
|
mail_server = get_settings('mail_server')
|
|
|
|
req = urllib.request.Request('https://'+mail_server+'/api/v1/get/alias/all')
|
|
|
|
req.add_header('Content-Type', 'application/json')
|
|
|
|
req.add_header('X-API-Key', apikey)
|
|
|
|
current = urllib.request.urlopen(req)
|
|
|
|
remote = current.read().decode('utf-8')
|
|
|
|
remoteData = json.loads(remote)
|
|
|
|
i = 0
|
2023-04-12 11:57:35 +02:00
|
|
|
for search in remoteData:
|
|
|
|
print(remoteData[i]['address'])
|
2023-04-11 13:01:37 +02:00
|
|
|
i=i+1
|
2023-04-12 11:57:35 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def alias_id(alias):
|
|
|
|
apikey = get_api()
|
|
|
|
mail_server = get_settings('mail_server')
|
|
|
|
req = urllib.request.Request('https://'+mail_server+'/api/v1/get/alias/all')
|
|
|
|
req.add_header('Content-Type', 'application/json')
|
|
|
|
req.add_header('X-API-Key', apikey)
|
|
|
|
current = urllib.request.urlopen(req)
|
|
|
|
remote = current.read().decode('utf-8')
|
|
|
|
remoteData = json.loads(remote)
|
|
|
|
i = 0
|
|
|
|
for search in remoteData:
|
|
|
|
if remoteData[i]['address'] == alias:
|
|
|
|
return remoteData[i]['id']
|
|
|
|
i=i+1
|
|
|
|
return None
|
|
|
|
|
2023-04-11 13:01:37 +02:00
|
|
|
|
|
|
|
def number_of_aliases_in_db():
|
|
|
|
cursor = conn.cursor()
|
|
|
|
cursor.execute('SELECT count(*) FROM aliases')
|
|
|
|
count = cursor.fetchone()[0]
|
|
|
|
return count
|
|
|
|
|
|
|
|
|
2023-04-10 15:07:53 +02:00
|
|
|
def search(alias):
|
2023-04-11 13:01:37 +02:00
|
|
|
results = checklist(alias)
|
|
|
|
mail_server = get_settings('mail_server')
|
|
|
|
if results == True:
|
|
|
|
print('\n\nThe mail address %s exists. Using the MailCow instance : %s\n\n'%(alias,mail_server))
|
|
|
|
else:
|
|
|
|
print('\n\nThe mail address %s [b]does not[/b] exists. Using the MailCow instance : %s\n\n'%(alias,mail_server))
|
|
|
|
|
2023-04-10 15:07:53 +02:00
|
|
|
|
2023-04-11 13:01:37 +02:00
|
|
|
|
|
|
|
def show_current_info():
|
|
|
|
API = get_api()
|
|
|
|
mail_server = get_settings('mail_server')
|
|
|
|
|
|
|
|
if API == 'DUMMY_KEY':
|
|
|
|
API = 'Missing API Key!'
|
|
|
|
|
|
|
|
if mail_server == 'dummy.server':
|
|
|
|
mail_server = 'Missing address to MailCow instance!'
|
|
|
|
|
|
|
|
aliases_server = number_of_aliases_on_server()
|
|
|
|
alias_db = number_of_aliases_in_db()
|
|
|
|
|
|
|
|
print('\n[b]malias[/b] - Manage aliases on MailCow Instance.')
|
|
|
|
print('===================================================')
|
|
|
|
print('API key : [b]%s[/b]' % (API))
|
|
|
|
print('MailCow Instance : [b]%s[/b]' % (mail_server))
|
|
|
|
print('Logfile : [b]%s[/b]' % (logfile))
|
|
|
|
print('Aliases on server : [b]%s[/b]' % (aliases_server))
|
|
|
|
print('Aliases in DB : [b]%s[/b]' % (alias_db))
|
|
|
|
print('')
|
|
|
|
print('App version : [b]%s[/b] (https://gitlab.pm/rune/malias)' % (app_version))
|
|
|
|
print('')
|
|
|
|
|
|
|
|
|
2023-04-10 15:07:53 +02:00
|
|
|
conn = connect_database()
|
2023-04-11 13:01:37 +02:00
|
|
|
|
2023-04-10 15:07:53 +02:00
|
|
|
|
|
|
|
parser = argparse.ArgumentParser(prog='malias',
|
2023-04-11 13:01:37 +02:00
|
|
|
description='Application description',
|
2023-04-10 15:07:53 +02:00
|
|
|
formatter_class=RawTextHelpFormatter,
|
2023-04-11 13:01:37 +02:00
|
|
|
epilog='Making MailCow easier...')
|
2023-04-10 15:07:53 +02:00
|
|
|
|
|
|
|
parser.add_argument('-k', '--api', help='Add/Change API key.\n\n',
|
|
|
|
nargs=1, metavar=('APIkey'), required=False, action="append")
|
|
|
|
|
|
|
|
parser.add_argument('-s', '--search', help='Search for alias.\n\n',
|
|
|
|
nargs=1, metavar=('alias@domain.com'), required=False, action="append")
|
|
|
|
|
2023-04-11 13:01:37 +02:00
|
|
|
parser.add_argument('-m', '--server', help='Add/Uppdate MailCow instance.\n\n',
|
|
|
|
nargs=1, metavar=('alias@domain.com'), required=False, action="append")
|
|
|
|
|
|
|
|
|
|
|
|
parser.add_argument('-a', '--add', help='Add new alias.\n\n',
|
|
|
|
nargs=2, metavar=('alias@domain.com', 'to@domain.com'), required=False, action="append")
|
|
|
|
|
|
|
|
parser.add_argument('-v', '--version', help='Show current version and config info\n\n',
|
|
|
|
required=False, action='store_true')
|
2023-04-10 15:07:53 +02:00
|
|
|
|
|
|
|
args = vars(parser.parse_args())
|
|
|
|
|
|
|
|
if args['api']:
|
|
|
|
apikey(args['api'][0][0])
|
|
|
|
elif args['search']:
|
|
|
|
search(args['search'][0][0])
|
2023-04-11 13:01:37 +02:00
|
|
|
elif args['server']:
|
|
|
|
set_mailserver(args['server'][0][0])
|
|
|
|
elif args['add']:
|
|
|
|
create(args['add'][0][0],args['add'][0][1])
|
|
|
|
elif args['version']:
|
|
|
|
show_current_info()
|
|
|
|
|
2023-04-10 15:07:53 +02:00
|
|
|
|
|
|
|
else:
|
2023-04-11 13:01:37 +02:00
|
|
|
# get_settings(first_run_status)
|
|
|
|
get_api()
|
2023-04-12 11:57:35 +02:00
|
|
|
list_alias()
|
2023-04-11 13:01:37 +02:00
|
|
|
print('\n\nError use [b]malias -h[/b] to see the help screen!\n\n\n')
|