X-Git-Url: http://gitweb.michael.orlitzky.com/?p=mailshears.git;a=blobdiff_plain;f=lib%2Frm%2Fplugins%2Fpostfixadmin.rb;h=c8e44abd2d9140b5a75d969078e31b6eb836aa02;hp=103912b648e71ce8edf02a6be0745d76cded190b;hb=b947ef8844f090eedd50be0383abe417d910bb1a;hpb=20b843bddcd73833d41f98ff79d92ef59bb4d81e diff --git a/lib/rm/plugins/postfixadmin.rb b/lib/rm/plugins/postfixadmin.rb index 103912b..c8e44ab 100644 --- a/lib/rm/plugins/postfixadmin.rb +++ b/lib/rm/plugins/postfixadmin.rb @@ -3,18 +3,39 @@ require 'pg' require 'common/postfixadmin_plugin' require 'rm/rm_plugin' + +# Handle the removal of users and domains from the Postfixadmin database. +# class PostfixadminRm include PostfixadminPlugin include RmPlugin - def delete_user(user) + # Remove *user* from the Postfixadmin database. This should remove + # him from _every_ table in which he is referenced. Unfortunately, + # Postfixadmin does not use foreign keys or ON DELETE CASCADE + # triggers so we need to delete the associated child table records + # ourselves. + # + # @param user [User] the user to remove. + # + def remove_user(user) raise NonexistentUserError.new(user.to_s()) if not user_exists(user) + # Remove aliases FROM our user to some other address. sql_queries = ['DELETE FROM alias WHERE address = $1;'] - # Wipe out any aliases pointed at our user. + + # Also delete aliases that point SOLELY TO our user. + sql_queries << "DELETE FROM alias WHERE goto = $1;" + + # But aliases don't need to point to a single user! If our user + # was part of a multi-recipient alias, we want to remove our user + # from the alias and leave the other recipients. If you're + # wondering about the leftover double-commas, look towards the end + # of the function. 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;' sql_queries << 'DELETE FROM quota2 WHERE username = $1;' @@ -23,68 +44,70 @@ class PostfixadminRm # Should be handled by a trigger, according to PostfixAdmin code. sql_queries << 'DELETE FROM vacation_notification WHERE on_vacation = $1;' - connection = PGconn.connect(@db_host, @db_port, @db_opts, @db_tty, - @db_name, @db_user, @db_pass) - - sql_queries.each do |sql_query| - connection.query(sql_query, [user.to_s()]) - end + connection = PG::Connection.new(@db_hash) - # The earlier alias update query will leave things like - # "foo@example.com,,bar@example.com" in the "goto" column. Now - # we fix it. We don't do it in the loop because query() craps - # out on the superfluous parameter. - sql_query = "UPDATE alias SET goto=REPLACE(goto, ',,', ',');" - connection.query(sql_query) + begin + sql_queries.each do |sql_query| + connection.query(sql_query, [user.to_s()]) + end - connection.close() + # The earlier alias update query will leave things like + # "foo@example.com,,bar@example.com" in the "goto" column. Now + # we fix it. We don't do it in the loop because query() craps + # out on the superfluous parameter. + sql_query = "UPDATE alias SET goto=REPLACE(goto, ',,', ',');" + connection.query(sql_query) + ensure + # Make sure the connection gets closed even if a query explodes. + connection.close() + end end - def delete_domain(domain) + # Remove *domain* from the Postfixadmin database. This should remove + # the domain from _every_ table in which it is referenced. It should + # also remove every user that belongs to the doomed domain + # Postfixadmin has some experimental support for triggers, but they + # don't do a very good job of cleaning up. Therefore we remove all + # users in the domain manually before removing the domain itself. + # + # Log entries (from the "log" table) are not removed since they may + # still contain valuable information (although they won't mention + # this removal). + # + # @param domain [Domain] the domain to remove. + # + def remove_domain(domain) raise NonexistentDomainError.new(domain.to_s()) if not domain_exists(domain) + # First remove all users belonging to the domain. This will handle + # alias updates and all the sensitive crap we need to do when + # removing a user. + users = list_domains_users([domain]) + users.each { |u| remove_user(u) } + + # The domain_admins table contains one record per domain + # (repeating the user as necessary), so this really is sufficient. sql_queries = ['DELETE FROM domain_admins WHERE domain = $1;'] + + # Some of the following queries should be redundant now that we've + # removed all users in the domain. sql_queries << 'DELETE FROM alias WHERE domain = $1;' sql_queries << 'DELETE FROM mailbox WHERE domain = $1;' sql_queries << 'DELETE FROM alias_domain WHERE alias_domain = $1;' - sql_queries << 'DELETE FROM log WHERE domain = $1;' sql_queries << 'DELETE FROM vacation WHERE domain = $1;' sql_queries << 'DELETE FROM domain WHERE domain = $1;' - connection = PGconn.connect(@db_host, @db_port, @db_opts, @db_tty, - @db_name, @db_user, @db_pass) + connection = PG::Connection.new(@db_hash) - sql_queries.each do |sql_query| - connection.query(sql_query, [domain.to_s()]) - end - - connection.close() - end - - - protected; - - def domain_exists(domain) - count = 0 - - connection = PGconn.connect(@db_host, @db_port, @db_opts, @db_tty, - @db_name, @db_user, @db_pass) - - sql_query = 'SELECT COUNT(domain) as count FROM domain WHERE domain = $1;' - connection.query(sql_query, [domain.to_s()]) do |result| - return false if result.ntuples() < 1 - begin - count = result.getvalue(0,0).to_i() - return false if count.nil? - rescue StandardError - return false + begin + sql_queries.each do |sql_query| + connection.query(sql_query, [domain.to_s()]) end + ensure + # Make sure the connection gets closed even if a query explodes. + connection.close() end - - connection.close() - - return (count > 0) end end