commit 2891e0c2f55f7c42efb4be061ef2545b0797289b
Author: Marc Dequenes <duck@Orfeo.duckcorp.org>
Date:   Mon Feb 16 13:44:09 2009 +0100

    [evol] properly moved tmail signature handling out of postman in a library (which i should probably suggest upstream)

diff --git a/lib/tmail_extra.rb b/lib/tmail_extra.rb
new file mode 100644
index 0000000..5a6db0c
--- /dev/null
+++ b/lib/tmail_extra.rb
@@ -0,0 +1,41 @@
+# attempt to check PGP signature in a RFC3156-compliant way
+module TMail
+  class Mail
+    def is_pgp_signed?
+	content_type == "multipart/signed" and parts.size == 2 and parts[1].content_type == "application/pgp-signature"
+    end
+
+    def pgp_signature
+      return nil unless is_pgp_signed?
+      parts[1].decoded
+    end
+
+    def pgp_signed_part
+      return nil unless is_pgp_signed?
+      parts[0]
+    end
+
+    def verify_pgp_signature
+      return nil unless is_pgp_signed?
+
+      # using RAW part, without any decoding
+      # remove last EOL due to MIME protocol and properly convert all EOL to CRLF
+      content = parts[0].raw.chomp.gsub(/\r?\n/, "\r\n")
+      sig = pgp_signature()
+
+      logger.debug "Proper signed content detected"
+      sig_check = nil
+      GPGME::verify(sig, content) do |signature|
+        sig_check = signature
+      end
+
+      sig_check
+    end
+
+    protected
+
+    def raw
+      @port.read_all
+    end
+  end
+end
diff --git a/postman b/postman
index c33f212..b2ca2a9 100755
--- a/postman
+++ b/postman
@@ -11,6 +11,7 @@ require 'jcode'
 require 'log4r'
 require 'net/imap'
 require 'tmail'
+require 'tmail_extra'
 #require 'socket'
 #require 'fileutils'
 #require 'tempfile'
@@ -56,15 +57,6 @@ ActiveLdap::Base.establish_connection(ldap_config)
 
 #Socket.gethostname
 
-# needed to verify _untouched_ signed MIME part
-module TMail
-  class Mail
-    def raw
-      @port.read_all
-    end
-  end
-end
-
 #
 # TODO:
 #   - should be able to handle encrypted messages for user to send sensitive data (postman would need a GPG key too)
@@ -160,7 +152,7 @@ module CyborgHood
       #imap = Net::IMAP.new('imap.duckcorp.org', 993, true, "/etc/ssl/certs/duckcorp.crt", true)
       imap = Net::IMAP.new('localhost')
       logger.debug "Connected to IMAP server"
-      logger.debug imap.capability()
+      logger.debug "IMAP Capabilities: " + imap.capability.join(", ")
       imap.authenticate('LOGIN', @config.imap.login, @config.imap.passwd)
       logger.debug "Logged into IMAP account"
       #p imap.getquotaroot("INBOX")
@@ -175,33 +167,30 @@ module CyborgHood
 	logger.set_prefix("[#{mail.message_id}] ")
         logger.info "#{mail.from_addrs} -> #{mail.to_addrs}: #{mail.subject}"
         # ignore mails not signed
-	unless mail.content_type == "multipart/signed" and mail.parts.size == 2 and mail.parts[1].content_type == "application/pgp-signature"
+	unless mail.is_pgp_signed?
 	  logger.info "Mail not signed or not RFC3156 compliant"
           next
 	end
 
-        content = mail.parts[0].raw.chomp.gsub(/\r?\n/, "\r\n")
-        decoded_content = mail.parts[0].body
-        sig = mail.parts[1].decoded
+        decoded_content = mail.pgp_signed_part().body
 
         logger.debug "Proper signed content detected"
-        GPGME::verify(sig, content) do |signature|
-          if signature.status == 0
-            logger.info "Mail content was properly signed by key #{signature.fingerprint}"
-      	list = Person.find(:all, :attribute => 'keyFingerPrint', :value => signature.fingerprint)
-      	case list.size
-      	when 0
-      	  logger.info "Mail is from an unknow person"
-      	when 1
-      	  user = list.first
-      	  logger.info "Mail is from user #{user.uid} (#{user.cn})"
-      	  CommandParser.run(user, decoded_content)
-      	else
-      	  logger.warn "Multiple users match in database, so i guess there is a mistake. It is safer to skip..."
-      	end
-          else
-            logger.info "Mail content tampered or badly signed: " + signature.to_s
-          end
+	sig_check = mail.verify_pgp_signature()
+        if sig_check.status == 0
+          logger.info "Mail content was properly signed by key #{sig_check.fingerprint}"
+      	  list = Person.find(:all, :attribute => 'keyFingerPrint', :value => sig_check.fingerprint)
+      	  case list.size
+      	  when 0
+      	    logger.info "Mail is from an unknow person"
+      	  when 1
+      	    user = list.first
+      	    logger.info "Mail is from user #{user.uid} (#{user.cn})"
+      	    CommandParser.run(user, decoded_content)
+      	  else
+      	    logger.warn "Multiple users match in database, so i guess there is a mistake. It is safer to skip..."
+      	  end
+        else
+          logger.info "Mail content tampered or badly signed: " + sig_check.to_s
         end
       end
       imap.logout
