1 #!/usr/bin/ruby |
1 #!/usr/bin/ruby |
2 # |
2 # vim: set nosta noet ts=4 sw=4: |
3 # A Ruby interface to a single Ezmlm-idx mailing list directory |
3 # |
|
4 # A Ruby interface to a single Ezmlm-idx mailing list directory. |
4 # |
5 # |
5 # == Version |
6 # == Version |
6 # |
7 # |
7 # $Id$ |
8 # $Id$ |
8 # |
9 # |
9 # == Authors |
|
10 # |
|
11 # * Michael Granger <mgranger@laika.com> |
|
12 # * Jeremiah Jordan <jjordan@laika.com> |
|
13 # |
|
14 # :include: LICENSE |
|
15 # |
|
16 #--- |
10 #--- |
17 # |
|
18 # Please see the file LICENSE in the base directory for licensing details. |
|
19 # |
|
20 |
11 |
21 require 'pathname' |
12 require 'pathname' |
22 require 'ezmlm' |
13 require 'ezmlm' |
23 require 'tmail' |
14 require 'mail' |
24 |
15 |
25 |
16 |
26 ### A Ruby interface to an ezmlm-idx mailing list directory |
17 ### A Ruby interface to an ezmlm-idx mailing list directory |
|
18 ### |
27 class Ezmlm::List |
19 class Ezmlm::List |
28 |
20 |
29 ### Create a new Ezmlm::List object for the specified +listdir+, which should be |
21 ### Create a new Ezmlm::List object for the specified +listdir+, which should be |
30 ### an ezmlm-idx mailing list directory. |
22 ### an ezmlm-idx mailing list directory. |
|
23 ### |
31 def initialize( listdir ) |
24 def initialize( listdir ) |
32 listdir = Pathname.new( listdir ) if !listdir.is_a?( Pathname ) |
25 listdir = Pathname.new( listdir ) unless listdir.is_a?( Pathname ) |
33 @listdir = listdir |
26 @listdir = listdir |
34 |
|
35 # Cached lookups |
|
36 @config = nil |
|
37 end |
27 end |
38 |
28 |
39 |
29 |
40 ###### |
30 ###### |
41 public |
31 public |
47 |
37 |
48 ### Return the configured name of the list (without the host) |
38 ### Return the configured name of the list (without the host) |
49 def name |
39 def name |
50 return self.config[ 'L' ] |
40 return self.config[ 'L' ] |
51 end |
41 end |
52 |
42 |
53 |
43 |
54 ### Return the configured host of the list |
44 ### Return the configured host of the list |
55 def host |
45 def host |
56 return self.config[ 'H' ] |
46 return self.config[ 'H' ] |
57 end |
47 end |
58 |
48 |
59 |
49 |
60 ### Return the configured address of the list (in list@host form) |
50 ### Return the configured address of the list (in list@host form) |
61 def address |
51 def address |
62 return "%s@%s" % [ self.name, self.host ] |
52 return "%s@%s" % [ self.name, self.host ] |
63 end |
53 end |
64 alias_method :fullname, :address |
54 alias_method :fullname, :address |
65 |
55 |
66 |
56 |
67 ### Return the number of messages in the list archive |
57 ### Return the number of messages in the list archive |
68 def message_count |
58 def message_count |
69 numfile = self.listdir + 'num' |
59 numfile = self.listdir + 'num' |
70 return 0 unless numfile.exist? |
60 return 0 unless numfile.exist? |
89 ### Return the list config as a Hash |
79 ### Return the list config as a Hash |
90 def config |
80 def config |
91 unless @config |
81 unless @config |
92 configfile = self.listdir + 'config' |
82 configfile = self.listdir + 'config' |
93 raise "List config file %p does not exist" % [ configfile ] unless configfile.exist? |
83 raise "List config file %p does not exist" % [ configfile ] unless configfile.exist? |
94 |
84 |
95 @config = configfile.read.scan( /^(\S):([^\n]*)$/m ).inject({}) do |h,pair| |
85 @config = configfile.read.scan( /^(\S):([^\n]*)$/m ).inject({}) do |h,pair| |
96 key,val = *pair |
86 key,val = *pair |
97 h[key] = val |
87 h[key] = val |
98 h |
88 h |
99 end |
89 end |
100 end |
90 end |
101 |
91 |
102 return @config |
92 return @config |
103 end |
93 end |
104 |
94 |
105 |
95 |
106 ### Return the email address of the list's owner. |
96 ### Return the email address of the list's owner. |
107 def owner |
97 def owner |
108 self.config['5'] |
98 self.config['5'] |
109 end |
99 end |
110 |
100 |
111 |
101 |
112 ### Fetch an Array of the email addresses for all of the list's subscribers. |
102 ### Fetch an Array of the email addresses for all of the list's subscribers. |
113 def subscribers |
103 def subscribers |
114 subscribers_dir = self.listdir + 'subscribers' |
104 subscribers_dir = self.listdir + 'subscribers' |
115 return self.read_subscriber_dir( subscribers_dir ) |
105 return self.read_subscriber_dir( subscribers_dir ) |
130 |
120 |
131 ### Returns an Array of email addresses of people responsible for moderating subscription |
121 ### Returns an Array of email addresses of people responsible for moderating subscription |
132 ### of a closed list. |
122 ### of a closed list. |
133 def subscription_moderators |
123 def subscription_moderators |
134 return [] unless self.closed? |
124 return [] unless self.closed? |
135 |
125 |
136 modsubfile = self.listdir + 'modsub' |
126 modsubfile = self.listdir + 'modsub' |
137 remotefile = self.listdir + 'remote' |
127 remotefile = self.listdir + 'remote' |
138 |
128 |
139 subdir = nil |
129 subdir = nil |
140 if modsubfile.exist? && modsubfile.read(1) == '/' |
130 if modsubfile.exist? && modsubfile.read(1) == '/' |
141 subdir = Pathname.new( modsubfile.read.chomp ) |
131 subdir = Pathname.new( modsubfile.read.chomp ) |
142 elsif remotefile.exist? && remotefile.read(1) == '/' |
132 elsif remotefile.exist? && remotefile.read(1) == '/' |
143 subdir = Pathname.new( remotefile.read.chomp ) |
133 subdir = Pathname.new( remotefile.read.chomp ) |
144 else |
134 else |
145 subdir = self.listdir + 'mod/subscribers' |
135 subdir = self.listdir + 'mod/subscribers' |
146 end |
136 end |
147 |
137 |
148 return self.read_subscriber_dir( subdir ) |
138 return self.read_subscriber_dir( subdir ) |
149 end |
139 end |
150 |
140 |
151 |
141 |
152 ### Returns an Array of email addresses of people responsible for moderating posts |
142 ### Returns an Array of email addresses of people responsible for moderating posts |
153 ### sent to the list. |
143 ### sent to the list. |
154 def message_moderators |
144 def message_moderators |
155 return [] unless self.moderated? |
145 return [] unless self.moderated? |
156 |
146 |
157 modpostfile = self.listdir + 'modpost' |
147 modpostfile = self.listdir + 'modpost' |
158 subdir = nil |
148 subdir = nil |
159 |
149 |
160 if modpostfile.exist? && modpostfile.read(1) == '/' |
150 if modpostfile.exist? && modpostfile.read(1) == '/' |
161 subdir = Pathname.new( modpostfile.read.chomp ) |
151 subdir = Pathname.new( modpostfile.read.chomp ) |
162 else |
152 else |
163 subdir = self.listdir + 'mod/subscribers' |
153 subdir = self.listdir + 'mod/subscribers' |
164 end |
154 end |
165 |
155 |
166 return self.read_subscriber_dir( subdir ) |
156 return self.read_subscriber_dir( subdir ) |
167 end |
157 end |
168 |
158 |
169 |
159 |
170 ### Return a TMail::Mail object loaded from the last post to the list. Returns |
160 ### Return a TMail::Mail object loaded from the last post to the list. Returns |
171 ### +nil+ if there are no archived posts. |
161 ### +nil+ if there are no archived posts. |
172 def last_post |
162 def last_post |
173 archivedir = self.listdir + 'archive' |
163 archivedir = self.listdir + 'archive' |
174 return nil unless archivedir.exist? |
164 return nil unless archivedir.exist? |
187 raise RuntimeError, "unexpectedly empty archive directory '%s'" % [ last_archdir ] \ |
177 raise RuntimeError, "unexpectedly empty archive directory '%s'" % [ last_archdir ] \ |
188 unless last_post_path |
178 unless last_post_path |
189 |
179 |
190 last_post = TMail::Mail.load( last_post_path.to_s ) |
180 last_post = TMail::Mail.load( last_post_path.to_s ) |
191 end |
181 end |
192 |
182 |
193 |
183 |
194 |
184 |
195 ######### |
185 ######### |
196 protected |
186 protected |
197 ######### |
187 ######### |
198 |
188 |
199 ### Read the hashed subscriber email addresses from the specified +directory+ and return them in |
189 ### Read the hashed subscriber email addresses from the specified +directory+ and return them in |
200 ### an Array. |
190 ### an Array. |
201 def read_subscriber_dir( directory ) |
191 def read_subscriber_dir( directory ) |
202 rval = [] |
192 rval = [] |
203 Pathname.glob( directory + '*' ) do |hashfile| |
193 Pathname.glob( directory + '*' ) do |hashfile| |
204 rval.push( hashfile.read.scan(/T([^\0]+)\0/) ) |
194 rval.push( hashfile.read.scan(/T([^\0]+)\0/) ) |
205 end |
195 end |
206 |
196 |
207 return rval.flatten |
197 return rval.flatten |
208 end |
198 end |
209 |
199 |
210 |
200 end # class Ezmlm::List |
211 end |
201 |
212 |
|
213 # vim: set nosta noet ts=4 sw=4: |
|