From 6bdb6102c06c605d18f5d2cfba8ac806875ae13a Mon Sep 17 00:00:00 2001
From: thomascube <thomas@roundcube.net>
Date: Tue, 04 Jan 2011 17:00:35 -0500
Subject: [PATCH] Do charset detection in vcards with encoded values (#1485542)

---
 program/include/rcube_vcard.php |   32 ++++++++++++++++++++++----------
 1 files changed, 22 insertions(+), 10 deletions(-)

diff --git a/program/include/rcube_vcard.php b/program/include/rcube_vcard.php
index 9bbc32b..641d61e 100644
--- a/program/include/rcube_vcard.php
+++ b/program/include/rcube_vcard.php
@@ -28,6 +28,7 @@
  */
 class rcube_vcard
 {
+  private static $values_decoded = false;
   private $raw = array(
     'FN' => array(),
     'N' => array(array('','','','','')),
@@ -47,10 +48,10 @@
   /**
    * Constructor
    */
-  public function __construct($vcard = null, $charset = RCMAIL_CHARSET)
+  public function __construct($vcard = null, $charset = RCMAIL_CHARSET, $detect = false)
   {
     if (!empty($vcard))
-      $this->load($vcard, $charset);
+      $this->load($vcard, $charset, $detect);
   }
 
 
@@ -58,14 +59,23 @@
    * Load record from (internal, unfolded) vcard 3.0 format
    *
    * @param string vCard string to parse
+   * @param string Charset of string values
+   * @param boolean True if loading a 'foreign' vcard and extra heuristics for charset detection is required
    */
-  public function load($vcard, $charset = RCMAIL_CHARSET)
+  public function load($vcard, $charset = RCMAIL_CHARSET, $detect = false)
   {
+    self::$values_decoded = false;
     $this->raw = self::vcard_decode($vcard);
-    
+
     // resolve charset parameters
-    if ($charset == null)
-      $this->raw = $this->charset_convert($this->raw);
+    if ($charset == null) {
+      $this->raw = self::charset_convert($this->raw);
+    }
+    // vcard has encoded values and charset should be detected
+    else if ($detect && self::$values_decoded &&
+      ($detected_charset = self::detect_encoding(self::vcard_encode($this->raw))) && $detected_charset != RCMAIL_CHARSET) {
+        $this->raw = self::charset_convert($this->raw, $detected_charset);
+    }
 
     // find well-known address fields
     $this->displayname = $this->raw['FN'][0][0];
@@ -171,13 +181,13 @@
   
   /**
    * Convert a whole vcard (array) to UTF-8.
-   * Each member value that has a charset parameter will be converted.
+   * If $force_charset is null, each member value that has a charset parameter will be converted
    */
-  private function charset_convert($card)
+  private static function charset_convert($card, $force_charset = null)
   {
     foreach ($card as $key => $node) {
       foreach ($node as $i => $subnode) {
-        if (is_array($subnode) && $subnode['charset'] && ($charset = $subnode['charset'][0])) {
+        if (is_array($subnode) && (($charset = $force_charset) || ($subnode['charset'] && ($charset = $subnode['charset'][0])))) {
           foreach ($subnode as $j => $value) {
             if (is_numeric($j) && is_string($value))
               $card[$key][$i][$j] = rcube_charset_convert($value, $charset);
@@ -222,7 +232,7 @@
 
       if (preg_match('/^END:VCARD$/i', $line)) {
         // parse vcard
-        $obj = new rcube_vcard(self::cleanup($vcard_block), $charset);
+        $obj = new rcube_vcard(self::cleanup($vcard_block), $charset, true);
         if (!empty($obj->displayname))
           $out[] = $obj;
 
@@ -363,9 +373,11 @@
   {
     switch (strtolower($encoding)) {
       case 'quoted-printable':
+        self::$values_decoded = true;
         return quoted_printable_decode($value);
 
       case 'base64':
+        self::$values_decoded = true;
         return base64_decode($value);
 
       default:

--
Gitblit v1.9.1