A first version of a gpg signature checker
[banana.git] / banana / mimepart.inc.php
index 9a2b503..5e603b9 100644 (file)
@@ -19,15 +19,20 @@ class BananaMimePart
     private $boundary     = null;
     private $filename     = null;
     private $format       = null;
+    private $sign_protocole = null;
 
     private $body         = null;
     private $multipart    = null;
 
     protected function __construct($data = null)
     {
-        if (!is_null($data)) {
+        if ($data instanceof BananaMimePart) {
+            foreach ($this as $key=>$value) {
+                $this->$key = $data->$key;
+            }
+        } elseif (!is_null($data)) {
             $this->fromRaw($data);
-        }   
+        }
     }
 
     protected function makeTextPart($body, $content_type, $encoding, $charset = null, $format = 'fixed')
@@ -50,11 +55,11 @@ class BananaMimePart
         $this->id           = $id;
         if (is_null($content_type) || $content_type == 'application/octet-stream') {
             $this->decodeContent();
-            $this->content_type = BananaMimePart::getMimeType($body, false);
-        }   
+            $this->content_type = BananaMimePart::getMimeType($this->body, false);
+        }
     }
 
-    protected function makeFilePart($file, $content_type =null, $disposition = 'attachment')
+    protected function makeFilePart(array $file, $content_type = null, $disposition = 'attachment')
     {
         $body = file_get_contents($file['tmp_name']);
         if ($body === false || strlen($body) != $file['size']) {
@@ -77,19 +82,20 @@ class BananaMimePart
         return true;
     }
 
-    protected function makeMultiPart($body, $content_type, $encoding, $boundary)
+    protected function makeMultiPart($body, $content_type, $encoding, $boundary, $sign_protocole)
     {
         $this->body         = $body;
         $this->content_type = $content_type;
         $this->encoding     = $encoding;
         $this->boundary     = $boundary;
+        $this->sign_protocole = $sign_protocole;
         $this->parse();
     }
 
     protected function convertToMultiPart()
     {
         if (!$this->isType('multipart', 'mixed')) {
-            $newpart = $this;
+            $newpart = new BananaMimePart($this);
             $this->content_type = 'multipart/mixed';
             $this->encoding     = '8bit';
             $this->multipart    = array($newpart);
@@ -106,10 +112,10 @@ class BananaMimePart
 
     public function addAttachment(array $file, $content_type = null, $disposition = 'attachment')
     {
-        $newpart = new BananaMimePart;
         if (!is_uploaded_file($file['tmp_name'])) {
             return false;
         }
+        $newpart = new BananaMimePart;
         if ($newpart->makeFilePart($file, $content_type, $disposition)) {
             $this->convertToMultiPart();
             $this->multipart[] = $newpart;
@@ -169,6 +175,7 @@ class BananaMimePart
             $filename     = $this->getHeader('content-disposition', '/filename="?([^ "]+?)"?\s*(;|$)/i');
             $format       = strtolower($this->getHeader('content-type', '/format="?([^ "]+?)"?\s*(;|$)/i'));
             $id           = $this->getHeader('content-id', '/<(.*?)>/');
+            $sign_protocole = strtolower($this->getHeader('content-type', '/protocol="?([^ "]+?)"?\s*(;|$)/i'));
             if (empty($filename)) {
                 $filename = $this->getHeader('content-type', '/name="?([^"]+)"?/');
             }
@@ -179,7 +186,7 @@ class BananaMimePart
             $this->makeTextPart($content, $content_type, $encoding, $charset, $format);
             break;
           case 'multipart':
-            $this->makeMultiPart($content, $content_type, $encoding, $boundary);
+            $this->makeMultiPart($content, $content_type, $encoding, $boundary, $sign_protocole);
             break;
           default:
             $this->makeDataPart($content, $content_type, $encoding, $filename, $disposition, $id);
@@ -206,20 +213,31 @@ class BananaMimePart
             $this->multipart = array();
         }
         $boundary =& $this->boundary;
-        $parts = preg_split("/\n--" . preg_quote($boundary, '/') . "(--|\n)/", $this->body, -1, PREG_SPLIT_NO_EMPTY);
+        $parts = preg_split("/(^|\n)--" . preg_quote($boundary, '/') . "(--|\n)/", $this->body, -1, PREG_SPLIT_NO_EMPTY);
+        $signed = $this->isType('multipart', 'signed');
+        $signature = null;
+        $signed_message = null;
         foreach ($parts as &$part) {
             $newpart = new BananaMimePart($part);
             if (!is_null($newpart->content_type)) {
+                if ($signed && $newpart->content_type == $this->sign_protocole) { 
+                    $signature = $newpart->body; 
+                } elseif ($signed) { 
+                    $signed_message = $part; 
+                } 
                 $this->multipart[] = $newpart;
             }
         }
+        if ($signed) {
+            $this->checkSignature($signature, $signed_message);
+        }
         $this->body = null;
     }
 
     public static function getMimeType($data, $is_filename = true)
     {
         if ($is_filename) {
-            $type = mime_content_type($arg);
+            $type = mime_content_type($data);
         } else {
             $arg = escapeshellarg($data);
             $type = preg_replace('/;.*/', '', trim(shell_exec("echo $arg | file -bi -")));
@@ -260,10 +278,10 @@ class BananaMimePart
             if (!is_utf8($val)) {
                 $val = utf8_encode($val);
             }
-        } else {
+        } elseif (strpos($val, '=') !== false) {
             $val = preg_replace('/(=\?.*?\?[bq]\?.*?\?=) (=\?.*?\?[bq]\?.*?\?=)/i', '\1\2', $val);
             $val = preg_replace('/=\?(.*?)\?([bq])\?(.*?)\?=/ie', 'BananaMimePart::_decodeHeader("\1", "\2", "\3")', $val);
-        }    
+        }
     }
 
     static public function &parseHeaders(array &$lines)
@@ -362,7 +380,8 @@ class BananaMimePart
         $headers['Content-Type'] = $this->content_type . ";"
             . ($this->filename ? " name=\"{$this->filename}\";" : '')
             . ($this->charset ? " charset=\"{$this->charset}\";" : '')
-            . ($this->boundary ? " boundary=\"{$this->boundary}\";" : "");
+            . ($this->boundary ? " boundary=\"{$this->boundary}\";" : "")
+            . ($this->format ? " format={$this->format}" : "");
         if ($this->encoding) {
             $headers['Content-Transfer-Encoding'] = $this->encoding;
         }
@@ -401,6 +420,8 @@ class BananaMimePart
                 $content .= "\n--{$this->boundary}\n" . $part->get(true);
             }
             $content .= "\n--{$this->boundary}--";
+        } elseif ($this->isType('text', 'plain')) {
+            $content .= banana_flow($this->body);
         } else {
             $content .= banana_wordwrap($this->body);
         }
@@ -423,8 +444,9 @@ class BananaMimePart
                                                                     'artid' => Banana::$artid,
                                                                     'part'  => $part)))
                  . '" alt="' . banana_htmlentities($this->filename) . '" />';
-        } elseif (!in_array($type, Banana::$msgshow_mimeparts)
-                  && !in_array($this->content_type, Banana::$msgshow_mimeparts)) {
+        } elseif ((!in_array($type, Banana::$msgshow_mimeparts)
+                  && !in_array($this->content_type, Banana::$msgshow_mimeparts))
+                  || $this->disposition == 'attachment') {
             $part = $this->id ? $this->id : $this->filename;
             if (!$part) {
                 $part = $this->content_type;
@@ -434,14 +456,13 @@ class BananaMimePart
                                                  'part'  => $part,
                                                  'text'  => $this->filename ? $this->filename : $this->content_type,
                                                  'img'   => 'save')) . ']';
-        } else {
-            if ($type == 'multipart' && ($subtype == 'mixed' || $subtype == 'report')) {
-                $text = '';
-                foreach ($this->multipart as &$part) {
-                    $text .= $part->toHtml();
-                }
-                return $text;
+        } elseif ($type == 'multipart' && ($subtype == 'mixed' || $subtype == 'report')) {
+            $text = '';
+            foreach ($this->multipart as &$part) {
+                $text .= $part->toHtml();
             }
+            return $text;
+        } else {
             switch ($subtype) {
               case 'html': return banana_formatHtml($this);
               case 'enriched': case 'richtext': return banana_formatRichText($this);
@@ -593,6 +614,13 @@ class BananaMimePart
         }
         return null;
     }
+
+    private function checkSignature($signature, $message)
+    {
+        file_put_contents('machin.asc', $signature);
+        file_put_contents('message', str_replace(array("\r\n", "\n"), array("\n", "\r\n"), $message));
+        passthru('gpg --verify machin.asc message');
+    }
 }
 
 // vim:set et sw=4 sts=4 ts=4 enc=utf-8: