module Buryspam::Startup

Contains various class methods used for the intialization and startup of the entire script.

Constants

HOSTNAME
PARENT_CMD

Determine the name of the process that called us.

TRANSFER_MODES

Attributes

cmd[RW]

Public Class Methods

new_messages?() click to toggle source

Return true if we are receiving new messages. We are receiving new messages if we were started by procmail or if we were started in one of the transfer modes (--transfer/, --poll/ or --bulk). We need this information because we rotate spam files (and archive messages) only when new messages are being processed and not when invoked from the command line with --filter mbox (i.e., refiltering old messages), for example.

# File buryspam.rb, line 1806
def new_messages?
  called_by_procmail? || TRANSFER_MODES.has_key?(@cmd.mode)
end
run() click to toggle source

Main entry point for the script. Process the command line arguments, parse the configuration file and perform the required task.

# File buryspam.rb, line 1689
def run
  begin
    @cmd = CommandLine.instance

    # Display help messages before processing the Config file because
    # Config.process can raise an exception if there are configuration
    # errors, and no help will be displayed.
    if @cmd.mode == :help
      # Don't display banner if we are generating HTML for all the
      # configuration parameters/command line options.
      if @cmd.arg != '*'
        Status.print("\n#{BANNER}\nHelp...\n\n")
      end
      Help.instance.search(@cmd.arg)
      return
    end

    Config.process(@cmd.overrides)
    return unless FileUtils.free_space?

    case @cmd.mode
      when :transfer, :poll, :bulk
        Status.print("\n#{BANNER}\n#{TRANSFER_MODES[@cmd.mode]}\n\n")
        MUN_IMAP.transfer

      when :init
        Status.print("\n#{BANNER}\nInitializing...\n\n")
        Bayesian.init

      when :filter
        # Don't display a banner with Status.print when filtering
        # (procmail will see it otherwise).
        Logger.info("#{BANNER} Filtering...")
        Logger.debug("(invoked by: '#{PARENT_CMD}')")
        begin
          input = ""
          Mbox.read { |mbox|
            input = mbox.to_s
            Mbox.archive(input)
            print mbox.filter.join("")
          }
        rescue Exception => ex
          # If we were started by procmail and a problem occurred,
          # then echo the input to let procmail recover the message.
          print input if called_by_procmail?
          Status.error(ex)
        end

      when :grep, :decode
        # --grep and --decode may be used as part of a pipe
        # or a redirection, so don't use Status.print.
        Logger.info("#{BANNER} #{@cmd.mode.to_s.capitalize}...")
        Mbox.read(:strip_buryspam_hdrs => false) { |mbox|
          mbox.each_msg { |msg|
            decoded = msg.decode
            if @cmd.mode == :decode || @cmd.arg.match(decoded)
              print decoded
            end
          }
        }

      when :colour
        # We're generating HTML so log the banner --  don't display it.
        Logger.info("#{BANNER} Colour...")
        html = ""
        Mbox.read { |mbox|
          mbox.each_msg { |msg|
            html << msg.colourize
          }
        }
        print Message::HTML_HDR + html + Message::HTML_FTR

      when :stats
        Status.print("\n#{BANNER}\nStatistics...\n\n")
        Stats.show

      when :log
        Status.print("\n#{BANNER}\nLog...\n\n")
        # Default to showing (e)rror, (f)atal log messages only.
        Logger.show(@cmd.arg.empty? ? "ef" : @cmd.arg)

      else
        $stderr.print Help::USAGE
    end
  rescue CommandLine::Error,
         Config::Error
    # No need to display/log a full stack trace, so just pass the
    # error message text.
    Status.error($!.message)

    # read and echo stdin (if any) to let procmail recover the
    # (unfiltered) message
    if called_by_procmail?
      if $stdin.has_input?
        inp = $stdin.binread
        Status.error("Recovering #{inp.size} bytes of standard input")
        print inp
      else
        Status.error("Cannot recover input?")
      end
    end
  rescue Interrupt
    Status.warn("\n\nInterrupted.")
  rescue Exception
    Status.error($!)
  ensure
    Logger.close
  end
end

Private Class Methods

called_by_procmail?() click to toggle source

Return true if we were called by procmail. This is used to help determine how the messages are being delivered to us.

# File buryspam.rb, line 1814
def called_by_procmail?
  # Note that we cannot do:
  #  PARENT_CMD == Config.procmail
  # because Config.procmail may not have been set yet (this may be
  # true if we encountered an error in the configuration file which
  # sets Config.procmail!) So instead, we assume that if PARENT_CMD
  # ends in the string 'procmail', then the parent command is indeed
  # procmail.
  /\bprocmail$/.match(PARENT_CMD)
end