#
# mailshears, to prune unused mail directories.
#
-# Mail accounts for virtual hosts are stored in SQL, and managed by
+# Mail users for virtual hosts are stored in SQL, and managed by
# Postfixadmin. However, the physical directories are handled by
# Postfix/Dovecot and are left untouched by Postfixadmin. This is good
# for security, but comes at a cost: Postfixadmin can't remove a
# user's mail directory when his or her account is deleted.
#
-# This program compares the list of filesystem accounts with the ones
-# in the database. It outputs any accounts that exist in the
+# This program compares the list of filesystem users with the ones
+# in the database. It outputs any users that exist in the
# filesystem, but not the database.
#
require "#{mode_name}/#{mode_name}_dummy_runner"
def make_header(plugin_name)
- # The header that we output before the list of domains/accounts.
+ # The header that we output before the list of domains/users.
# Just the path of this script, the current time, and the plugin name.
exe = File.basename($PROGRAM_NAME)
header = "#{exe}, "
-* Error reporting sucks, and when a domain or account doesn't exist we
- should be able to say so. The describe_domain/account functions
+* Error reporting sucks, and when a domain or user doesn't exist we
+ should be able to say so. The describe_domain/user functions
should also work better. For plugins that don't implement domains,
- we can return a (count of?) list of accounts, or fall back to the
- account deletion descriptions.
-
-* Rename "account" to "user" everywhere.
+ we can return a (count of?) list of users, or fall back to the
+ user deletion descriptions.
* Implement "mv".
end
- def describe_account(account)
- if self.user_exists(account)
- return "Username: #{account}"
+ def describe_user(user)
+ if self.user_exists(user)
+ return "Username: #{user}"
else
return 'User not found'
end
end
- def describe_account(account)
- principal_id = self.get_principal_id(account)
+ def describe_user(user)
+ principal_id = self.get_principal_id(user)
if principal_id.nil?
return 'User not found'
protected;
- def get_principal_id(account)
+ def get_principal_id(user)
principal_id = nil
begin
sql_query += " ON principal.user_no = usr.user_no) "
sql_query += "WHERE usr.username = $1;"
- connection.query(sql_query, [account]) do |result|
+ connection.query(sql_query, [user]) do |result|
if result.num_tuples > 0
principal_id = result[0]['principal_id']
end
end
end
- def describe_account(account)
+ def describe_user(user)
begin
- account_path = get_account_path(account)
- return account_path
- rescue NonexistentAccountError => e
+ user_path = get_user_path(user)
+ return user_path
+ rescue NonexistentUserError => e
return "Doesn't exist: #{e.to_s}"
end
end
end
- def get_account_path(account)
- # Return the filesystem path of this account's mailbox.
- # Only works if the account exists!
- if not account.include?('@')
- msg = "#{account}: Accounts must contain an '@' symbol."
- raise InvalidAccountError.new(msg)
+ def get_user_path(user)
+ # Return the filesystem path of this user's mailbox.
+ # Only works if the user exists!
+ if not user.include?('@')
+ msg = "#{user}: Users must contain an '@' symbol."
+ raise InvalidUserError.new(msg)
end
- account_parts = account.split('@')
- user_part = account_parts[0]
- domain_part = account_parts[1]
+ user_parts = user.split('@')
+ local_part = user_parts[0]
+ domain_part = user_parts[1]
begin
domain_path = get_domain_path(domain_part)
rescue NonexistentDomainError
- raise NonexistentAccountError.new(account)
+ raise NonexistentUserError.new(user)
end
- account_path = File.join(domain_path, user_part)
+ user_path = File.join(domain_path, local_part)
- if File.directory?(account_path)
- return account_path
+ if File.directory?(user_path)
+ return user_path
else
- raise NonexistentAccountError.new(account)
+ raise NonexistentUserError.new(user)
end
end
end
def list_domains_users(domains)
- accounts = []
+ users = []
domains.each do |domain|
begin
# Throws a NonexistentDomainError if the domain's path
# doesn't exist on the filesystem. In this case, we want
- # to report zero accounts.
+ # to report zero users.
domain_path = get_domain_path(domain)
usernames = Filesystem.get_subdirs(domain_path)
usernames.each do |username|
- accounts << "#{username}@#{domain}"
+ users << "#{username}@#{domain}"
end
rescue NonexistentDomainError
# Party hard.
end
end
- return accounts
+ return users
end
end
-# Perhaps surprisingly, used to indicate that an account name is
+# Perhaps surprisingly, used to indicate that an user name is
# invalid.
-class InvalidAccountError < StandardError
+class InvalidUserError < StandardError
end
-# Used to indicate that an account does not exist on the filesystem.
-class NonexistentAccountError < StandardError
+# Used to indicate that an user does not exist on the filesystem.
+class NonexistentUserError < StandardError
end
raise NotImplementedError
end
- def describe_account(account)
- # Provide a "description" of the account. This is output along
+ def describe_user(user)
+ # Provide a "description" of the user. This is output along
# with the domain name and can be anything of use to the system
# administrator.
raise NotImplementedError
end
- def describe_account(account)
+ def describe_user(user)
# There's no other unique identifier in PostfixAdmin
- return account
+ return user
end
def list_users()
- accounts = []
+ users = []
# Just assume PostgreSQL for now.
begin
# deliver to that address; it's not an alias."
sql_query = 'SELECT username FROM mailbox;'
connection.query(sql_query) do |result|
- accounts = result.field_values('username')
+ users = result.field_values('username')
end
connection.close()
rescue PGError => e
raise DatabaseError.new(e)
end
- return accounts
+ return users
end
return domain
end
- def describe_account(account)
- user_id = self.get_user_id(account)
+ def describe_user(user)
+ user_id = self.get_user_id(user)
if user_id.nil?
return 'User not found'
protected;
- def get_user_id(account)
+ def get_user_id(user)
user_id = nil
begin
sql_query = "SELECT user_id FROM users WHERE username = $1;"
- connection.query(sql_query, [account]) do |result|
+ connection.query(sql_query, [user]) do |result|
if result.num_tuples > 0
user_id = result[0]['user_id']
end
def run(plugin, src, dst)
if src.include?('@') then
- puts "Would move account: #{src} to #{dst}"
+ puts "Would move user: #{src} to #{dst}"
else
puts "Would move domain: #{src} to #{dst}"
end
module MvPlugin
#
- # Plugins for moving (renaming) accounts.
+ # Plugins for moving (renaming) users.
#
def MvPlugin.included(c)
raise NotImplementedError
end
- def mv_account(from, to)
- # Rename the given account.
+ def mv_user(from, to)
+ # Rename the given user.
raise NotImplementedError
end
# AgenDAV doesn't have a concept of domains.
end
- def mv_account(from, to)
+ def mv_user(from, to)
sql_queries = ['UPDATE prefs SET username = $1 WHERE username $2;']
sql_queries << 'UPDATE shared SET user_from = $1 WHERE user_from = $2;'
sql_queries << 'UPDATE shared SET user_which = $1 WHERE user_which = $2;'
end
- def mv_account(from, to)
+ def mv_user(from, to)
# Delete the given username. DAViCal uses foreign keys properly
# and only supports postgres, so we let the ON UPDATE CASCADE
# trigger handle most of the work.
FileUtils.mv(from_path, to_path)
end
- def mv_account(from, to)
- from_path = self.get_account_path(from)
- to_path = self.get_account_path(to)
+ def mv_user(from, to)
+ from_path = self.get_user_path(from)
+ to_path = self.get_user_path(to)
FileUtils.mv(from_path, to_path)
end
# Roundcube doesn't have a concept of domains.
end
- def mv_account(from, to)
+ def mv_user(from, to)
sql_queries = ['UPDATE users SET username = $1 WHERE username = $2;']
begin
def get_leftover_domains(db_domains)
# AgenDAV doesn't have a concept of domains. We could parse the
# usernames to see what domains are present, but the point is
- # moot: all leftover accounts will be pruned anyway.
+ # moot: all leftover users will be pruned anyway.
return []
end
- def get_leftover_accounts(db_accounts)
+ def get_leftover_users(db_users)
# Get a list of all users who have logged in to AgenDAV.
- ad_accounts = self.list_users()
- return ad_accounts - db_accounts
+ ad_users = self.list_users()
+ return ad_users - db_users
end
end
def get_leftover_domains(db_domains)
# DAViCal doesn't have a concept of domains. We could parse the
# usernames to see what domains are present, but the point is
- # moot: all leftover accounts will be pruned anyway.
+ # moot: all leftover users will be pruned anyway.
return []
end
- def get_leftover_accounts(db_accounts)
+ def get_leftover_users(db_users)
# Get a list of all users who have logged in to DAViCal.
- davical_accounts = self.list_users()
- return davical_accounts - db_accounts
+ davical_users = self.list_users()
+ return davical_users - db_users
end
return (fs_domains - db_domains)
end
- def get_leftover_accounts(db_accounts)
- # Get the list of accounts according to the filesystem.
+ def get_leftover_users(db_users)
+ # Get the list of users according to the filesystem.
fs_domains = self.list_domains()
- fs_accounts = self.list_domains_users(fs_domains)
+ fs_users = self.list_domains_users(fs_domains)
- # And return the accounts on the filesystem that aren't in the DB.
- return (fs_accounts - db_accounts)
+ # And return the users on the filesystem that aren't in the DB.
+ return (fs_users - db_users)
end
end
require 'rm/plugins/postfixadmin'
class PostfixadminPrune < PostfixadminRm
- # We don't need the ability to remove "left over" accounts or
+ # We don't need the ability to remove "left over" users or
# domains, since "left over" is with respect to what's in
# PostfixAdmin. In other words, the other plugins check themselves
# against PostfixAdmin, it doesn't make sense to check PostfixAdmin
def get_leftover_domains(db_domains)
# Roundcube doesn't have a concept of domains. We could parse the
# usernames to see what domains are present, but the point is
- # moot: all leftover accounts will be pruned anyway.
+ # moot: all leftover users will be pruned anyway.
return []
end
- def get_leftover_accounts(db_accounts)
+ def get_leftover_users(db_users)
# Get a list of all users who have logged in to Roundcube.
- rc_accounts = self.list_users()
- return rc_accounts - db_accounts
+ rc_users = self.list_users()
+ return rc_users - db_users
end
end
db_users = pfa.list_users()
db_domains = pfa.list_domains()
- leftover_users = plugin.get_leftover_accounts(db_users)
+ leftover_users = plugin.get_leftover_users(db_users)
leftover_domains = plugin.get_leftover_domains(db_domains)
leftover_users.each do |user|
- user_description = plugin.describe_account(user)
+ user_description = plugin.describe_user(user)
report(plugin, "Would remove user: #{user} (#{user_description})")
end
include RmPlugin
#
- # Plugins for the removal of leftover non-PostfixAdmin accounts,
- # i.e. after an account has been removed from the PostfixAdmin
+ # Plugins for the removal of leftover non-PostfixAdmin users,
+ # i.e. after an user has been removed from the PostfixAdmin
# database.
#
raise NotImplementedError
end
- def get_leftover_accounts(db_accounts)
- # Given a list of accounts, determine which accounts belonging to
+ def get_leftover_users(db_users)
+ # Given a list of users, determine which users belonging to
# this plugin are not contained in the given list.
raise NotImplementedError
end
db_users = pfa.list_users()
db_domains = pfa.list_domains()
- leftover_users = plugin.get_leftover_accounts(db_users)
+ leftover_users = plugin.get_leftover_users(db_users)
leftover_domains = plugin.get_leftover_domains(db_domains)
leftover_users.each do |user|
- user_description = plugin.describe_account(user)
- plugin.delete_account(user)
+ user_description = plugin.describe_users(user)
+ plugin.delete_user(user)
report(plugin, "Removed user: #{user} (#{user_description})")
end
include RmPlugin
- def delete_account(account)
+ def delete_user(user)
# Delete the given username and any records in other tables
# belonging to it.
- raise NonexistentAccountError.new(account) if not user_exists(account)
+ raise NonexistentUserError.new(user) if not user_exists(user)
sql_queries = ['DELETE FROM prefs WHERE username = $1;']
sql_queries << 'DELETE FROM shared WHERE user_from = $1;'
@db_pass)
sql_queries.each do |sql_query|
- connection.query(sql_query, [account])
+ connection.query(sql_query, [user])
end
connection.close()
include RmPlugin
- def delete_account(account)
+ def delete_user(user)
# Delete the given username. DAViCal uses foreign keys properly
# and only supports postgres, so we let the ON DELETE CASCADE
# trigger handle most of the work.
- raise NonexistentAccountError.new(account) if not user_exists(account)
+ raise NonexistentUserError.new(user) if not user_exists(user)
sql_queries = ['DELETE FROM usr WHERE username = $1']
@db_pass)
sql_queries.each do |sql_query|
- connection.query(sql_query, [account])
+ connection.query(sql_query, [user])
end
connection.close()
FileUtils.rm_r(domain_path)
end
- def delete_account(account)
+ def delete_user(user)
# Will raise an exception if the path doesn't exist.
- account_path = self.get_account_path(account)
- FileUtils.rm_r(account_path)
+ user_path = self.get_user_path(user)
+ FileUtils.rm_r(user_path)
end
end
include RmPlugin
- def delete_account(account)
- raise NonexistentAccountError.new(account) if not user_exists(account)
+ def delete_user(user)
+ raise NonexistentUserError.new(user) if not user_exists(user)
sql_queries = ['DELETE FROM alias WHERE address = $1;']
- # Wipe out any aliases pointed at our account.
+ # Wipe out any aliases pointed at our user.
sql_queries << "UPDATE alias SET goto=REPLACE(goto, $1, '');"
sql_queries << 'DELETE FROM mailbox WHERE username = $1;'
sql_queries << 'DELETE FROM quota WHERE username = $1;'
@db_pass)
sql_queries.each do |sql_query|
- connection.query(sql_query, [account])
+ connection.query(sql_query, [user])
end
# The earlier alias update query will leave things like
include RoundcubePlugin
include RmPlugin
- def delete_account(account)
+ def delete_user(user)
# Delete the given username and any records in other tables
# belonging to it.
- raise NonexistentAccountError.new(account) if not user_exists(account)
+ raise NonexistentUserError.new(user) if not user_exists(user)
- user_id = self.get_user_id(account)
+ user_id = self.get_user_id(user)
# The Roundcube developers were nice enough to include
# DBMS-specific install and upgrade scripts, so Postgres can take
def run(plugin, *targets)
targets.each do |target|
if target.include?('@') then
- user_description = plugin.describe_account(target)
+ user_description = plugin.describe_user(target)
report(plugin, "Would remove user: #{user} (#{user_description})")
else
domain_description = plugin.describe_domain(target)
module RmPlugin
#
- # Plugins for the removal of accounts.
+ # Plugins for the removal of users.
#
def RmPlugin.included(c)
raise NonexistentDomainError.new(domain) if usernames.empty?
usernames.each do |u|
- delete_account(u)
+ delete_user(u)
end
end
- def delete_account(account)
- # Delete the given account.
+ def delete_user(user)
+ # Delete the given user.
raise NotImplementedError
end
def run(plugin, *targets)
targets.each do |target|
- # Why think too hard? An account has an @, a domain doesn't.
+ # Why think too hard? An user has an @, a domain doesn't.
if target.include?('@') then
begin
- account_description = plugin.describe_account(target)
- plugin.delete_account(target)
- report(plugin, "Removed account: #{target} (#{account_description})")
+ user_description = plugin.describe_user(target)
+ plugin.delete_user(target)
+ report(plugin, "Removed user: #{target} (#{user_description})")
- rescue NonexistentAccountError => e
- report(plugin, "Account not found: #{e.to_s}")
+ rescue NonexistentUserError => e
+ report(plugin, "User not found: #{e.to_s}")
rescue StandardError => e
- report(plugin, "There was an error removing the account: #{e.to_s}")
+ report(plugin, "There was an error removing the user: #{e.to_s}")
Kernel.exit(ExitCodes::DATABASE_ERROR)
end
else
plugin.delete_domain(target)
report(plugin, "Removed domain: #{target} (#{domain_description})")
- rescue NonexistentAccountError => e
+ rescue NonexistentUserError => e
# Can happen in the usernames.each... block.
- report(plugin, "Account not found: #{e.to_s}")
+ report(plugin, "User not found: #{e.to_s}")
rescue NonexistentDomainError => e
report(plugin, "Domain not found: #{e.to_s}")
rescue StandardError => e