2025-03-04 10:14:27 +01:00
#!/usr/bin/python3 -W ignore::DeprecationWarning
2025-02-21 13:16:42 +01:00
import sys
2023-04-10 15:07:53 +02:00
import sqlite3
from pathlib import Path
from sqlite3 import Error
import urllib . request
import json
import logging
import argparse
import os
2025-03-03 13:57:02 +01:00
import time
from rich import print
2025-03-04 10:14:27 +01:00
from datetime import datetime , timedelta
2023-04-10 15:07:53 +02:00
from string import ascii_letters , digits
from argparse import RawTextHelpFormatter
2024-04-10 13:40:00 +02:00
from operator import itemgetter
2025-03-03 13:57:02 +01:00
import httpx
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
2025-03-03 13:57:02 +01:00
# HTTPx ref -> https://www.python-httpx.org/
2023-04-10 15:07:53 +02:00
homefilepath = Path . home ( )
2025-03-03 13:57:02 +01:00
filepath = homefilepath . joinpath ( ' .config/malias2 ' )
database = filepath . joinpath ( ' malias2.db ' )
logfile = filepath . joinpath ( ' malias2.log ' )
2023-04-10 15:07:53 +02:00
Path ( filepath ) . mkdir ( parents = True , exist_ok = True )
logging . basicConfig ( filename = logfile , level = logging . INFO , format = ' %(message)s ' )
2025-03-03 13:57:02 +01:00
logging . getLogger ( " httpx " ) . setLevel ( logging . ERROR )
app_version = ' 2.0 '
db_version = ' 2.0.0 '
footer = ' malias version %s ' % ( app_version )
2023-04-10 15:07:53 +02:00
2025-03-04 10:14:27 +01:00
def unix_to_datetime ( unix_timestamp ) :
return datetime . fromtimestamp ( unix_timestamp )
2023-09-06 12:29:32 +02:00
def get_latest_release ( ) :
2025-03-03 13:57:02 +01:00
version = ' N/A '
req = httpx . get ( ' https://gitlab.pm/api/v1/repos/rune/malias/releases/latest ' ,
headers = { " Content-Type " : " application/json " }
)
version = req . json ( ) [ ' tag_name ' ]
return version
2023-09-06 12:29:32 +02:00
def release_check ( ) :
2023-10-03 10:15:50 +02:00
latest_release = get_latest_release ( )
2023-09-06 12:29:32 +02:00
if app_version != latest_release :
print ( ' [b]New version available @ [i]https://iurl.no/malias[/b][/i] ' )
else :
2023-10-03 10:15:50 +02:00
print ( ' You have the the latest version. Version: %s ' % ( app_version ) )
2024-04-10 13:40:00 +02:00
2023-09-06 12:29:32 +02:00
2025-03-03 13:57:02 +01:00
2023-04-10 15:07:53 +02:00
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 ( )
2023-04-11 13:01:37 +02:00
c . execute ( ''' CREATE TABLE IF NOT EXISTS settings (
id INTEGER NOT NULL PRIMARY KEY,
2023-04-13 09:29:07 +02:00
first_run INTEGER,
server TEXT,
2025-03-03 13:57:02 +01:00
apikey TEXT NOT NULL,
2023-04-16 18:04:24 +02:00
data_copy INTEGER
2023-04-11 13:01:37 +02:00
) ''' )
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) ''' )
2024-04-10 13:40:00 +02:00
c . execute ( ''' CREATE TABLE IF NOT EXISTS timedaliases
(id integer NOT NULL PRIMARY KEY,
alias text NOT NULL,
goto text NOT NULL,
validity text NOT NULL) ''' )
2025-03-03 13:57:02 +01:00
c . execute ( ''' CREATE TABLE IF NOT EXISTS dbversion
(version integer NOT NULL DEFAULT 0) ''' )
c . execute ( ''' CREATE TABLE IF NOT EXISTS timedaliases
(id integer NOT NULL PRIMARY KEY,
alias text NOT NULL,
goto text NOT NULL,
validity text NOT NULL) ''' )
2024-04-10 13:40:00 +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! ' )
2025-03-03 13:57:02 +01:00
cursor . execute ( ' INSERT INTO settings values(?,?,?,?,?) ' , ( 0 , 1 , ' dummy.server ' , ' DUMMY_KEY ' , 0 ) )
cursor . execute ( ' INSERT INTO dbversion values(?) ' , ( db_version , ) )
2023-04-11 13:01:37 +02:00
conn . commit ( )
2023-04-10 15:07:53 +02:00
return None
2023-04-11 13:01:37 +02:00
2024-04-10 13:40:00 +02:00
2023-04-11 13:01:37 +02:00
def get_settings ( kind ) :
2025-03-03 13:57:02 +01:00
now = datetime . now ( ) . strftime ( " % m- %d - % Y % H: % M " )
2023-04-11 13:01:37 +02:00
cursor = conn . cursor ( )
cursor . execute ( ' SELECT * FROM settings ' )
2024-04-10 13:40:00 +02:00
data = cursor . fetchall ( )
2025-03-03 13:57:02 +01:00
first_run_status = data [ 0 ] [ 1 ] # pyright: ignore
server = data [ 0 ] [ 2 ] # pyright: ignore
api_key = data [ 0 ] [ 3 ] # pyright: ignore
copy_status = data [ 0 ] [ 4 ] # pyright: ignore
if kind == ' connection ' :
if server == ' dummy.server ' or api_key == ' DUMMY_KEY ' :
print ( ' Error: No mailcow server or API key registered. Please add with [b]malias -s [i]your.server APIKEY[/i][/b] ' )
2023-04-11 13:01:37 +02:00
exit ( 0 )
else :
2025-03-03 13:57:02 +01:00
connection = { ' key ' : api_key , ' server ' : server }
req = httpx . get ( ' https:// ' + connection [ ' server ' ] + ' /api/v1/get/domain/0 ' ,
headers = { " Content-Type " : " application/json " ,
' X-API-Key ' : connection [ ' key ' ]
}
)
data = req . json ( )
code = str ( req )
if code . find ( ' 200 ' ) != - 1 :
return connection # pyright: ignore
else :
logging . error ( now + ' - Error : Server returned error: %s , ' % ( data [ ' msg ' ] ) )
print ( ' \n [b red]Error[/b red] : Server returned error [b] %s [/b] \n \n ' % ( data [ ' msg ' ] ) )
exit ( 0 )
2023-04-11 13:01:37 +02:00
if kind == ' first_run_status ' :
return first_run_status
2023-04-16 18:04:24 +02:00
if kind == ' copy_status ' :
return copy_status
2023-04-11 13:01:37 +02:00
2024-04-10 13:40:00 +02:00
2025-03-03 13:57:02 +01:00
def get_last_timed ( username ) :
connection = get_settings ( ' connection ' )
req = httpx . get ( ' https:// ' + connection [ ' server ' ] + ' /api/v1/get/time_limited_aliases/ %s ' % username ,
headers = { " Content-Type " : " application/json " ,
' X-API-Key ' : connection [ ' key ' ]
}
)
data = req . json ( )
data . sort ( key = itemgetter ( ' validity ' ) , reverse = True )
return ( data [ 0 ] )
2024-04-10 13:40:00 +02:00
2025-03-03 13:57:02 +01:00
def set_conection_info ( server , apikey ) :
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 ( )
2025-03-03 13:57:02 +01:00
cursor . execute ( ' UPDATE settings SET server = ?, apikey = ? WHERE id = 0 ' , ( server , apikey ) )
logging . info ( now + ' - Info : Connectioninformations updated ' )
print ( ' Your connection information has been updated. ' )
2023-04-11 13:01:37 +02:00
conn . commit ( )
2023-10-03 10:15:50 +02:00
2023-09-01 11:22:54 +02:00
2023-04-13 09:29:07 +02:00
def copy_data ( ) :
2025-03-03 13:57:02 +01:00
connection = get_settings ( ' connection ' )
2023-04-16 18:04:24 +02:00
if get_settings ( ' copy_status ' ) == 0 :
now = datetime . now ( ) . strftime ( " % m- %d - % Y % H: % M " )
cursor = conn . cursor ( )
2025-03-03 13:57:02 +01:00
req = httpx . get ( ' https:// ' + connection [ ' server ' ] + ' /api/v1/get/alias/all ' ,
headers = { " Content-Type " : " application/json " ,
' X-API-Key ' : connection [ ' key ' ]
}
)
data = req . json ( )
if not data :
print ( ' \n [b red]Error[/b red] : No aliases on server %s . Nothing to copy! \n \n ' % ( connection [ ' server ' ] ) )
exit ( 0 )
i = 0
for data in data :
cursor . execute ( ' INSERT INTO aliases values(?,?,?,?) ' , ( data [ ' id ' ] , data [ ' address ' ] , data [ ' goto ' ] , now ) )
2023-04-16 18:04:24 +02:00
i = i + 1
2025-03-03 13:57:02 +01:00
cursor . execute ( ' UPDATE settings SET data_copy = ? WHERE id = 0 ' , ( 1 , ) )
2023-04-16 18:04:24 +02:00
conn . commit ( )
2025-03-03 13:57:02 +01:00
logging . info ( now + ' - Info : Imported %s new aliases from %s ' % ( str ( i ) , connection [ ' server ' ] ) )
print ( ' \n [b]Info[/b] : %s aliases imported from the mailcow instance %s to local DB \n ' % ( i , connection [ ' server ' ] ) )
2023-04-16 18:04:24 +02:00
else :
2025-03-03 13:57:02 +01:00
print ( ' \n [b]Info[/b] : aliases alreday imported from the mailcow instance %s to local DB \n \n [i]Updating with any missing aliases![/i] ' % ( connection [ ' server ' ] ) )
2023-09-04 15:12:57 +02:00
update_data ( )
def update_data ( ) :
2025-03-03 13:57:02 +01:00
connection = get_settings ( ' connection ' )
2023-09-04 15:12:57 +02:00
if get_settings ( ' copy_status ' ) == 1 :
now = datetime . now ( ) . strftime ( " % m- %d - % Y % H: % M " )
2025-03-03 13:57:02 +01:00
req = httpx . get ( ' https:// ' + connection [ ' server ' ] + ' /api/v1/get/alias/all ' ,
headers = { " Content-Type " : " application/json " ,
' X-API-Key ' : connection [ ' key ' ]
}
)
data = req . json ( )
2023-09-04 15:12:57 +02:00
i = 0
count_alias = 0
cursor = conn . cursor ( )
2025-03-03 13:57:02 +01:00
for data in data :
cursor . execute ( ' SELECT count(*) FROM aliases where alias like ? and goto like ? ' , ( data [ ' address ' ] , data [ ' goto ' ] , ) )
2023-09-04 15:12:57 +02:00
count = cursor . fetchone ( ) [ 0 ]
if count > = 1 :
i + = 1
else :
2025-03-03 13:57:02 +01:00
cursor . execute ( ' INSERT INTO aliases values(?,?,?,?) ' , ( data [ ' id ' ] , data [ ' address ' ] , data [ ' goto ' ] , now ) )
2023-09-04 15:12:57 +02:00
count_alias + = 1
i + = 1
conn . commit ( )
if count_alias > 0 :
2025-03-03 13:57:02 +01:00
logging . info ( now + ' - Info : Local DB updated with %s new aliases from %s ' % ( str ( count_alias ) , connection [ ' server ' ] ) )
print ( ' \n [b]Info[/b] : Local DB update with %s new aliases from %s \n ' % ( str ( count_alias ) , connection [ ' server ' ] ) )
2023-09-04 15:12:57 +02:00
else :
print ( ' \n [b]Info[/b] : No missing aliases from local DB \n ' )
2025-03-03 13:57:02 +01:00
def create ( alias , to_address ) :
now = datetime . now ( ) . strftime ( " % m- %d - % Y % H: % M " )
connection = get_settings ( ' connection ' ) # pyright: ignore
check = checklist ( alias )
if check [ 0 ] == True :
logging . error ( now + ' - Error : alias %s exists on the mailcow instance %s ' % ( alias , connection [ ' server ' ] ) )
print ( ' \n [b]Error[/b] : alias %s exists on the mailcow instance %s \n ' % ( alias , connection [ ' server ' ] ) )
exit ( 0 )
elif check [ 1 ] == True :
logging . error ( now + ' - Error : alias %s exists in local database. ' % ( alias ) )
print ( ' \n [b]Error[/b] : alias %s exists in local database. \n ' % ( alias ) )
exit ( 0 )
else :
try :
new_data = { ' address ' : alias , ' goto ' : to_address , ' active ' : " 1 " }
new_data = json . dumps ( new_data )
req = httpx . post ( ' https:// ' + connection [ ' server ' ] + ' /api/v1/add/alias ' ,
headers = { " Content-Type " : " application/json " ,
' X-API-Key ' : connection [ ' key ' ]
} ,
data = new_data
)
except httpx . HTTPError as exc :
print ( f " Error while requesting { exc . request . url !r} . " )
mail_id = alias_id ( alias )
if mail_id == None :
logging . error ( now + ' - Error : alias %s not created on the mailcow instance %s ' % ( alias , connection [ ' server ' ] ) )
print ( ' \n [b]Error[/b] : alias %s exists on the mailcow instance %s \n ' % ( alias , connection [ ' server ' ] ) )
else :
cursor = conn . cursor ( )
cursor . execute ( ' INSERT INTO aliases values(?,?,?,?) ' , ( mail_id , alias , to_address , now ) )
conn . commit ( )
logging . info ( now + ' - Info : alias %s created for %s on the mailcow instance %s ' % ( alias , to_address , connection [ ' server ' ] ) )
print ( ' \n [b]Info[/b] : alias %s created for %s on the mailcow instance %s \n ' % ( alias , to_address , connection [ ' server ' ] ) )
2023-04-10 15:07:53 +02:00
def checklist ( alias ) :
2025-03-03 13:57:02 +01:00
alias_e = None
alias_i = None
connection = get_settings ( ' connection ' )
req = httpx . get ( ' https:// ' + connection [ ' server ' ] + ' /api/v1/get/alias/all ' ,
headers = { " Content-Type " : " application/json " ,
' X-API-Key ' : connection [ ' key ' ]
}
)
data = req . json ( )
2023-04-10 15:07:53 +02:00
i = 0
2025-03-03 13:57:02 +01:00
for data in data :
if alias == data [ ' address ' ] or alias in data [ ' goto ' ] :
alias_e = True
2023-04-10 15:07:53 +02:00
i = i + 1
2023-04-18 14:41:11 +02:00
cursor = conn . cursor ( )
2023-11-09 12:02:11 +01:00
cursor . execute ( ' SELECT count(*) FROM aliases where alias == ? or goto == ? ' , ( alias , alias , ) )
2023-04-18 14:41:11 +02:00
count = cursor . fetchone ( ) [ 0 ]
if count > = 1 :
2025-03-03 13:57:02 +01:00
alias_i = True
alias_exist = [ alias_e , alias_i ]
2023-04-18 14:41:11 +02:00
return alias_exist
2023-04-10 15:07:53 +02:00
2023-04-12 11:57:35 +02:00
def alias_id ( alias ) :
2025-03-03 13:57:02 +01:00
connection = get_settings ( ' connection ' )
req = httpx . get ( ' https:// ' + connection [ ' server ' ] + ' /api/v1/get/alias/all ' ,
headers = { " Content-Type " : " application/json " ,
' X-API-Key ' : connection [ ' key ' ]
}
)
data = req . json ( )
2023-04-12 11:57:35 +02:00
i = 0
2025-03-03 13:57:02 +01:00
for data in data :
if data [ ' address ' ] == alias :
return data [ ' id ' ]
2023-04-12 11:57:35 +02:00
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-16 18:04:24 +02:00
def number_of_aliases_on_server ( ) :
2025-03-03 13:57:02 +01:00
connection = get_settings ( ' connection ' )
req = httpx . get ( ' https:// ' + connection [ ' server ' ] + ' /api/v1/get/alias/all ' ,
headers = { " Content-Type " : " application/json " ,
' X-API-Key ' : connection [ ' key ' ]
}
)
data = req . json ( )
return len ( data )
2023-04-16 18:04:24 +02:00
2024-04-10 13:40:00 +02:00
2025-03-03 13:57:02 +01:00
def search ( alias ) :
connection = get_settings ( ' connection ' )
2023-04-16 18:04:24 +02:00
cursor = conn . cursor ( )
2025-03-03 13:57:02 +01:00
search_term = ' % ' + alias + ' % '
cursor . execute ( ' SELECT alias,goto from aliases where alias like ? or goto like ? ' , ( search_term , search_term , ) )
localdata = cursor . fetchall ( )
req = httpx . get ( ' https:// ' + connection [ ' server ' ] + ' /api/v1/get/alias/all ' ,
headers = { " Content-Type " : " application/json " ,
' X-API-Key ' : connection [ ' key ' ]
}
)
remotedata = req . json ( )
remote = [ ]
i = 0
for data in remotedata :
if alias in remotedata [ i ] [ ' address ' ] or alias in remotedata [ i ] [ ' goto ' ] :
remote . append ( ( remotedata [ i ] [ ' address ' ] , remotedata [ i ] [ ' goto ' ] ) )
i = i + 1
finallist = localdata + list ( set ( remote ) - set ( localdata ) )
i = 0
print ( ' \n Aliases on %s containg search term [b] %s [/b] ' % ( connection [ ' server ' ] , alias ) )
print ( ' ================================================================= ' )
for data in finallist :
the_alias = finallist [ i ] [ 0 ] . ljust ( 20 , ' ' )
print ( the_alias + ' \t goes to \t \t ' + finallist [ i ] [ 1 ] )
i = i + 1
print ( ' \n ' + footer + ' \n ' )
2024-04-10 13:40:00 +02:00
2023-04-16 18:04:24 +02:00
2025-03-03 13:57:02 +01:00
def get_mail_domains ( info ) :
connection = get_settings ( ' connection ' )
2023-04-17 14:02:58 +02:00
cursor = conn . cursor ( )
2025-03-03 13:57:02 +01:00
req = httpx . get ( ' https:// ' + connection [ ' server ' ] + ' /api/v1/get/domain/all ' ,
headers = { " Content-Type " : " application/json " ,
' X-API-Key ' : connection [ ' key ' ]
}
)
remoteData = req . json ( )
if info :
total_aliases = 0
i = 0
print ( ' \n [b]malias[/b] - All email domains on %s ' % ( connection [ ' server ' ] ) )
print ( ' ================================================================== ' )
for domains in remoteData :
cursor . execute ( ' SELECT count(*) FROM aliases where alias like ? or goto like ? ' , ( ' % ' + remoteData [ i ] [ ' domain_name ' ] + ' % ' , ' % ' + remoteData [ i ] [ ' domain_name ' ] + ' % ' , ) )
count = cursor . fetchone ( ) [ 0 ]
total_aliases + = count
print ( ' %s \t \t with %s aliases ' % ( remoteData [ i ] [ ' domain_name ' ] , count ) )
i + = 1
print ( ' \n \n There is a total of %s domains with %s aliases. \n %s ' % ( str ( i ) , str ( total_aliases ) , footer ) )
2023-10-03 10:15:50 +02:00
2023-04-11 13:01:37 +02:00
else :
2025-03-03 13:57:02 +01:00
return ( remoteData )
2024-04-10 13:40:00 +02:00
2023-04-11 13:01:37 +02:00
def show_current_info ( ) :
2025-03-03 13:57:02 +01:00
connection = get_settings ( ' connection ' )
2023-10-03 10:15:50 +02:00
latest_release = get_latest_release ( )
2023-04-11 13:01:37 +02:00
aliases_server = number_of_aliases_on_server ( )
alias_db = number_of_aliases_in_db ( )
2023-09-05 11:36:39 +02:00
mail_domains = get_mail_domains ( False )
domain = " "
i = 0
for domains in mail_domains :
if i != 0 :
domain = domain + ' , ' + str ( mail_domains [ i ] [ ' domain_name ' ] )
else :
domain = domain + str ( mail_domains [ i ] [ ' domain_name ' ] )
i + = 1
2025-02-21 13:16:42 +01:00
print ( ' \n [b]malias[/b] - Manage aliases on mailcow Instance. ' )
2023-04-11 13:01:37 +02:00
print ( ' =================================================== ' )
2025-03-03 13:57:02 +01:00
print ( ' API key : [b] %s [/b] ' % ( connection [ ' key ' ] ) )
print ( ' Mailcow Instance : [b] %s [/b] ' % ( connection [ ' server ' ] ) )
2025-02-21 13:16:42 +01:00
print ( ' Active domains : [b] %s [/b] ' % ( domain ) )
print ( ' Logfile : [b] %s [/b] ' % ( logfile ) )
print ( ' Databse : [b] %s [b] ' % ( database ) )
print ( ' Aliases on server : [b] %s [/b] ' % ( aliases_server ) )
print ( ' Aliases in DB : [b] %s [/b] ' % ( alias_db ) )
print ( ' ' )
2025-03-03 13:57:02 +01:00
if float ( app_version ) < float ( latest_release ) :
2025-02-21 13:16:42 +01:00
print ( ' App version : [b] %s [/b] a new version ( %s ) is available @ https://iurl.no/malias ' % ( app_version , latest_release ) )
else :
print ( ' App version : [b] %s [/b] ' % ( app_version ) )
2023-04-11 13:01:37 +02:00
print ( ' ' )
2024-04-10 13:40:00 +02:00
2025-03-03 13:57:02 +01:00
def delete_alias ( alias ) :
status_e = None
status_i = None
now = datetime . now ( ) . strftime ( " % m- %d - % Y % H: % M " )
connection = get_settings ( ' connection ' )
check = checklist ( alias )
if check [ 0 ] == None and check [ 1 ] == None :
print ( ' \n [b]Error[/b] : The alias %s not found ' )
exit ( 0 )
if check [ 0 ] or check [ 1 ] == True :
alias_server_id = alias_id ( alias )
data = { ' id ' : alias_server_id }
delete_data = json . dumps ( data )
if check [ 0 ] == True and alias_server_id != None :
req = httpx . post ( ' https:// ' + connection [ ' server ' ] + ' /api/v1/delete/alias ' ,
headers = { " Content-Type " : " application/json " ,
' X-API-Key ' : connection [ ' key ' ]
} ,
data = delete_data
)
data = req . json ( )
code = str ( req )
if code . find ( ' 200 ' ) != - 1 :
status_e = True
else :
status_e = None
if check [ 1 ] == True :
cursor = conn . cursor ( )
cursor . execute ( ' DELETE from aliases where id = ? ' , ( alias_server_id , ) )
conn . commit ( )
status_i = True
if status_e == True and status_i == True :
logging . info ( now + ' - Info : alias %s deleted from the mailcow instance %s and Local DB ' % ( alias , connection [ ' server ' ] ) )
print ( ' \n [b]Info[/b] : alias %s deleted from the mailcow instance %s and local DB ' % ( alias , connection [ ' server ' ] ) )
if status_e == True and status_i == None :
logging . info ( now + ' - Info : alias %s deleted from the mailcow instance %s . ' % ( alias , connection [ ' server ' ] ) )
print ( ' \n [b]Info[/b] : alias %s deleted from the mailcow instance %s . ' % ( alias , connection [ ' server ' ] ) )
if status_e == None and status_i == True :
logging . info ( now + ' - Info : alias %s deleted from the local database. ' % ( alias ) )
print ( ' \n [b]Info[/b] : alias %s deleted from the local database. ' % ( alias ) )
2024-04-10 13:40:00 +02:00
2025-03-03 13:57:02 +01:00
def create_timed ( username , domain ) :
now = datetime . now ( ) . strftime ( " % m- %d - % Y % H: % M " )
connection = get_settings ( ' connection ' )
data = { ' username ' : username , ' domain ' : domain , ' description ' : ' malias v ' + app_version }
data_json = json . dumps ( data )
req = httpx . post ( ' https:// ' + connection [ ' server ' ] + ' /api/v1/add/time_limited_alias ' , data = data_json ,
headers = { " Content-Type " : " application/json " ,
' X-API-Key ' : connection [ ' key ' ]
}
)
response = json . loads ( req . text )
if response [ 0 ] [ ' type ' ] == ' danger ' and response [ 0 ] [ ' msg ' ] == ' domain_invalid ' :
logging . error ( now + ' - Error : the domain %s does not exist. ' % ( domain ) )
print ( ' [b][red]Error[/red][/b] : the domain %s does not exist. ' % ( domain ) )
exit ( 0 )
if response [ 0 ] [ ' type ' ] == ' danger ' and response [ 0 ] [ ' msg ' ] == ' access_denied ' :
logging . error ( now + ' - Error : something went wrong. The server responded with access denied. ' )
print ( ' [b][red]Error[/red][/b] : something went wrong. The server responded with [b]access denied[/b]. ' )
exit ( 0 )
alias = get_last_timed ( username )
2025-03-04 10:14:27 +01:00
validity = unix_to_datetime ( alias [ ' validity ' ] )
2025-03-03 13:57:02 +01:00
print ( ' The timed alias %s was created. The alias is valid until %s UTC \n ' % ( alias [ ' address ' ] , validity ) )
2024-04-10 13:40:00 +02:00
cursor = conn . cursor ( )
2025-03-03 13:57:02 +01:00
cursor . execute ( ' INSERT INTO timedaliases values(?,?,?,?) ' , ( alias [ ' validity ' ] , alias [ ' address ' ] , username , validity ) )
2024-04-10 13:40:00 +02:00
conn . commit ( )
2025-03-03 13:57:02 +01:00
logging . info ( now + ' - Info : timed alias %s created for %s and valid too %s UTC on the mailcow instance %s ' % ( alias [ ' address ' ] , username , validity , connection [ ' server ' ] ) )
2023-04-11 13:01:37 +02:00
2023-04-10 15:07:53 +02:00
2025-03-03 13:57:02 +01:00
def check_local_db ( alias_id ) :
cursor = conn . cursor ( )
cursor . execute ( ' SELECT count(*) FROM aliases where id = ? ' , ( alias_id , ) )
count = cursor . fetchone ( ) [ 0 ]
return count
2024-04-10 13:40:00 +02:00
2023-04-10 15:07:53 +02:00
2025-03-03 13:57:02 +01:00
def list_alias ( ) :
now = datetime . now ( ) . strftime ( " % m- %d - % Y % H: % M " )
connection = get_settings ( ' connection ' )
cursor = conn . cursor ( )
req = httpx . get ( ' https:// ' + connection [ ' server ' ] + ' /api/v1/get/alias/all ' ,
headers = { " Content-Type " : " application/json " ,
' X-API-Key ' : connection [ ' key ' ]
}
)
data = req . json ( )
i = 0
l = 0
print ( ' \n [b]malias[/b] - All aliases on %s ([b]*[/b] also in local db) ' % ( connection [ ' server ' ] ) )
print ( ' ================================================================== ' )
for search in data :
the_alias = data [ i ] [ ' address ' ] . ljust ( 20 , ' ' )
the_goto = data [ i ] [ ' goto ' ] . ljust ( 20 , ' ' )
cursor . execute ( ' SELECT count(*) FROM aliases where alias like ? or goto like ? ' , ( data [ i ] [ ' address ' ] , data [ i ] [ ' address ' ] , ) )
count = cursor . fetchone ( ) [ 0 ]
if count > = 1 :
print ( the_alias + ' \t goes to \t \t ' + the_goto + ' \t [b]*[/b] ' )
l = l + 1
else :
print ( the_alias + ' \t goes to \t \t ' + the_goto )
i = i + 1
print ( ' \n \n Total number of aliases %s on instance [b] %s [/b] and %s on [b]local DB[/b]. ' % ( str ( i ) , connection [ ' server ' ] , str ( l ) ) )
print ( ' \n ' + footer )
2023-04-10 15:07:53 +02:00
2025-03-03 13:57:02 +01:00
def export_data ( ) :
connection = get_settings ( ' connection ' )
cursor = conn . cursor ( )
req = httpx . get ( ' https:// ' + connection [ ' server ' ] + ' /api/v1/get/alias/all ' ,
headers = { " Content-Type " : " application/json " ,
' X-API-Key ' : connection [ ' key ' ]
}
)
data = req . json ( )
with open ( " alias.json " , " w " ) as outfile :
json . dump ( data , outfile , ensure_ascii = False , indent = 4 )
2023-04-11 13:01:37 +02:00
2025-03-04 10:14:27 +01:00
def list_timed_aliases ( account ) :
connection = get_settings ( ' connection ' )
req = httpx . get ( ' https:// ' + connection [ ' server ' ] + ' /api/v1/get/time_limited_aliases/ ' + account ,
headers = { " Content-Type " : " application/json " ,
' X-API-Key ' : connection [ ' key ' ]
}
)
data = req . json ( )
i = 0
print ( ' \n [b]malias[/b] - Timed aliases on %s for %s ' % ( connection [ ' server ' ] , account ) )
print ( ' ========================================================================================================== ' )
for data in data :
the_alias = data [ ' address ' ] . ljust ( 30 , ' ' )
the_goto = data [ ' goto ' ] . ljust ( 20 , ' ' )
the_validity = unix_to_datetime ( data [ ' validity ' ] )
print ( the_alias + ' \t goes to \t \t ' + the_goto + ' Valid to: ' + str ( the_validity ) )
i = i + 1
#print('\n\nTotal number of timed aliases on instance [b]%s[/b] for account.' %(connection['server'],account))
print ( ' \n ' + footer )
2023-04-11 13:01:37 +02:00
2025-03-03 13:57:02 +01:00
# For Testing purposes
2024-04-10 13:40:00 +02:00
2025-03-03 13:57:02 +01:00
def list_all ( ) :
connection = get_settings ( ' connection ' )
req = httpx . get ( ' https:// ' + connection [ ' server ' ] + ' /api/v1/get/alias/all ' ,
headers = { " Content-Type " : " application/json " ,
' X-API-Key ' : connection [ ' key ' ]
}
)
data = req . json ( )
print ( data )
2023-04-16 18:04:24 +02:00
2025-03-03 13:57:02 +01:00
def updatedb ( ) :
# Function for updatimg DB when we have to
2023-10-03 10:15:50 +02:00
2025-03-03 13:57:02 +01:00
# 26.02.2025
# Placeholder for future updates and functions.
exit ( 1 )
2023-04-10 15:07:53 +02:00
2025-03-03 13:57:02 +01:00
conn = connect_database ( )
parser = argparse . ArgumentParser ( prog = ' malias ' ,
description = ' Malias is an application for adding, creating, and deleting aliases on a Mailcow instance. \n \n Use the issues section in the git repo for any problems or suggestions. https://gitlab.pm/rune/malias ' ,
formatter_class = RawTextHelpFormatter ,
epilog = ' Making mailcow easier... ' )
2023-04-16 18:04:24 +02:00
parser . add_argument ( ' -c ' , ' --copy ' , help = ' Copy alias data from mailcow server to local DB. \n \n ' ,
required = False , action = ' store_true ' )
2025-03-03 13:57:02 +01:00
parser . add_argument ( ' -s ' , ' --set ' , help = ' Set connection information. \n \n ' ,
nargs = 2 , metavar = ( ' server ' , ' APIKey ' ) , 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 ( ' -f ' , ' --find ' , help = ' Search for alias. \n \n ' ,
nargs = 1 , metavar = ( ' alias@domain.com ' ) , required = False , action = " append " )
parser . add_argument ( ' -d ' , ' --delete ' , help = ' Delete alias. \n \n ' ,
nargs = 1 , metavar = ( ' alias@domain.com ' ) , required = False , action = " append " )
parser . add_argument ( ' -t ' , ' --timed ' , help = ' Add new time limited alias for user on domain. \n The user@domain.com is where you want the alias to be delivered to. \n The domain.com is which domain to use when creating the timed-alias. \n One year validity \n \n ' ,
nargs = 2 , metavar = ( ' user@domain.com ' , ' domain.com ' ) , required = False , action = " append " )
2025-03-04 10:14:27 +01:00
parser . add_argument ( ' -w ' , ' --alias ' , help = ' List timed (temprary) aliases connected toone account. \n \n ' ,
nargs = 1 , metavar = ( ' alias@domain.com ' ) , required = False , action = " append " )
2023-04-16 18:04:24 +02:00
parser . add_argument ( ' -l ' , ' --list ' , help = ' List all aliases on the Mailcow instance. \n \n ' ,
2023-04-13 09:29:07 +02:00
required = False , action = ' store_true ' )
2023-09-01 11:22:54 +02:00
parser . add_argument ( ' -o ' , ' --domains ' , help = ' List all mail domains on the Mailcow instance. \n \n ' ,
required = False , action = ' store_true ' )
2025-03-03 13:57:02 +01:00
parser . add_argument ( ' -e ' , ' --export ' , help = ' List all mail domains on the Mailcow instance. \n \n ' ,
required = False , action = ' store_true ' )
parser . add_argument ( ' -v ' , ' --version ' , help = ' Show current version and information \n \n ' ,
required = False , action = ' store_true ' )
2023-09-01 11:22:54 +02:00
2023-04-16 18:04:24 +02:00
2023-04-10 15:07:53 +02:00
args = vars ( parser . parse_args ( ) )
2025-03-03 13:57:02 +01:00
if args [ ' copy ' ] :
copy_data ( )
elif args [ ' set ' ] :
set_conection_info ( args [ ' set ' ] [ 0 ] [ 0 ] , args [ ' set ' ] [ 0 ] [ 1 ] )
2023-04-11 13:01:37 +02:00
elif args [ ' add ' ] :
create ( args [ ' add ' ] [ 0 ] [ 0 ] , args [ ' add ' ] [ 0 ] [ 1 ] )
2025-03-03 13:57:02 +01:00
elif args [ ' find ' ] :
search ( args [ ' find ' ] [ 0 ] [ 0 ] )
2023-10-03 10:15:50 +02:00
elif args [ ' version ' ] :
2024-04-10 13:40:00 +02:00
show_current_info ( )
2025-03-03 13:57:02 +01:00
elif args [ ' delete ' ] :
delete_alias ( args [ ' delete ' ] [ 0 ] [ 0 ] )
elif args [ ' timed ' ] :
create_timed ( args [ ' timed ' ] [ 0 ] [ 0 ] , args [ ' timed ' ] [ 0 ] [ 1 ] )
2025-03-04 10:14:27 +01:00
elif args [ ' alias ' ] :
list_timed_aliases ( args [ ' alias ' ] [ 0 ] [ 0 ] )
2023-04-16 18:04:24 +02:00
elif args [ ' list ' ] :
list_alias ( )
2023-09-01 11:22:54 +02:00
elif args [ ' domains ' ] :
2023-09-05 11:36:39 +02:00
get_mail_domains ( True )
2025-03-03 13:57:02 +01:00
elif args [ ' export ' ] :
export_data ( )
2023-04-10 15:07:53 +02:00
else :
2024-04-10 13:40:00 +02:00
print ( ' \n \n Eh, sorry! I need something more to help you! If you write [b]malias -h[/b] I \' ll show a help screen to get you going!!! \n \n \n ' )
2025-03-04 10:14:27 +01:00