alecpl
2011-04-14 ae1db2239e4c2a67f09ecc6d35b70fc7079425bf
program/include/rcube_vcard.php
@@ -40,6 +40,7 @@
    'notes'    => 'NOTE',
    'email'    => 'EMAIL',
    'address'  => 'ADR',
    'jobtitle' => 'TITLE',
    'gender'      => 'X-GENDER',
    'maidenname'  => 'X-MAIDENNAME',
    'anniversary' => 'X-ANNIVERSARY',
@@ -135,11 +136,15 @@
    $typemap = $this->typemap;
    
    // copy name fields to output array
    foreach (array('firstname','surname','middlename','nickname','organization') as $col)
      $out[$col] = $this->$col;
    foreach (array('firstname','surname','middlename','nickname','organization') as $col) {
      if (strlen($this->$col))
        $out[$col] = $this->$col;
    }
    
    $out['prefix'] = $this->raw['N'][0][3];
    $out['suffix'] = $this->raw['N'][0][4];
    if ($this->raw['N'][0][3])
      $out['prefix'] = $this->raw['N'][0][3];
    if ($this->raw['N'][0][4])
      $out['suffix'] = $this->raw['N'][0][4];
    
    // convert from raw vcard data into associative data for Roundcube
    foreach (array_flip($this->fieldmap) as $tag => $col) {
@@ -161,6 +166,10 @@
              }
            }
          }
          // force subtype if none set
          if (preg_match('/^(email|phone|address|website)/', $key) && !$subtype)
            $subtype = 'other';
          
          if ($subtype)
            $key .= ':' . $subtype;
@@ -273,8 +282,14 @@
        break;
        
      case 'photo':
        $encoded = !preg_match('![^a-z0-9/=+-]!i', $value);
        $this->raw['PHOTO'][0] = array(0 => $encoded ? $value : base64_encode($value), 'BASE64' => true);
        if (strpos($value, 'http:') === 0) {
            // TODO: fetch file from URL and save it locally?
            $this->raw['PHOTO'][0] = array(0 => $value, 'URL' => true);
        }
        else {
            $encoded = !preg_match('![^a-z0-9/=+-]!i', $value);
            $this->raw['PHOTO'][0] = array(0 => $encoded ? $value : base64_encode($value), 'BASE64' => true);
        }
        break;
        
      case 'email':
@@ -418,8 +433,14 @@
  {
    // Convert special types (like Skype) to normal type='skype' classes with this simple regex ;)
    $vcard = preg_replace(
      '/item(\d+)\.(TEL|URL)([^:]*?):(.*?)item\1.X-ABLabel:(?:_\$!<)?([\w-() ]*)(?:>!\$_)?./s',
      '/item(\d+)\.(TEL|EMAIL|URL)([^:]*?):(.*?)item\1.X-ABLabel:(?:_\$!<)?([\w-() ]*)(?:>!\$_)?./s',
      '\2;type=\5\3:\4',
      $vcard);
    // convert Apple X-ABRELATEDNAMES into X-* fields for better compatibility
    $vcard = preg_replace_callback(
      '/item(\d+)\.(X-ABRELATEDNAMES)([^:]*?):(.*?)item\1.X-ABLabel:(?:_\$!<)?([\w-() ]*)(?:>!\$_)?./s',
      array('self', 'x_abrelatednames_callback'),
      $vcard);
    // Remove cruft like item1.X-AB*, item1.ADR instead of ADR, and empty lines
@@ -436,10 +457,33 @@
    return $vcard;
  }
  private static function x_abrelatednames_callback($matches)
  {
    return 'X-' . strtoupper($matches[5]) . $matches[3] . ':'. $matches[4];
  }
  private static function rfc2425_fold_callback($matches)
  {
    return ":\n  ".rtrim(chunk_split($matches[1], 72, "\n  "));
    // use mb string function if available
    if (function_exists('mb_ereg_replace')) {
      return ":\n  " . mb_ereg_replace('(.{70})', "\\1\n  ", $matches[1]);
    }
    // chunk_split string and avoid lines breaking multibyte characters
    $c = 66;
    $out = ":\n  " . substr($matches[1], 0, $c);
    for ($n = $c; $c < strlen($matches[1]); $c++) {
      // break if length > 70 or mutlibyte character starts after position 66
      if ($n > 70 || ($n > 66 && ord($matches[1][$c]) >> 6 == 3)) {
        $out .= "\n  ";
        $n = 0;
      }
      $out .= $matches[1][$c];
      $n++;
    }
    return $out;
  }
  private static function rfc2425_fold($val)
@@ -627,6 +671,12 @@
    if (substr($string, 0, 2) == "\xFF\xFE")     return 'UTF-16LE';  // Little Endian
    if (substr($string, 0, 3) == "\xEF\xBB\xBF") return 'UTF-8';
    // heuristics
    if ($string[0] == "\0" && $string[1] == "\0" && $string[2] == "\0" && $string[3] != "\0") return 'UTF-32BE';
    if ($string[0] != "\0" && $string[1] == "\0" && $string[2] == "\0" && $string[3] == "\0") return 'UTF-32LE';
    if ($string[0] == "\0" && $string[1] != "\0" && $string[2] == "\0" && $string[3] != "\0") return 'UTF-16BE';
    if ($string[0] != "\0" && $string[1] == "\0" && $string[2] != "\0" && $string[3] == "\0") return 'UTF-16LE';
    // use mb_detect_encoding()
    $encodings = array('UTF-8', 'ISO-8859-1', 'ISO-8859-2', 'ISO-8859-3',
      'ISO-8859-4', 'ISO-8859-5', 'ISO-8859-6', 'ISO-8859-7', 'ISO-8859-8', 'ISO-8859-9',