commit c427bfc7f6b5dfa59dc920cae338cf9611b94476
Author: Marc Dequenes <duck@Orfeo.duckcorp.org>
Date:   Thu Feb 19 01:04:13 2009 +0100

    [evol] moved the mail processing into a new class returning proper orders

diff --git a/lib/cyborghood/mail.rb b/lib/cyborghood/mail.rb
new file mode 100644
index 0000000..bf87d5a
--- /dev/null
+++ b/lib/cyborghood/mail.rb
@@ -0,0 +1,58 @@
+module CyborgHood
+  class Mail < Delegator
+    def initialize(msg)
+      # unquote headers and transform into TMail object
+      @mail = TMail::Mail.parse(TMail::Unquoter.unquote_and_convert_to(msg, "UTF-8"))
+    end
+
+    def __getobj__
+      @mail
+    end
+
+    def parse
+      sig_check = verify_pgp_signature()
+      if sig_check.status == 0
+        logger.info "Mail content was properly signed by key #{sig_check.fingerprint}"
+        user = Person.find_by_fingerprint(sig_check.fingerprint)
+        if user.nil?
+          logger.info "Mail is from an unknown person"
+        else
+          logger.info "Mail is from user #{user.uid} (#{user.cn})"
+
+          signed_content = pgp_signed_part()
+          if signed_content.multipart?
+            if signed_content.parts[0].content_type == "text/plain"
+              command_txt = signed_content.parts[0].body
+              refs = signed_content.parts.collect{|p| p.dup }
+            end
+          else
+            command_txt = signed_content.body if signed_content.content_type == "text/plain"
+            refs = []
+          end
+
+          if command_txt
+            commands = []
+            command_txt.each_line do |line|
+              line.chomp!
+              sline = line.strip
+              # skip empty lines and comments
+              next if sline == "" or sline[0, 1] == "#"
+              # stop processing when detecting message signature
+              break if line == "-- "
+
+              commands << sline
+            end
+
+            return {:user => user, :commands => commands, :refs => refs}.to_ostruct
+          else
+            logger.info "Mail does not contain a proper MIME part for commands"
+          end
+        end
+      else
+        logger.info "Mail content tampered or badly signed: " + sig_check.to_s
+      end
+
+      nil
+    end
+  end
+end
diff --git a/postman b/postman
index 0b75a37..fec1e80 100755
--- a/postman
+++ b/postman
@@ -17,6 +17,7 @@ require 'active_ldap'
 require 'shellwords'
 require 'cyborghood/base'
 require 'cyborghood/objects'
+require 'cyborghood/mail'
 
 #Socket.gethostname
 
@@ -26,18 +27,11 @@ require 'cyborghood/objects'
 #
 
 class CommandParser
-  def self.run(user, txt, refs)
-    txt.each_line do |line|
-      line.chomp!
-      sline = line.strip
-      # skip empty lines and comments
-      next if sline == "" or sline[0, 1] == "#"
-      # stop processing when detecting message signature
-      break if line == "-- "
-
-      logger.info "Executing command: #{sline}"
+  def self.run(order)
+    order.commands.each do |cmd|
+      logger.info "Executing command: #{cmd}"
       begin
-        execute_cmd(user, sline)
+        execute_cmd(order.user, cmd, order.refs)
       rescue
         logger.info "Command failed: " + $!
       end
@@ -46,7 +40,7 @@ class CommandParser
 
   private
 
-  def self.execute_cmd(user, cmdstr)
+  def self.execute_cmd(user, cmdstr, refs)
     cmdline = Shellwords.shellwords(cmdstr)
     subsys = cmdline.shift
 
@@ -56,7 +50,7 @@ class CommandParser
       case cmdline.shift.upcase
       when "INFO"
         if cmdline.empty?
-          list = DnsDomain.find_by_manager(user)
+          list = CyborgHood::DnsDomain.find_by_manager(user)
           logger.info "User is manager of the following zones: " + list.collect{|z| z.cn }.sort.join(", ")
         else
           ok = false
@@ -65,7 +59,7 @@ class CommandParser
         case cmdline.shift.upcase
         when "ZONE"
           zone = cmdline.shift.downcase
-          dom = DnsDomain.new(zone)
+          dom = CyborgHood::DnsDomain.new(zone)
           logger.info "User requesting zone content for '#{zone}'"
           if dom.hosted?
             if dom.managed_by? user
@@ -126,49 +120,32 @@ module CyborgHood
       imap.select('INBOX')
       imap.search(["ALL"], "UTF-8").each do |message_id|
         msg = imap.fetch(message_id, "RFC822")[0].attr["RFC822"]
-        # unquote headers and transform into TMail object
-        mail = TMail::Mail.parse(TMail::Unquoter.unquote_and_convert_to(msg, "UTF-8"))
 
-        logger.set_prefix()
+        mail = Mail.new(msg)
+
+        #logger.set_prefix()
         logger.debug "######################################"
-        logger.set_prefix("[#{mail.message_id}] ")
-        logger.info "#{mail.from_addrs} -> #{mail.to_addrs}: #{mail.subject}"
+        #logger.set_prefix("[#{mail.message_id}] ")
+        logger.info "New mail #{mail.message_id}: #{mail.from_addrs} -> #{mail.to_addrs} (#{mail.subject})"
         # ignore mails not signed
         unless mail.is_pgp_signed?
-          logger.info "Mail not signed or not RFC3156 compliant"
+          logger.info "Mail not signed or not RFC3156 compliant, ignoring..."
           next
         end
 
         logger.debug "Proper signed content detected"
-        sig_check = mail.verify_pgp_signature()
-        if sig_check.status == 0
-          logger.info "Mail content was properly signed by key #{sig_check.fingerprint}"
-          user = Person.find_by_fingerprint(sig_check.fingerprint)
-          if user.nil?
-            logger.info "Mail is from an unknown person"
-          else
-            logger.info "Mail is from user #{user.uid} (#{user.cn})"
-
-            signed_content = mail.pgp_signed_part()
-            if signed_content.multipart?
-              if signed_content.parts[0].content_type == "text/plain"
-                command_txt = signed_content.parts[0].body
-                command_refs = signed_content.parts.collect{|p| p.dup }
-              end
-            else
-              command_txt = signed_content.body if signed_content.content_type == "text/plain"
-              command_refs = []
-            end
-
-            if command_txt
-              CommandParser.run(user, command_txt, command_refs)
-            else
-              logger.info "Mail does not contain a proper MIME part for commands"
-            end
-          end
-        else
-          logger.info "Mail content tampered or badly signed: " + sig_check.to_s
+        begin
+          order = mail.parse
+        rescue CyberError => e
+          logger.error "Internal processing error, skipping mail (#{e.message})"
+          next
         end
+        if order.nil?
+          logger.info "Mail is invalid, ignoring..."
+          next
+        end
+
+        CommandParser.run(order)
       end
       imap.logout
     end
