schleuder (2.1.1-2) direct (non packaging) changes

Summary

 bin/schleuder                        |    2 -
 contrib/newlist.rb                   |   29 +++++++++++---
 contrib/schleuder-migrationhelper.pl |    4 --
 ext/default-list.conf                |    6 ---
 ext/schleuder.conf                   |   43 +++++++++++++--------
 lib/schleuder.rb                     |    1 
 lib/schleuder/crypt.rb               |    3 +
 lib/schleuder/list.rb                |   36 +++++++++++++-----
 lib/schleuder/list_config.rb         |    6 ---
 lib/schleuder/mail.rb                |   34 +++++++++--------
 lib/schleuder/processor.rb           |    2 -
 lib/schleuder/schleuder_config.rb    |   20 ++++++----
 lib/schleuder/schleuder_logger.rb    |   70 +++++++++++++++++++++++++++++++++--
 plugins/send_log_plugin.rb           |    2 -
 14 files changed, 181 insertions(+), 77 deletions(-)

    
download this patch

Patch contents

--- schleuder-2.1.1.orig/contrib/schleuder-migrationhelper.pl
+++ schleuder-2.1.1/contrib/schleuder-migrationhelper.pl
@@ -49,10 +49,6 @@
 $new->{'prefix_out'} = $old->{'mail'}->{'subout'};
 $new->{'default_mime'} = lc(substr($old->{'mail'}->{'defaultenvelop'}, 1, length($old->{'mail'}->{'defaultenvelop'})-2));
 
-if (defined($old->{'site'}->{'logfile'})) {
-  $new->{'logging'} = true;
-}
-
 if (($old->{'policy'}->{'allow_plaintext_sending'} eq 'yes')||($old->{'policy'}->{'allow_plaintext_sending'} eq 'true')) {
   $new->{'allow_plaintext_sending'} = 'true'
 } else {
--- schleuder-2.1.1.orig/contrib/newlist.rb
+++ schleuder-2.1.1/contrib/newlist.rb
@@ -1,4 +1,4 @@
-#!/usr/bin/env ruby
+#!/usr/bin/env ruby1.8
 
 $:.unshift File.dirname(__FILE__) + '/../lib'
 require 'schleuder'
@@ -79,7 +79,7 @@
       require 'highline/import' if interactive
     rescue LoadError => ex
       puts "Unable to load 'highline'.\n\n"
-      puts "Please install the highline gem before trying to use"
+      puts "Please install the libhighline-ruby1.8 package before trying to use"
       puts "#{$0} in interactive mode."
       exit 1
     end
@@ -100,8 +100,10 @@
     list_privatekeyfile = args[:list_privatekeyfile] ||  'none'
     list_publickeyfile = args[:list_publickeyfile] || 'none'
     list_passphrase = args[:list_passphrase] || 'none'
-    unless args[:mailuser].nil?
+    if ! args[:mailuser].nil?
       mailuser = Etc.getpwnam(args[:mailuser]).uid
+    elsif Process::Sys.getuid == 0
+      mailuser = Etc.getpwnam('schleuder').uid
     else
       mailuser = Process::Sys.getuid
     end
@@ -168,7 +170,7 @@
     Schleuder.log.debug "Store list config..."
     list.config = list.config
     Schleuder.log.debug "Changing ownership..."
-    ListCreator::filepermissions(listdir,mailuser)
+    ListCreator::filepermissions(list,mailuser)
     Schleuder.log.debug "List successfully created..."
     ListCreator::print_list_infos(list) if interactive
   end
@@ -227,6 +229,9 @@
     _length = Schleuder.config.gpg_key_length
     _sub_type = Schleuder.config.gpg_subkey_type
     _sub_length = Schleuder.config.gpg_subkey_length
+    if GPGME.respond_to? 'check_version'
+      GPGME::check_version('0.0.0')
+    end
     GPGME::Ctx.new.genkey(
       ListCreator::create_gnupg_params_template(_name,_email,_pass,_type,_length,_sub_type,_sub_length),
       nil,nil
@@ -256,7 +261,8 @@
 </GnupgKeyParms>"
   end
 
-  def self.filepermissions(listdir, mailuser)
+  def self.filepermissions(list, mailuser)
+    listdir = File.expand_path(File.join(Schleuder.config.lists_dir, list.listname))
     File.chown(mailuser,nil,listdir)
     File.chmod(0700,listdir)
     Dir.new(listdir).each{ |f|
@@ -265,12 +271,23 @@
         File.chmod(0600)
       end
     }
+    File.chown(mailuser,nil,list.configfile)
+    File.chmod(0600,list.configfile)
+    unless list.logfile == 'syslog'
+      # Touch and set permissions on logfile
+      File.open(list.logfile, 'a').close()
+      File.chown(mailuser, nil, list.logfile)
+      File.chmod(0600, list.logfile)
+    end
   end
 
   def self.print_list_infos(list)
     puts "A new schleuder list #{list.config.myname} have been created."
     puts
-    puts "To get a working list you have to tell your MTA to handle this list. For various examples have a look at: http://schleuder.nadir.org/documentation/creatinglists"
+    puts "To get a working list you have to tell your MTA to handle this list."
+    puts "For various examples have a look at:"
+    puts " * /usr/share/doc/schleuder/README.Debian"
+    puts " * http://schleuder.nadir.org/documentation/creatinglists"
     puts
     puts "Lists' key fingerprint:"
     puts Schleuder::Utils::get_pretty_fingerprint(Schleuder::Crypt.new(list.config.gpg_password).get_key(list.config.myaddr))
--- schleuder-2.1.1.orig/ext/default-list.conf
+++ schleuder-2.1.1/ext/default-list.conf
@@ -51,15 +51,9 @@
 # cause fatal damage) list them here.
 #keywords_admin_only: ['SAVE-MEMBERS', 'DEL-KEY']
 #
-# list-specific logging? true||false
-#logging: true
-#
 # list-specific loglevel: ERROR || WARN || INFO || DEBUG
 #loglevel: ERROR
 #
-# How many logfiles to keep when rotating (daily)
-#log_rotate_keep: 3
-#
 # speaks for itself, no?
 #public_footer:
 #
--- schleuder-2.1.1.orig/ext/schleuder.conf
+++ schleuder-2.1.1/ext/schleuder.conf
@@ -10,7 +10,7 @@
 #gpg_key_type: RSA
 #
 # Set the length of a key we might create for new lists.
-#gpg_key_length: 2048
+#gpg_key_length: 4096
 #
 # Set the type of the subkey of a key we might create
 # for new lists.
@@ -18,28 +18,33 @@
 #
 # Set the length of the subkey of a key we might create
 # for new lists.
-#gpg_subkey_length: 2048
+#gpg_subkey_length: 4096
 #
-# Name of the per list config file.
-#lists_configfile: list.conf
-#
-# Per list logfile name. Will be written into the directory
-# of the list.
-#lists_logfile: list.log
+# Name of the per list config file. Either:
+#  - a file name that resides in the list data directory,
+#  - a directory, ending with '/', having a "$LISTNAME.conf" file.
+#lists_configfile: /etc/schleuder/lists/
+#
+# Per list logfile location:
+#  - specify a filename to log under that name in the directory of the
+#    list,
+#  - specify a directory, ending with '/' to put a file named
+#    "$LISTNAME.log" in that directory,
+#  - specify "syslog" to log through the syslog(3) facility.
+#lists_logfile: /var/log/schleuder/
 #
 # Name of the per list file containing all members and their
 # options.
 #lists_memberfile: members.conf
 #
 # Where we find the global options for all lists.
-# Note: the following notion isn't valid. You have
-# to provide a fully qualified path.
-#lists_default_conf: conf_dir + '/default-list.conf'
+#lists_default_conf: /etc/schleuder/default-list.conf
 #
 # Location of the various schleuderlists' directory.
-#lists_dir: /var/schleuderlists
+#lists_dir: /var/lib/schleuder
 #
-# Location of the global logfile.
+# Location of the global logfile. Specify "syslog" to log through
+# the syslog(3) facility.
 #logfile: /var/log/schleuder/schleuder.log
 #
 # Global schleuder log level, might change after the list config
@@ -47,9 +52,15 @@
 # Possible values: ERROR || WARN || INFO || DEBUG
 #loglevel: ERROR
 #
-# Location of schleuder plugins. Note: the following notion
-# isn't valid. You have to provide a fully qualified path.
-#plugins_dir = schleuder_base + '/plugins'
+# How many logfiles to keep when rotating (daily)
+# (specifying 0 will disable logfile rotation)
+#log_rotate_keep: 0
+#
+# Location of schleuder plugins.
+# Multiple plugins directory are supported.
+#plugins_dir:
+#- /usr/share/schleuder/plugins
+#- /etc/schleuder/plugins
 #
 # The super administrator of this schleuder installation. This
 # address will receive all notices which can'tbe delivered to
--- schleuder-2.1.1.orig/bin/schleuder
+++ schleuder-2.1.1/bin/schleuder
@@ -1,4 +1,4 @@
-#!/usr/bin/env ruby
+#!/usr/bin/env ruby1.8
 
 # TODO: 
 # - make code comments rdoc-compatible.
--- schleuder-2.1.1.orig/plugins/send_log_plugin.rb
+++ schleuder-2.1.1/plugins/send_log_plugin.rb
@@ -5,7 +5,7 @@
     end
     
     def process(mail)
-      log = File.read(File.join(Schleuder.config.lists_dir, Schleuder.list.listname, Schleuder.config.lists_logfile))
+      log = File.read(Schleuder.list.logfile)
       reply(mail, log)
     end
   end
--- schleuder-2.1.1.orig/lib/schleuder.rb
+++ schleuder-2.1.1/lib/schleuder.rb
@@ -1,5 +1,4 @@
 # third party
-require 'rubygems'
 require 'tmail'
 require 'net/smtp'
 
--- schleuder-2.1.1.orig/lib/schleuder/list.rb
+++ schleuder-2.1.1/lib/schleuder/list.rb
@@ -11,8 +11,7 @@
     def initialize(listname,newlist=false)
       @listname = listname
       @listdir = File.expand_path(File.join(Schleuder.config.lists_dir, listname))
-      file = File.join(@listdir, Schleuder.config.lists_logfile)
-      @log = SchleuderLogger.new("Schleuder #{listname}", file)
+      @log = SchleuderLogger.new("schleuder-#{listname}", logfile)
       
       # setting GNUPGHOME to list's home, to make use of the keys there
       @log.debug "setting ENV[GNUPGHOME] to #{@listdir}"
@@ -24,11 +23,6 @@
       # logged regardless of the loglevel set in the config (as the
       # SchleuderLogger uses WARN as default).
       @log.sev_threshold = eval("Logger::" + config.loglevel.upcase)
-
-      # delete out-of-age logfiles. Do it here and not in
-      # schleuder_logger because that one also cares for the global log
-      removed = File.unlink(*Dir["#{file}.20[0-9]*"].sort.slice(0..-self.config.log_rotate_keep))
-      @log.info "Removed #{removed} old logfiles" if removed > 0
     end
     
     # Provides an array of Schleuder::Member's, read from +members.conf+
@@ -101,11 +95,22 @@
       @_config
     end
 
+    # Returns path to the list configuration file
+    def configfile
+      # If `lists_configfile` ends with a '/', assume its pointing to a
+      # directory where configuration files are named "$LISTNAME.conf".
+      if Schleuder.config.lists_configfile.end_with? '/' then
+        file = File.join(Schleuder.config.lists_configfile, "#{@listname}.conf")
+      else
+        file = File.join(@listdir, Schleuder.config.lists_configfile)
+      end
+    end
+
     # Loads the configuration
     # fromfile = Wether to load the config from file.
     def _load_config(fromfile=true)
         @log.debug("reading list-config for: #{@listname}") unless @log.nil?
-        @_config = ListConfig.new(File.join(@listdir, Schleuder.config.lists_configfile),fromfile)
+        @_config = ListConfig.new(configfile,fromfile)
     end
     
     # Saves +data+ into the list-config-file (default: list.conf). +data+ must
@@ -117,7 +122,7 @@
       else
         @_config = ListConfig.new(data)
       end
-      _write(YAML::dump(@_config.to_hash), File.join(@listdir, Schleuder.config.lists_configfile))
+      _write(YAML::dump(@_config.to_hash), configfile)
     end
     
     # Builds the bounce-address for the list
@@ -130,6 +135,19 @@
       self.config.myaddr.gsub(/^(.*)@(.*)$/, '\1-sendkey@\2')
     end
 
+    # builds the logfile path
+    def logfile
+      # If lists_logfile ends with a '/' assume that it's a directory, and log
+      # to "#{lists_logfile}#{listname}.log"
+      if Schleuder.config.lists_logfile.end_with? '/' then
+        File.join(Schleuder.config.lists_logfile, "#{@listname}.log")
+      elsif Schleuder.config.lists_logfile == 'syslog' then
+        Schleuder.config.lists_logfile
+      else
+        File.join(@listdir, Schleuder.config.lists_logfile)
+      end
+    end
+
     private
 
     def _write(data,filename)
--- schleuder-2.1.1.orig/lib/schleuder/crypt.rb
+++ schleuder-2.1.1/lib/schleuder/crypt.rb
@@ -7,6 +7,9 @@
       # Instantiates and stores password
       def initialize(password)
         @password = password
+        if GPGME.respond_to? 'check_version'
+          GPGME::check_version('0.0.0')
+        end
         @ctx = GPGME::Ctx.new
         # feed the passphrase into the Context
         @ctx.set_passphrase_cb(method(:passfunc))		
--- schleuder-2.1.1.orig/lib/schleuder/schleuder_config.rb
+++ schleuder-2.1.1/lib/schleuder/schleuder_config.rb
@@ -13,6 +13,8 @@
     attr_accessor :logfile
     # Global loglevel: (ERROR || WARN || INFO || DEBUG)
     attr_accessor :loglevel
+    # How many logfiles to keep when rotating (daily)
+    attr_accessor :log_rotate_keep
     # Directory which holds plugin-files
     attr_accessor :plugins_dir
     # Directory which holds one subdirectory for each list
@@ -38,7 +40,7 @@
     def initialize(config_file=nil)
       conf_dir = '/etc/schleuder'
       config_file = conf_dir + '/schleuder.conf' unless config_file
-      base = File.expand_path(File.dirname(__FILE__) + '/../..')
+      base = '/usr/share/schleuder'
       # These are some "vendor defaults".
       # If you need to change these, put them into schleuder.conf
       @smtp_host = 'localhost'
@@ -46,20 +48,24 @@
       @superadminaddr = 'root@localhost'
       @logfile = '/var/log/schleuder/schleuder.log'
       @loglevel = 'ERROR'
-      @plugins_dir = base + '/plugins'
-      @lists_dir = '/var/schleuderlists'
-      @lists_configfile = 'list.conf'
-      @lists_logfile = 'list.log'
+      @log_rotate_keep = 0
+      @plugins_dir = [base + '/plugins', '/etc/schleuder/plugins']
+      @lists_dir = '/var/lib/schleuder'
+      @lists_configfile = '/etc/schleuder/lists/'
+      @lists_logfile = '/var/log/schleuder/'
       @lists_memberfile = 'members.conf'
       @lists_default_conf = conf_dir + '/default-list.conf'
 
       @gpg_key_type = 'RSA'
-      @gpg_key_length = 2048
+      @gpg_key_length = 4096
       @gpg_subkey_type = 'RSA'
-      @gpg_subkey_length = 2048
+      @gpg_subkey_length = 4906
 
       # overload with config_file 
       super config_file
+
+      # turn @plugins_dir into an array if needed
+      @plugins_dir = [@plugins_dir] unless @plugins_dir.class == Array
     end
   end
 end
--- schleuder-2.1.1.orig/lib/schleuder/processor.rb
+++ schleuder-2.1.1/lib/schleuder/processor.rb
@@ -5,7 +5,7 @@
       Schleuder.list.log
     else
       unless @log
-        @log = SchleuderLogger.new('Schleuder', config.logfile, config.loglevel)
+        @log = SchleuderLogger.new('schleuder', config.logfile, config.loglevel)
       end
       @log
     end
--- schleuder-2.1.1.orig/lib/schleuder/schleuder_logger.rb
+++ schleuder-2.1.1/lib/schleuder/schleuder_logger.rb
@@ -4,13 +4,67 @@
   class SchleuderLogger < Logger
     # instantiates a Logger and sets @+progname+ and @+sev_threshold+
     def initialize(progname, logfile, loglevel="warn")
-      # rotate daily
-      super logfile, 'daily'
+      logfile = nil if logfile == 'syslog'
+      if Schleuder.config.log_rotate_keep > 0 && ! logfile.nil? then
+        # rotate daily
+        super logfile, 'daily'
+      else
+        super logfile
+      end
       @progname = progname
+      if logfile.nil?
+        init_syslog
+      end
       # By specifying the log-level we can define what messages are actually
       # logged.  For 'ageing' logfiles and/or set a maximum size see
       # documentation for +Logger+.
       @sev_threshold = eval("Logger::" + loglevel.upcase)
+
+      if Schleuder.config.log_rotate_keep > 0 && ! logfile.nil? then
+        # delete out-of-age logfiles
+        removed = File.unlink(*Dir["#{logfile}.20[0-9]*"].sort.slice(0..-Schleuder.config.log_rotate_keep))
+        @log.info "Removed #{removed} old logfiles" if removed > 0
+      end
+    end
+
+    def init_syslog
+        require 'syslog'
+        require 'stringio'
+
+        unless Syslog.opened?
+	  @syslog = Syslog.open(@progname, Syslog::LOG_PID | Syslog::LOG_NDELAY,
+                                Syslog::LOG_MAIL)
+        else
+	  @syslog = Syslog.reopen(@progname, Syslog::LOG_PID | Syslog::LOG_NDELAY,
+                                  Syslog::LOG_MAIL)
+        end
+        @@LOGGER_LEVEL_TO_SYSLOG = {
+          Logger::DEBUG   => Syslog::LOG_DEBUG,
+          Logger::INFO    => Syslog::LOG_INFO,
+          Logger::WARN    => Syslog::LOG_WARNING,
+          Logger::ERROR   => Syslog::LOG_ERR,
+          Logger::FATAL   => Syslog::LOG_CRIT,
+          Logger::UNKNOWN => Syslog::LOG_NOTICE,
+        }
+	# On top of using syslog(3), continue to use Logger to keep a backlog
+        # handy for notify_admin
+        @logdev = Logger::LogDevice.new(StringIO.new)
+    end
+
+    def add(severity, message = nil, progname = nil, &block)
+      severity ||= Logger::UNKNOWN
+      return true if severity < @level
+      if message.nil?
+        if block_given?
+          message = yield
+        else
+          message = progname
+        end
+      end
+
+      super(severity, message)
+      return true unless @syslog
+      @syslog.log(@@LOGGER_LEVEL_TO_SYSLOG[severity], '%s', message)
     end
 
     # extends Logger#error by sending notification to admin
@@ -28,6 +82,15 @@
       exit 1
     end
 
+    def read_backlog
+      unless @syslog
+        logfile = File.expand_path(@logdev.instance_variable_get('@filename'))
+        File.read(logfile)
+      else
+        @logdev.dev.string
+      end
+    end
+
     def notify_admin msg=nil, subject=nil
       self.info 'notifying (super)admin'
       m = Mail.new
@@ -37,8 +100,7 @@
 
       if msg.nil?
         msg = "Hello,\n\nan error has occurred working for list #{Schleuder.list.listname}:\n\n"
-        logfile = File.expand_path(@logdev.instance_variable_get('@filename'))
-        File.read(logfile).split(/\n[IDEFW]{1}, /).each do |line|
+        read_backlog.split(/\n[IDEFW]{1}, /).each do |line|
           msg << "#{line}\n" if line.match(/ ##{$$}\]/)
         end
       end
--- schleuder-2.1.1.orig/lib/schleuder/list_config.rb
+++ schleuder-2.1.1/lib/schleuder/list_config.rb
@@ -31,11 +31,7 @@
     # Subject prefix for outgoing mails
     attr_accessor :prefix_out
     # Wether to log or not
-    attr_accessor :logging
-    # The loglevel (ERROR || WARN || INFO || DEBUG)
     attr_accessor :loglevel
-    # How many logfiles to keep when rotating (daily)
-    attr_accessor :log_rotate_keep
     # Which headers from original mail to include into the internal meta data
     attr_accessor :headers_to_meta
     # Restrict specific plugins to admin
@@ -73,9 +69,7 @@
       @prefix = ''
       @prefix_in = ''
       @prefix_out = ''
-      @logging = true
       @loglevel = 'ERROR'
-      @log_rotate_keep = 3
       @headers_to_meta = [:from, :to, :cc, :date]
       @keywords_admin_only = ['SAVE-MEMBERS', 'DEL-KEY']
       @bounces_drop_all = false
--- schleuder-2.1.1.orig/lib/schleuder/mail.rb
+++ schleuder-2.1.1/lib/schleuder/mail.rb
@@ -375,23 +375,27 @@
     def process_plugins!
       if self.keywords.empty?
         Schleuder.log.info 'No keywords present, skipping plugins'
-      elsif File.directory? Schleuder.config.plugins_dir
-        Dir[Schleuder.config.plugins_dir + '/*_plugin.rb'].each do |plugfile|
-          Schleuder.log.debug "processing file #{plugfile} as plugin"
-          require plugfile
-          # interpreting class name from file name
-          classname = File.basename(plugfile, '.rb').split('_').collect { |p| p.capitalize }.join
-          plugin = instance_eval(classname).new
-          Schleuder.log.debug "Testing #{plugin.class}.match..."
-          if plugin.match(self)
-            Schleuder.log.debug "#{plugin.class}.match matched -- executing #{plugin.class}.process"
-            plugin.process(self)
-          else
-            Schleuder.log.debug "#{plugin.class}.match didn't match"
+        return
+      end
+      Schleuder.config.plugins_dir.each do |plugins_dir|
+        if File.directory? plugins_dir
+          Dir[plugins_dir + '/*_plugin.rb'].each do |plugfile|
+            Schleuder.log.debug "processing file #{plugfile} as plugin"
+            require plugfile
+            # interpreting class name from file name
+            classname = File.basename(plugfile, '.rb').split('_').collect { |p| p.capitalize }.join
+            plugin = instance_eval(classname).new
+            Schleuder.log.debug "Testing #{plugin.class}.match..."
+            if plugin.match(self)
+              Schleuder.log.debug "#{plugin.class}.match matched -- executing #{plugin.class}.process"
+              plugin.process(self)
+            else
+              Schleuder.log.debug "#{plugin.class}.match didn't match"
+            end
           end
+        else
+          Schleuder.log.error "#{plugins_dir} does not exist or is not readable!"
         end
-      else
-        Schleuder.log.error "#{Schleuder.config.plugins_dir} does not exist or is not readable!"
       end
     end