2008-05-07 18:22:04 +00:00
|
|
|
#!/usr/bin/ruby
|
2017-02-01 15:35:35 -08:00
|
|
|
# vim: set nosta noet ts=4 sw=4:
|
2008-05-07 18:22:04 +00:00
|
|
|
#
|
2017-02-01 15:35:35 -08:00
|
|
|
# A Ruby interface to a single Ezmlm-idx mailing list directory.
|
2008-05-07 18:22:04 +00:00
|
|
|
#
|
|
|
|
|
# == Version
|
|
|
|
|
#
|
|
|
|
|
# $Id$
|
|
|
|
|
#
|
|
|
|
|
#---
|
|
|
|
|
|
|
|
|
|
require 'pathname'
|
|
|
|
|
require 'ezmlm'
|
2017-02-01 15:35:35 -08:00
|
|
|
require 'mail'
|
2008-05-07 18:22:04 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
### A Ruby interface to an ezmlm-idx mailing list directory
|
2017-02-01 15:35:35 -08:00
|
|
|
###
|
2008-05-07 18:22:04 +00:00
|
|
|
class Ezmlm::List
|
2017-02-01 15:35:35 -08:00
|
|
|
|
2008-05-08 21:12:48 +00:00
|
|
|
### Create a new Ezmlm::List object for the specified +listdir+, which should be
|
|
|
|
|
### an ezmlm-idx mailing list directory.
|
2017-02-01 15:35:35 -08:00
|
|
|
###
|
2008-05-08 21:12:48 +00:00
|
|
|
def initialize( listdir )
|
2017-02-01 15:35:35 -08:00
|
|
|
listdir = Pathname.new( listdir ) unless listdir.is_a?( Pathname )
|
2008-05-08 21:12:48 +00:00
|
|
|
@listdir = listdir
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
######
|
|
|
|
|
public
|
|
|
|
|
######
|
|
|
|
|
|
|
|
|
|
# The Pathname object for the list directory
|
|
|
|
|
attr_reader :listdir
|
|
|
|
|
|
|
|
|
|
|
2008-05-10 01:52:42 +00:00
|
|
|
### Return the configured name of the list (without the host)
|
|
|
|
|
def name
|
|
|
|
|
return self.config[ 'L' ]
|
|
|
|
|
end
|
2017-02-01 15:35:35 -08:00
|
|
|
|
2008-05-10 01:52:42 +00:00
|
|
|
|
|
|
|
|
### Return the configured host of the list
|
|
|
|
|
def host
|
|
|
|
|
return self.config[ 'H' ]
|
|
|
|
|
end
|
2017-02-01 15:35:35 -08:00
|
|
|
|
2008-05-10 01:52:42 +00:00
|
|
|
|
|
|
|
|
### Return the configured address of the list (in list@host form)
|
|
|
|
|
def address
|
|
|
|
|
return "%s@%s" % [ self.name, self.host ]
|
|
|
|
|
end
|
|
|
|
|
alias_method :fullname, :address
|
2017-02-01 15:35:35 -08:00
|
|
|
|
2008-05-10 01:52:42 +00:00
|
|
|
|
2008-05-09 17:51:36 +00:00
|
|
|
### Return the number of messages in the list archive
|
|
|
|
|
def message_count
|
|
|
|
|
numfile = self.listdir + 'num'
|
|
|
|
|
return 0 unless numfile.exist?
|
|
|
|
|
return Integer( numfile.read[/^(\d+):/, 1] )
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### Return the Date parsed from the last post to the list.
|
|
|
|
|
def last_message_date
|
|
|
|
|
mail = self.last_post or return nil
|
|
|
|
|
return mail.date
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### Return the author of the last post to the list.
|
|
|
|
|
def last_message_author
|
|
|
|
|
mail = self.last_post or return nil
|
|
|
|
|
return mail.from
|
|
|
|
|
end
|
2008-05-10 01:52:42 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
### Return the list config as a Hash
|
|
|
|
|
def config
|
|
|
|
|
unless @config
|
|
|
|
|
configfile = self.listdir + 'config'
|
|
|
|
|
raise "List config file %p does not exist" % [ configfile ] unless configfile.exist?
|
2017-02-01 15:35:35 -08:00
|
|
|
|
2008-05-10 01:52:42 +00:00
|
|
|
@config = configfile.read.scan( /^(\S):([^\n]*)$/m ).inject({}) do |h,pair|
|
|
|
|
|
key,val = *pair
|
|
|
|
|
h[key] = val
|
|
|
|
|
h
|
|
|
|
|
end
|
|
|
|
|
end
|
2017-02-01 15:35:35 -08:00
|
|
|
|
2008-05-10 01:52:42 +00:00
|
|
|
return @config
|
|
|
|
|
end
|
2017-02-01 15:35:35 -08:00
|
|
|
|
2008-05-09 17:51:36 +00:00
|
|
|
|
2008-05-08 21:12:48 +00:00
|
|
|
### Return the email address of the list's owner.
|
|
|
|
|
def owner
|
2008-05-10 01:52:42 +00:00
|
|
|
self.config['5']
|
2008-05-08 21:12:48 +00:00
|
|
|
end
|
2017-02-01 15:35:35 -08:00
|
|
|
|
2008-05-08 21:12:48 +00:00
|
|
|
|
|
|
|
|
### Fetch an Array of the email addresses for all of the list's subscribers.
|
|
|
|
|
def subscribers
|
|
|
|
|
subscribers_dir = self.listdir + 'subscribers'
|
|
|
|
|
return self.read_subscriber_dir( subscribers_dir )
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### Returns +true+ if subscription to the list is moderated.
|
|
|
|
|
def closed?
|
|
|
|
|
return (self.listdir + 'modsub').exist? || (self.listdir + 'remote').exist?
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### Returns +true+ if posting to the list is moderated.
|
|
|
|
|
def moderated?
|
|
|
|
|
return (self.listdir + 'modpost').exist?
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### Returns an Array of email addresses of people responsible for moderating subscription
|
|
|
|
|
### of a closed list.
|
|
|
|
|
def subscription_moderators
|
|
|
|
|
return [] unless self.closed?
|
2017-02-01 15:35:35 -08:00
|
|
|
|
2008-05-08 21:12:48 +00:00
|
|
|
modsubfile = self.listdir + 'modsub'
|
|
|
|
|
remotefile = self.listdir + 'remote'
|
2017-02-01 15:35:35 -08:00
|
|
|
|
2008-05-08 21:12:48 +00:00
|
|
|
subdir = nil
|
|
|
|
|
if modsubfile.exist? && modsubfile.read(1) == '/'
|
|
|
|
|
subdir = Pathname.new( modsubfile.read.chomp )
|
|
|
|
|
elsif remotefile.exist? && remotefile.read(1) == '/'
|
|
|
|
|
subdir = Pathname.new( remotefile.read.chomp )
|
|
|
|
|
else
|
|
|
|
|
subdir = self.listdir + 'mod/subscribers'
|
|
|
|
|
end
|
2017-02-01 15:35:35 -08:00
|
|
|
|
2008-05-08 21:12:48 +00:00
|
|
|
return self.read_subscriber_dir( subdir )
|
|
|
|
|
end
|
2017-02-01 15:35:35 -08:00
|
|
|
|
|
|
|
|
|
2008-05-08 21:12:48 +00:00
|
|
|
### Returns an Array of email addresses of people responsible for moderating posts
|
|
|
|
|
### sent to the list.
|
|
|
|
|
def message_moderators
|
|
|
|
|
return [] unless self.moderated?
|
2017-02-01 15:35:35 -08:00
|
|
|
|
2008-05-08 21:12:48 +00:00
|
|
|
modpostfile = self.listdir + 'modpost'
|
|
|
|
|
subdir = nil
|
2017-02-01 15:35:35 -08:00
|
|
|
|
2008-05-08 21:12:48 +00:00
|
|
|
if modpostfile.exist? && modpostfile.read(1) == '/'
|
|
|
|
|
subdir = Pathname.new( modpostfile.read.chomp )
|
|
|
|
|
else
|
|
|
|
|
subdir = self.listdir + 'mod/subscribers'
|
|
|
|
|
end
|
2017-02-01 15:35:35 -08:00
|
|
|
|
2008-05-08 21:12:48 +00:00
|
|
|
return self.read_subscriber_dir( subdir )
|
|
|
|
|
end
|
2017-02-01 15:35:35 -08:00
|
|
|
|
|
|
|
|
|
2008-05-09 17:51:36 +00:00
|
|
|
### Return a TMail::Mail object loaded from the last post to the list. Returns
|
|
|
|
|
### +nil+ if there are no archived posts.
|
|
|
|
|
def last_post
|
|
|
|
|
archivedir = self.listdir + 'archive'
|
|
|
|
|
return nil unless archivedir.exist?
|
|
|
|
|
|
|
|
|
|
# Find the last numbered directory under the archive dir
|
|
|
|
|
last_archdir = Pathname.glob( archivedir + '[0-9]*' ).
|
|
|
|
|
sort_by {|pn| Integer(pn.basename.to_s) }.last
|
|
|
|
|
|
|
|
|
|
return nil unless last_archdir
|
|
|
|
|
|
|
|
|
|
# Find the last numbered file under the last numbered directory we found
|
|
|
|
|
# above.
|
|
|
|
|
last_post_path = Pathname.glob( last_archdir + '[0-9]*' ).
|
2008-05-10 01:52:42 +00:00
|
|
|
sort_by {|pn| pn.basename.to_s }.last
|
2008-05-09 17:51:36 +00:00
|
|
|
|
|
|
|
|
raise RuntimeError, "unexpectedly empty archive directory '%s'" % [ last_archdir ] \
|
|
|
|
|
unless last_post_path
|
|
|
|
|
|
|
|
|
|
last_post = TMail::Mail.load( last_post_path.to_s )
|
|
|
|
|
end
|
2017-02-01 15:35:35 -08:00
|
|
|
|
|
|
|
|
|
2008-05-08 21:12:48 +00:00
|
|
|
|
|
|
|
|
#########
|
|
|
|
|
protected
|
|
|
|
|
#########
|
|
|
|
|
|
2017-02-01 15:35:35 -08:00
|
|
|
### Read the hashed subscriber email addresses from the specified +directory+ and return them in
|
2008-05-08 21:12:48 +00:00
|
|
|
### an Array.
|
|
|
|
|
def read_subscriber_dir( directory )
|
|
|
|
|
rval = []
|
|
|
|
|
Pathname.glob( directory + '*' ) do |hashfile|
|
|
|
|
|
rval.push( hashfile.read.scan(/T([^\0]+)\0/) )
|
|
|
|
|
end
|
2017-02-01 15:35:35 -08:00
|
|
|
|
2008-05-08 21:12:48 +00:00
|
|
|
return rval.flatten
|
|
|
|
|
end
|
2008-05-07 18:22:04 +00:00
|
|
|
|
2017-02-01 15:35:35 -08:00
|
|
|
end # class Ezmlm::List
|
|
|
|
|
|