alecpl
2011-01-20 6c68cbde375cd425ed98c037e2fa964aca552744
- Fix handling of comments inside an email address spec. (#1487673)


3 files modified
128 ■■■■ changed files
CHANGELOG 1 ●●●● patch | view | raw | blame | history
program/include/rcube_imap.php 82 ●●●●● patch | view | raw | blame | history
tests/maildecode.php 45 ●●●●● patch | view | raw | blame | history
CHANGELOG
@@ -1,6 +1,7 @@
CHANGELOG Roundcube Webmail
===========================
- Fix handling of comments inside an email address spec. (#1487673)
- Fix randomly disappearing folders list in IE (#1487704)
- Fix list column add/removal in IE (#1487703)
- Fix login redirect issues (#1487686)
program/include/rcube_imap.php
@@ -4696,10 +4696,13 @@
    private function _parse_address_list($str, $decode=true)
    {
        // remove any newlines and carriage returns before
        $a = rcube_explode_quoted_string('[,;]', preg_replace( "/[\r\n]/", " ", $str));
        $str = preg_replace('/\r?\n(\s|\t)?/', ' ', $str);
        // extract list items, remove comments
        $str = self::explode_header_string(',;', $str, true);
        $result = array();
        foreach ($a as $key => $val) {
        foreach ($str as $key => $val) {
            $name    = '';
            $address = '';
            $val     = trim($val);
@@ -4741,6 +4744,81 @@
    /**
     * Explodes header (e.g. address-list) string into array of strings
     * using specified separator characters with proper handling
     * of quoted-strings and comments (RFC2822)
     *
     * @param string $separator       String containing separator characters
     * @param string $str             Header string
     * @param bool   $remove_comments Enable to remove comments
     *
     * @return array Header items
     */
    static function explode_header_string($separator, $str, $remove_comments=false)
    {
        $length  = strlen($str);
        $result  = array();
        $quoted  = false;
        $comment = 0;
        $out     = '';
        for ($i=0; $i<$length; $i++) {
            // we're inside a quoted string
            if ($quoted) {
                if ($str[$i] == '"') {
                    $quoted = false;
                }
                else if ($str[$i] == '\\') {
                    if ($comment <= 0) {
                        $out .= '\\';
                    }
                    $i++;
                }
            }
            // we're inside a comment string
            else if ($comment > 0) {
                    if ($str[$i] == ')') {
                        $comment--;
                    }
                    else if ($str[$i] == '(') {
                        $comment++;
                    }
                    else if ($str[$i] == '\\') {
                        $i++;
                    }
                    continue;
            }
            // separator, add to result array
            else if (strpos($separator, $str[$i]) !== false) {
                    if ($out) {
                        $result[] = $out;
                    }
                    $out = '';
                    continue;
            }
            // start of quoted string
            else if ($str[$i] == '"') {
                    $quoted = true;
            }
            // start of comment
            else if ($remove_comments && $str[$i] == '(') {
                    $comment++;
            }
            if ($comment <= 0) {
                $out .= $str[$i];
            }
        }
        if ($out && $comment <= 0) {
            $result[] = $out;
        }
        return $result;
    }
    /**
     * This is our own debug handler for the IMAP connection
     * @access public
     */
tests/maildecode.php
@@ -35,28 +35,45 @@
        8  => '"Test<Test" <test@domain.tld>',
        9  => '=?ISO-8859-1?B?VGVzdAo=?= <test@domain.tld>',
        10 => '=?ISO-8859-1?B?VGVzdAo=?=<test@domain.tld>', // #1487068
        // comments in address (#1487673)
        11 => 'Test (comment) <test@domain.tld>',
        12 => '"Test" (comment) <test@domain.tld>',
        13 => '"Test (comment)" (comment) <test@domain.tld>',
        14 => '(comment) <test@domain.tld>',
        15 => 'Test <test@(comment)domain.tld>',
        16 => 'Test Test ((comment)) <test@domain.tld>',
        17 => 'test@domain.tld (comment)',
        18 => '"Test,Test" <test@domain.tld>',
    );
    $results = array(
        0  => array('', 'test@domain.tld'),
        1  => array('', 'test@domain.tld'),
        2  => array('Test', 'test@domain.tld'),
        3  => array('Test Test', 'test@domain.tld'),
        4  => array('Test Test', 'test@domain.tld'),
        5  => array('Test Test', 'test@domain.tld'),
        6  => array('Test Test', 'test@domain.tld'),
        7  => array('Test " Test', 'test@domain.tld'),
        8  => array('Test<Test', 'test@domain.tld'),
        9  => array('Test', 'test@domain.tld'),
        10 => array('Test', 'test@domain.tld'),
        0  => array(1, '', 'test@domain.tld'),
        1  => array(1, '', 'test@domain.tld'),
        2  => array(1, 'Test', 'test@domain.tld'),
        3  => array(1, 'Test Test', 'test@domain.tld'),
        4  => array(1, 'Test Test', 'test@domain.tld'),
        5  => array(1, 'Test Test', 'test@domain.tld'),
        6  => array(1, 'Test Test', 'test@domain.tld'),
        7  => array(1, 'Test " Test', 'test@domain.tld'),
        8  => array(1, 'Test<Test', 'test@domain.tld'),
        9  => array(1, 'Test', 'test@domain.tld'),
        10 => array(1, 'Test', 'test@domain.tld'),
        11 => array(1, 'Test', 'test@domain.tld'),
        12 => array(1, 'Test', 'test@domain.tld'),
        13 => array(1, 'Test (comment)', 'test@domain.tld'),
        14 => array(1, '', 'test@domain.tld'),
        15 => array(1, 'Test', 'test@domain.tld'),
        16 => array(1, 'Test Test', 'test@domain.tld'),
        17 => array(1, '', 'test@domain.tld'),
        18 => array(1, 'Test,Test', 'test@domain.tld'),
    );
    foreach ($headers as $idx => $header) {
      $res = $this->app->imap->decode_address_list($header);
      $this->assertEqual(1, count($res), "Rows number in result for header: " . $header);
      $this->assertEqual($results[$idx][0], $res[1]['name'], "Name part decoding for header: " . $header);
      $this->assertEqual($results[$idx][1], $res[1]['mailto'], "Name part decoding for header: " . $header);
      $this->assertEqual($results[$idx][0], count($res), "Rows number in result for header: " . $header);
      $this->assertEqual($results[$idx][1], $res[1]['name'], "Name part decoding for header: " . $header);
      $this->assertEqual($results[$idx][2], $res[1]['mailto'], "Name part decoding for header: " . $header);
    }
  }