commit 3d7bbe55cb6110cbe884ce7c45db045849a2be38
Author: Marc Dequènes (Duck) <Duck@DuckCorp.org>
Date:   Sat Jun 19 20:04:41 2010 +0200

    [evol] improved Order classes a lot (closes #101)

diff --git a/bin/postman b/bin/postman
index 64a1ff7..eed369a 100755
--- a/bin/postman
+++ b/bin/postman
@@ -134,7 +134,8 @@ module CyborgHood
           return true
         end
 
-        order = MailOrder.parse(report.user, report.message)
+        mail_parser = MailOrderParser.new(report.user)
+        order = mail_parser.parse(report.message)
         result_tag = order.valid? ? "SUCCESS" : "FAILURE"
         result_msg = "Processing result: #{result_tag}"
         result_msg += " (#{order.error.untranslated})" unless order.valid?
diff --git a/lib/cyborghood/command_runner.rb b/lib/cyborghood/command_runner.rb
index b86b2c8..fac0325 100644
--- a/lib/cyborghood/command_runner.rb
+++ b/lib/cyborghood/command_runner.rb
@@ -91,7 +91,7 @@ module CyborgHood
               end
 
               srv_dns = Services::DNS.new(zone)
-	      zone_content = srv_dns.read_zone
+              zone_content = srv_dns.read_zone
 
               result.ok = true
               result.message = _("Requested zone content attached.")
@@ -116,15 +116,15 @@ module CyborgHood
               srv_dns = Services::DNS.new(zone)
 
               return if cmdline.empty?
-              content_ref = cmdline.shift
-              ref, part = Order.dereference_param(shared_parameters, content_ref)
-              unless part.content_type == "text/plain"
-                result.message = _("Attachment has wrong content-type.")
+
+              zone_data = cmdline.shift
+              unless zone_data.content_type == "text/plain"
+                result.message = _("Zone data has wrong content-type.")
                 return result
               end
 
               f = Tempfile.new(zone)
-              f.write(part.content)
+              f.write(zone_data.content)
               f.close
               logger.debug "Created temporary zone file '#{f.path}'"
 
diff --git a/lib/cyborghood/mail_order.rb b/lib/cyborghood/mail_order.rb
index 3cabae7..663d7c9 100644
--- a/lib/cyborghood/mail_order.rb
+++ b/lib/cyborghood/mail_order.rb
@@ -19,51 +19,53 @@
 require 'cyborghood/order'
 
 module CyborgHood
-  class MailOrder < Order
-    def self.parse(user, message)
+  class MailOrderParser < OrderParser
+    def parse(message)
       logger.debug "Parsing Mail"
+
+      # analyse mail parts
       order_txt = nil
-      shared_parameters = nil
       if message.multipart?
         if message.parts[0].content_type == "text/plain"
           order_txt = message.parts[0].body
-          shared_parameters = {}
           i = -1
           message.parts.each do |part|
             i += 1
-	    next if i == 0
+            next if i == 0
 
-            shared_parameters[i] = SharedParameter.new(part.body, part.content_type)
-            filename = part.header['content-disposition'].params['filename'] || part.header['content-type'].params['name']
+            @shared_parameters[i] = CommandParameter.new(part.body, part.content_type)
 
-            shared_parameters[filename] = ParameterReference.new(i) if filename
+            filename = part.header['content-disposition'].params['filename'] || part.header['content-type'].params['name']
+            @shared_parameters[filename] = CommandParameterRef.new(i) if filename
           end
         end
       else
         order_txt = message.body if message.content_type == "text/plain"
-        shared_parameters = {}
       end
-      return new(:error => _("Mail does not contain a proper text part for commands."), :user => user) if order_txt.nil?
+      return Order.new(:error => _("Mail does not contain a proper text part for commands."), :user => @user) if order_txt.nil?
 
+      # find command lines
       command_lines = order_txt.split("\n")
 
       # remove message signature
       signature_pos = command_lines.index("-- ")
       command_lines.slice!(signature_pos..-1) if signature_pos
 
-      super(user, command_lines, shared_parameters) do |word, errors, used_refs|
+      # generic parsing
+      super(command_lines) do |word, errors|
         if word =~ /^@([a-zA-Z0-9._-]+)$/
           ref = $1
-          param = ParameterReference.new(ref)
-          d_ref, d_param = dereference_param(shared_parameters, param)
+          ref = ref.is_numeric? ? ref.to_i : ref
+          d_ref, d_param = deref_param(ref)
           if d_ref.nil?
             errors << _("Attachment '%{ref}' not found.", :ref => ref)
+            d_param = nil
           else
-            used_refs << d_ref
+            @used_refs << d_ref
           end
           d_param
         else
-          word
+          CommandParameter.new(word, 'text/plain')
         end
       end
     end
diff --git a/lib/cyborghood/order.rb b/lib/cyborghood/order.rb
index 9ddf5f6..a46c742 100644
--- a/lib/cyborghood/order.rb
+++ b/lib/cyborghood/order.rb
@@ -31,16 +31,20 @@ module CyborgHood
     end
   end
 
-  class SharedParameter
-    attr_reader :content_type, :content
+  class CommandParameter < String
+    attr_reader :content_type
 
     def initialize(content, content_type = nil)
-      @content = content
+      super(content)
       @content_type = content_type
     end
+
+    def content
+      to_s
+    end
   end
 
-  class ParameterReference
+  class CommandParameterRef
     attr_reader :reference
 
     def initialize(reference)
@@ -59,10 +63,24 @@ module CyborgHood
       @shared_parameters = params[:shared_parameters]
     end
 
-    def self.parse(user, command_lines, shared_parameters)
+    def valid?
+       @error.nil? and @user and not @commands.empty?
+    end
+  end
+
+  class OrderParser
+    include I18nTranslation
+
+    def initialize(user)
+      @user = user
+
+      @commands = []
+      @shared_parameters = {}
+      @used_refs = []
+    end
+
+    def parse(command_lines)
       logger.debug "Parsing Order"
-      used_refs = []
-      commands = []
       command_lines.each do |line|
         line.strip!
         # skip empty lines and comments
@@ -76,33 +94,29 @@ module CyborgHood
           raw_cmd_parts = []
         end
         cmd_parts = raw_cmd_parts.collect do |word|
-          yield word, errors, used_refs
+          yield word, errors
         end
 
-        commands << Command.new(line, cmd_parts, errors)
+        @commands << Command.new(line, cmd_parts, errors)
       end
 
       # remove references to unused parameters
-      shared_parameters.delete_if{|ref, param| not used_refs.include?(ref) }
+      @shared_parameters.delete_if{|ref, param| not @used_refs.include?(ref) }
 
       logger.debug "Order is OK"
-      new(:user => user, :commands => commands, :shared_parameters => shared_parameters)
+      Order.new(:user => @user, :commands => @commands, :shared_parameters => @shared_parameters)
     end
 
-    def self.dereference_param(shared_parameters, param, ref = nil)
-      if param.is_a? SharedParameter
-        [ref, param]
-      elsif param.is_a? ParameterReference
-        d_ref = param.reference
-        d_param = shared_parameters[d_ref]
-        return dereference_param(shared_parameters, d_param, d_ref)
+    def deref_param(param, old_ref = nil)
+      if param.is_a? CommandParameterRef
+        return deref_param(@shared_parameters[param.reference], param.reference)
+      elsif param.is_a? CommandParameter
+        return old_ref, param
+      elsif param.is_a? String or param.is_a? Fixnum
+        return deref_param(@shared_parameters[param], param)
       else
         nil
       end
     end
-
-    def valid?
-       @error.nil? and @user and not @commands.empty?
-    end
   end
 end
