]> gitweb.michael.orlitzky.com - mailshears.git/blob - lib/common/postfixadmin_plugin.rb
mailshears.gemspec: bump version to 0.1.0
[mailshears.git] / lib / common / postfixadmin_plugin.rb
1 require 'common/domain'
2 require 'common/plugin'
3 require 'common/user'
4 require 'pg'
5
6 # Code that all Postfixadmin plugins ({PostfixadminPrune},
7 # {PostfixadminRm}, {PostfixadminMv}) share.
8 #
9 module PostfixadminPlugin
10
11 # We implement the Plugin "interface."
12 include Plugin
13
14 # Initialize this Postfixadmin {Plugin} with values in *cfg*.
15 #
16 # @param cfg [Configuration] the configuration for this plugin.
17 #
18 def initialize(cfg)
19 @db_hash = {
20 :host => cfg.postfixadmin_dbhost,
21 :port => cfg.postfixadmin_dbport,
22 :options => cfg.postfixadmin_dbopts,
23 :dbname => cfg.postfixadmin_dbname,
24 :user => cfg.postfixadmin_dbuser,
25 :password => cfg.postfixadmin_dbpass }
26 end
27
28
29 # Obtain a list of domains from Postfixadmin. This is more efficient
30 # than the {Plugin} default implementation because domains have
31 # their own table in the database and we can easily select them
32 # rather than filtering the list of users.
33 #
34 # @return [Array<Domain>] a list of the domains in Postfixadmin.
35 #
36 def list_domains()
37 domains = []
38
39 connection = PG::Connection.new(@db_hash)
40
41 # 'ALL' is a magic domain, and we don't want it.
42 sql_query = "SELECT domain FROM domain WHERE domain <> 'ALL';"
43
44 begin
45 connection.sync_exec(sql_query) do |result|
46 domains = result.field_values('domain')
47 end
48 ensure
49 # Make sure the connection gets closed even if the query explodes.
50 connection.close()
51 end
52
53 return domains.map{ |d| Domain.new(d) }
54 end
55
56
57 # Return a list of Postfixadmin users.
58 #
59 # @return [Array<User>] a list of users contained in the
60 # Postfixadmin database.
61 #
62 def list_users()
63 users = []
64
65 connection = PG::Connection.new(@db_hash)
66
67 sql_query = 'SELECT username FROM mailbox;'
68
69 begin
70 connection.sync_exec(sql_query) do |result|
71 users = result.field_values('username')
72 end
73 ensure
74 # Make sure the connection gets closed even if the query explodes.
75 connection.close()
76 end
77
78 return users.map{ |u| User.new(u) }
79 end
80
81
82
83 # Efficiently list all Postfixadmin users belonging to the given
84 # Postfixadmin *domains*.
85 #
86 # @param domains [Array<Domain>] the domains whose users we want.
87 #
88 # @return [Array<User>] a list of {User} objects belonging to
89 # *domains* for this plugin.
90 #
91 def list_domains_users(domains)
92 usernames = []
93 return usernames if domains.length() == 0
94
95 connection = PG::Connection.new(@db_hash)
96
97 # The number of parameters that we'll pass into our prepared query
98 # is the number of domains that we're given. It's important that
99 # we have at least one domain here.
100 params = 1.upto(domains.length()).map{ |i| '$' + i.to_s() }.join(',')
101 sql_query = "SELECT username FROM mailbox WHERE domain IN (#{params});"
102
103 begin
104 # Now replace each Domain with its string representation and pass
105 # those in as our individual parameters.
106 connection.sync_exec_params(sql_query, domains.map{ |d| d.to_s() }) do |result|
107 usernames = result.field_values('username')
108 end
109 ensure
110 # Make sure the connection gets closed even if the query explodes.
111 connection.close()
112 end
113
114 return usernames.map{ |u| User.new(u) }
115 end
116
117
118 # Get a list of all Postfixadmin aliases as a <tt>from => to</tt>
119 # hash. This is useful for testing, since aliases should be removed
120 # when either the "from user" or "to user" are removed.
121 #
122 # @return [Hash] all aliases known to Postfixadmin in the form of a
123 # <tt>from => to</tt> hash.
124 #
125 def list_aliases()
126 aliases = []
127
128 connection = PG::Connection.new(@db_hash)
129
130 sql_query = 'SELECT address,goto FROM alias;'
131
132 begin
133 results = connection.sync_exec(sql_query)
134 results.each do |row|
135 # row should be a hash
136 aliases << row
137 end
138 ensure
139 # Make sure the connection gets closed even if the query explodes.
140 connection.close()
141 end
142
143 return aliases
144 end
145
146
147 # A fast implementation of the "does this domain exist?"
148 # operation. It only queries the database for the existence of
149 # *domain* rather than a list of all domains (which is the default
150 # implementation).
151 #
152 # @param domain [Domain] the domain whose existence is in question.
153 #
154 # @return [Boolean] true if *domain* exists in the Postfixadmin
155 # database and false otherwise.
156 #
157 def domain_exists(domain)
158 count = 0
159
160 connection = PG::Connection.new(@db_hash)
161
162 sql_query = 'SELECT COUNT(domain) as count FROM domain WHERE domain = $1;'
163
164 begin
165 connection.sync_exec_params(sql_query, [domain.to_s()]) do |result|
166 return false if result.ntuples() < 1
167 count = result.getvalue(0,0).to_i()
168
169 return false if count.nil?
170 end
171 ensure
172 # Make sure the connection gets closed even if the query explodes.
173 connection.close()
174 end
175
176 return (count > 0)
177 end
178
179 end