require 'common/domain' require 'common/plugin' require 'common/user' require 'pg' # Code that all Postfixadmin plugins ({PostfixadminPrune}, # {PostfixadminRm}, {PostfixadminMv}) share. # module PostfixadminPlugin # We implement the Plugin "interface." include Plugin # Initialize this Postfixadmin {Plugin} with values in *cfg*. # # @param cfg [Configuration] the configuration for this plugin. # def initialize(cfg) @db_hash = { :host => cfg.postfixadmin_dbhost, :port => cfg.postfixadmin_dbport, :options => cfg.postfixadmin_dbopts, :tty => cfg.postfixadmin_dbtty, :dbname => cfg.postfixadmin_dbname, :user => cfg.postfixadmin_dbuser, :password => cfg.postfixadmin_dbpass } end # Obtain a list of domains from Postfixadmin. This is more efficient # than the {Plugin} default implementation because domains have # their own table in the database and we can easily select them # rather than filtering the list of users. # # @return [Array] a list of the domains in Postfixadmin. # def list_domains() domains = [] connection = PG::Connection.new(@db_hash) # 'ALL' is a magic domain, and we don't want it. sql_query = "SELECT domain FROM domain WHERE domain <> 'ALL';" begin connection.query(sql_query) do |result| domains = result.field_values('domain') end ensure # Make sure the connection gets closed even if the query explodes. connection.close() end return domains.map{ |d| Domain.new(d) } end # Return a list of Postfixadmin users. # # @return [Array] a list of users contained in the # Postfixadmin database. # def list_users() users = [] connection = PG::Connection.new(@db_hash) sql_query = 'SELECT username FROM mailbox;' begin connection.query(sql_query) do |result| users = result.field_values('username') end ensure # Make sure the connection gets closed even if the query explodes. connection.close() end return users.map{ |u| User.new(u) } end # Efficiently list all Postfixadmin users belonging to the given # Postfixadmin *domains*. # # @param domains [Array] the domains whose users we want. # # @return [Array] a list of {User} objects belonging to # *domains* for this plugin. # def list_domains_users(domains) usernames = [] return usernames if domains.length() == 0 connection = PG::Connection.new(@db_hash) # The number of parameters that we'll pass into our prepared query # is the number of domains that we're given. It's important that # we have at least one domain here. params = 1.upto(domains.length()).map{ |i| '$' + i.to_s() }.join(',') sql_query = "SELECT username FROM mailbox WHERE domain IN (#{params});" begin # Now replace each Domain with its string representation and pass # those in as our individual parameters. connection.query(sql_query, domains.map{ |d| d.to_s() }) do |result| usernames = result.field_values('username') end ensure # Make sure the connection gets closed even if the query explodes. connection.close() end return usernames.map{ |u| User.new(u) } end # Get a list of all Postfixadmin aliases as a from => to # hash. This is useful for testing, since aliases should be removed # when either the "from user" or "to user" are removed. # # @return [Hash] all aliases known to Postfixadmin in the form of a # from => to hash. # def list_aliases() aliases = [] connection = PG::Connection.new(@db_hash) sql_query = 'SELECT address,goto FROM alias;' begin results = connection.query(sql_query) results.each do |row| # row should be a hash aliases << row end ensure # Make sure the connection gets closed even if the query explodes. connection.close() end return aliases end # A fast implementation of the "does this domain exist?" # operation. It only queries the database for the existence of # *domain* rather than a list of all domains (which is the default # implementation). # # @param domain [Domain] the domain whose existence is in question. # # @return [Boolean] true if *domain* exists in the Postfixadmin # database and false otherwise. # def domain_exists(domain) count = 0 connection = PG::Connection.new(@db_hash) sql_query = 'SELECT COUNT(domain) as count FROM domain WHERE domain = $1;' begin connection.query(sql_query, [domain.to_s()]) do |result| return false if result.ntuples() < 1 count = result.getvalue(0,0).to_i() return false if count.nil? end ensure # Make sure the connection gets closed even if the query explodes. connection.close() end return (count > 0) end end