diff options
| -rw-r--r-- | CHANGELOG | 1 | ||||
| -rw-r--r-- | program/include/rcube_imap_generic.php | 245 | 
2 files changed, 129 insertions, 117 deletions
| @@ -1,6 +1,7 @@  CHANGELOG RoundCube Webmail  =========================== +- Parse untagged CAPABILITY response for LOGIN command (#1486742)  - Renamed all php-cli scripts to use .sh extension  - Some files from /bin + spellchecking actions moved to the new 'utils' task  - Added thread tree icons diff --git a/program/include/rcube_imap_generic.php b/program/include/rcube_imap_generic.php index 6ca6c8f5a..1cb4d4cc2 100644 --- a/program/include/rcube_imap_generic.php +++ b/program/include/rcube_imap_generic.php @@ -30,7 +30,7 @@   * Struct representing an e-mail message header   *   * @package    Mail - * @author     Aleksander Machniak <alec@alec.pl>  + * @author     Aleksander Machniak <alec@alec.pl>   */  class rcube_mail_header  { @@ -80,7 +80,7 @@ class iilBasicHeader extends rcube_mail_header   * PHP based wrapper class to connect to an IMAP server   *   * @package    Mail - * @author     Aleksander Machniak <alec@alec.pl>  + * @author     Aleksander Machniak <alec@alec.pl>   */  class rcube_imap_generic  { @@ -118,7 +118,7 @@ class rcube_imap_generic      function __construct()      {      } -               +      private function putLine($string, $endln=true)      {          if (!$this->fp) @@ -127,7 +127,7 @@ class rcube_imap_generic  		if (!empty($this->prefs['debug_mode'])) {      		write_log('imap', 'C: '. rtrim($string));  	    } -         +          return fputs($this->fp, $string . ($endln ? "\r\n" : ''));      } @@ -173,16 +173,16 @@ class rcube_imap_generic  	    if (!$this->fp) {      		return NULL;  	    } -     +  	    if (!$size) {  		    $size = 1024;  	    } -     +  	    do {  		    if (feof($this->fp)) {  			    return $line ? $line : NULL;  		    } -		 +      		$buffer = fgets($this->fp, $size);      		if ($buffer === false) { @@ -204,11 +204,11 @@ class rcube_imap_generic  	    $line = chop($line);  	    if (preg_match('/\{[0-9]+\}$/', $line)) {  		    $out = ''; -         +  		    preg_match_all('/(.*)\{([0-9]+)\}$/', $line, $a);  		    $bytes = $a[2][0];  		    while (strlen($out) < $bytes) { -			    $line = $this->readBytes($bytes);  +			    $line = $this->readBytes($bytes);  			    if ($line === NULL)  				    break;  			    $out .= $line; @@ -216,7 +216,7 @@ class rcube_imap_generic  		    $line = $a[1][0] . '"' . ($escape ? $this->Escape($out) : $out) . '"';  	    } -	 +          return $line;      } @@ -237,17 +237,23 @@ class rcube_imap_generic      		}      		$len = $data_len;  	    } -	 +  	    return $data;      }      // don't use it in loops, until you exactly know what you're doing -    private function readReply() +    private function readReply($untagged=null)      {  	    do {  		    $line = trim($this->readLine(1024)); +            // store untagged response lines +		    if ($line[0] == '*') +                $untagged[] = $line;  	    } while ($line[0] == '*'); +        if ($untagged) +            $untagged = join("\n", $untagged); +  	    return $line;      } @@ -331,7 +337,7 @@ class rcube_imap_generic  		    return false;  	    } -	    // get capabilities (only once) because initial  +	    // get capabilities (only once) because initial  	    // optional CAPABILITY response may differ  	    $this->capability = array(); @@ -348,7 +354,7 @@ class rcube_imap_generic  			    }  		    }  	    } while ($a[0] != 'cp01'); -	 +  	    $this->capability_readed = true;  	    if (in_array($name, $this->capability)) { @@ -368,7 +374,7 @@ class rcube_imap_generic      {          $ipad = '';          $opad = ''; -     +          // initialize ipad, opad          for ($i=0; $i<64; $i++) {              $ipad .= chr(0x36); @@ -380,17 +386,17 @@ class rcube_imap_generic          for ($i=0; $i<$padLen; $i++) {              $pass .= chr(0);          } -     +          // generate hash          $hash  = md5($this->_xor($pass,$opad) . pack("H*", md5($this->_xor($pass, $ipad) . base64_decode($encChallenge)))); -     +          // generate reply          $reply = base64_encode($user . ' ' . $hash); -     +          // send result, get reply          $this->putLine($reply);          $line = $this->readLine(1024); -     +          // process result          $result = $this->parseResult($line);          if ($result == 0) { @@ -408,7 +414,12 @@ class rcube_imap_generic      {          $this->putLine('a001 LOGIN "'.$this->escape($user).'" "'.$this->escape($password).'"'); -        $line = $this->readReply(); +        $line = $this->readReply($untagged); + +        // re-set capabilities list if untagged CAPABILITY response provided +	    if (preg_match('/\* CAPABILITY (.+)/i', $untagged, $matches)) { +		    $this->capability = explode(' ', strtoupper($matches[1])); +	    }          // process result          $result = $this->parseResult($line); @@ -420,7 +431,7 @@ class rcube_imap_generic          @fclose($this->fp);          $this->fp = false; -     +          $this->error    = "Authentication for $user failed (LOGIN): $line";          $this->errornum = $result; @@ -433,11 +444,11 @@ class rcube_imap_generic      		$this->rootdir = $this->prefs['rootdir'];  		    return true;  	    } -	 +          if (!$this->getCapability('NAMESPACE')) {  	        return false;  	    } -     +  	    if (!$this->putLine("ns1 NAMESPACE")) {              return false;          } @@ -463,12 +474,12 @@ class rcube_imap_generic  	    if (count($first_userspace)!=2) {  	        return false;  	    } -     +  	    $this->rootdir            = $first_userspace[0];  	    $this->delimiter          = $first_userspace[1];  	    $this->prefs['rootdir']   = substr($this->rootdir, 0, -1);  	    $this->prefs['delimiter'] = $this->delimiter; -	 +  	    return true;      } @@ -478,8 +489,8 @@ class rcube_imap_generic       * INBOX.foo -> .       * INBOX/foo -> /       * INBOX\foo -> \ -     *  -     * @return mixed A delimiter (string), or false.  +     * +     * @return mixed A delimiter (string), or false.       * @see connect()       */      function getHierarchyDelimiter() @@ -497,7 +508,7 @@ class rcube_imap_generic  	    if (!$this->putLine('ghd LIST "" ""')) {  	        return false;  	    } -     +  	    do {  		    $line = $this->readLine(500);  		    if ($line[0] == '*') { @@ -531,7 +542,7 @@ class rcube_imap_generic  	    if (!is_array($data)) {  	        return false;  	    } -     +  	    // extract user space data (opposed to global/shared space)  	    $user_space_data = $data[0];  	    if (!is_array($user_space_data)) { @@ -545,7 +556,7 @@ class rcube_imap_generic  	    }  	    // extract delimiter -	    $delimiter = $first_userspace[1];	 +	    $delimiter = $first_userspace[1];  	    return $delimiter;      } @@ -566,7 +577,7 @@ class rcube_imap_generic  	    $message = "INITIAL: $auth_method\n";  	    $result = false; -	 +  	    // initialize connection  	    $this->error    = '';  	    $this->errornum = 0; @@ -648,7 +659,7 @@ class rcube_imap_generic  				    $this->errornum = -2;  				    return false;  			    } -			 +  			    // Now we're authenticated, capabilities need to be reread  			    $this->clearCapability();          	} @@ -675,18 +686,18 @@ class rcube_imap_generic  		    if ($line[0] == '+') {  			    // got a challenge string, try CRAM-MD5  			    $result = $this->authenticate($user, $password, substr($line,2)); -        		 +  			    // stop if server sent BYE response  			    if ($result == -3) {  				    return false;  			    }  		    } -		 +  		    if (!is_resource($result) && $orig_method == 'CHECK') {  			    $auth_method = 'PLAIN';  		    }  	    } -		 +  	    if ($auth_method == 'PLAIN') {  		    // do plain text auth  		    $result = $this->login($user, $password); @@ -727,7 +738,7 @@ class rcube_imap_generic  	    if ($this->selected == $mailbox) {  		    return true;  	    } -     +  	    if ($this->putLine("sel1 SELECT \"".$this->escape($mailbox).'"')) {  		    do {  			    $line = chop($this->readLine(300)); @@ -763,7 +774,7 @@ class rcube_imap_generic  	    if (empty($mailbox)) {  		    $mailbox = 'INBOX';  	    } -     +  	    $this->select($mailbox);  	    if ($this->selected == $mailbox) {  		    return $this->recent; @@ -777,7 +788,7 @@ class rcube_imap_generic  	    if ($refresh) {  		    $this->selected = '';  	    } -	 +  	    $this->select($mailbox);  	    if ($this->selected == $mailbox) {  		    return $this->exists; @@ -792,7 +803,7 @@ class rcube_imap_generic  	    if ($field == 'INTERNALDATE') {  	        $field = 'ARRIVAL';  	    } -	 +  	    $fields = array('ARRIVAL' => 1,'CC' => 1,'DATE' => 1,              'FROM' => 1, 'SIZE' => 1, 'SUBJECT' => 1, 'TO' => 1); @@ -804,9 +815,9 @@ class rcube_imap_generic  	    if (!$this->select($mailbox)) {  	        return false;  	    } -     +  	    $is_uid = $is_uid ? 'UID ' : ''; -	 +  	    // message IDs  	    if (is_array($add))  		    $add = $this->compressMessageSet(join(',', $add)); @@ -828,14 +839,14 @@ class rcube_imap_generic  			    $data .= $line;  		    }  	    } while (!$this->startsWith($line, 's ', true, true)); -	 +  	    $result_code = $this->parseResult($line); -	 +  	    if ($result_code != 0) {              $this->error = "Sort: $line";              return false;  	    } -	 +  	    return preg_split('/\s+/', $data, -1, PREG_SPLIT_NO_EMPTY);      } @@ -851,9 +862,9 @@ class rcube_imap_generic  			    return false;  		    }  	    } -	 +  	    $index_field = empty($index_field) ? 'DATE' : strtoupper($index_field); -	 +      	$fields_a['DATE']         = 1;  	    $fields_a['INTERNALDATE'] = 4;      	$fields_a['ARRIVAL'] 	  = 4; @@ -877,7 +888,7 @@ class rcube_imap_generic  	    if (!$this->select($mailbox)) {  		    return false;  	    } -	 +      	// build FETCH command string  	    $key     = 'fhi0';  	    $cmd     = $uidfetch ? 'UID FETCH' : 'FETCH'; @@ -912,7 +923,7 @@ class rcube_imap_generic  		    if (preg_match('/^\* ([0-9]+) FETCH/', $line, $m)) {              	$id     = $m[1];  			    $flags  = NULL; -					 +  			    if ($skip_deleted && preg_match('/FLAGS \(([^)]+)\)/', $line, $matches)) {  				    $flags = explode(' ', strtoupper($matches[1]));  				    if (in_array('\\DELETED', $flags)) { @@ -962,28 +973,28 @@ class rcube_imap_generic  		    }  	    } while (!$this->startsWith($line, $key, true, true)); -	    return $result;	 +	    return $result;      }      private function compressMessageSet($message_set)      { -	    // given a comma delimited list of independent mid's,  +	    // given a comma delimited list of independent mid's,  	    // compresses by grouping sequences together -	 +  	    // if less than 255 bytes long, let's not bother  	    if (strlen($message_set)<255) {  	        return $message_set;  	    } -     +  	    // see if it's already been compress  	    if (strpos($message_set, ':') !== false) {  	        return $message_set;  	    } -     +  	    // separate, then sort  	    $ids = explode(',', $message_set);  	    sort($ids); -	 +  	    $result = array();  	    $start  = $prev = $ids[0]; @@ -1006,7 +1017,7 @@ class rcube_imap_generic  	    } else {      	    $result[] = $start.':'.$prev;  	    } -     +  	    // return as comma separated string  	    return implode(',', $result);      } @@ -1051,14 +1062,14 @@ class rcube_imap_generic  		    $message_set = join(',', $message_set);          else if (empty($message_set))  		    $message_set = '1:*'; -	 +  	    return $this->fetchHeaderIndex($mailbox, $message_set, 'UID', false);      }      function fetchHeaders($mailbox, $message_set, $uidfetch=false, $bodystr=false, $add='')      {  	    $result = array(); -	 +  	    if (!$this->select($mailbox)) {  		    return false;  	    } @@ -1089,15 +1100,15 @@ class rcube_imap_generic  	    do {  		    $line = $this->readLine(1024);  		    $line = $this->multLine($line); -             +              if (!$line)                  break; -             +  		    $a    = explode(' ', $line);  		    if (($line[0] == '*') && ($a[2] == 'FETCH')) {  			    $id = $a[1]; -             +  			    $result[$id]            = new rcube_mail_header;  			    $result[$id]->id        = $id;  			    $result[$id]->subject   = ''; @@ -1133,16 +1144,16 @@ class rcube_imap_generic  				    	}  					    $time_str = str_replace('"', '', $time_str); -					 +  					    // if time is gmt...  		                $time_str = str_replace('GMT','+0000',$time_str); -					 +  					    $result[$id]->internaldate = $time_str;      					$result[$id]->timestamp = $this->StrToTime($time_str);  	    				$result[$id]->date = $time_str;  		    		} -			    	// BODYSTRUCTURE  +			    	// BODYSTRUCTURE  				    if($bodystr) {  					    while (!preg_match('/ BODYSTRUCTURE (.*) BODY\[HEADER.FIELDS/s', $line, $m)) {  						    $line2 = $this->readLine(1024); @@ -1168,13 +1179,13 @@ class rcube_imap_generic  				// So, we'll read ahead, and if the one we're reading now is a valid header, we'll  				// process the previous line.  Otherwise, we'll keep adding the strings until we come  				// to the next valid header line. -	 +  			    do {  				    $line = chop($this->readLine(300), "\r\n");      				// The preg_match below works around communigate imap, which outputs " UID <number>)".  	    			// Without this, the while statement continues on and gets the "FH0 OK completed" message. -		    		// If this loop gets the ending message, then the outer loop does not receive it from radline on line 1249.   +		    		// If this loop gets the ending message, then the outer loop does not receive it from radline on line 1249.  			    	// This in causes the if statement on line 1278 to never be true, which causes the headers to end up missing  				    // If the if statement was changed to pick up the fh0 from this loop, then it causes the outer loop to spin      				// An alternative might be: @@ -1198,7 +1209,7 @@ class rcube_imap_generic      			// patch from "Maksim Rubis" <siburny@hotmail.com>  	    		} while ($line[0] != ')' && !$this->startsWith($line, $key, true)); -    			if (strncmp($line, $key, strlen($key))) {  +    			if (strncmp($line, $key, strlen($key))) {  	    			// process header, fill rcube_mail_header obj.  		    		// initialize  			    	if (is_array($headers)) { @@ -1211,10 +1222,10 @@ class rcube_imap_generic  			    	// create array with header field:data      				while ( list($lines_key, $str) = each($lines) ) {  	    				list($field, $string) = $this->splitHeaderLine($str); -		    			 +  			    		$field  = strtolower($field);  				    	$string = preg_replace('/\n\s*/', ' ', $string); -					     +      					switch ($field) {  	        			case 'date';  			    			$result[$id]->date = $string; @@ -1280,7 +1291,7 @@ class rcube_imap_generic  	    		if (!empty($flags_str)) {  		    		$flags_str = preg_replace('/[\\\"]/', '', $flags_str);  			    	$flags_a   = explode(' ', $flags_str); -					 +  				    if (is_array($flags_a)) {      				//	reset($flags_a);  	    				foreach($flags_a as $flag) { @@ -1343,12 +1354,12 @@ class rcube_imap_generic  	    $c = count($a);  	    if ($c > 0) { -		     +  			// Strategy:  			// First, we'll create an "index" array. -			// Then, we'll use sort() on that array,  +			// Then, we'll use sort() on that array,  			// and use that to sort the main array. -                 +  		    // create "index" array  		    $index = array();  		    reset($a); @@ -1366,7 +1377,7 @@ class rcube_imap_generic  			    }      			$index[$key]=$data;  	    	} -		 +  		    // sort index      		$i = 0;  	    	if ($flag == 'ASC') { @@ -1375,7 +1386,7 @@ class rcube_imap_generic          	    arsort($index);  		    } -    		// form new array based on index  +    		// form new array based on index  	    	$result = array();  		    reset($index);      		while (list($key, $val) = each($index)) { @@ -1383,7 +1394,7 @@ class rcube_imap_generic  		    	$i++;  		    }  	    } -	 +  	    return $result;      } @@ -1392,7 +1403,7 @@ class rcube_imap_generic  	    if (!$this->select($mailbox)) {              return -1;          } -		 +          $c = 0;  		$command = $messages ? "UID EXPUNGE $messages" : "EXPUNGE"; @@ -1406,7 +1417,7 @@ class rcube_imap_generic              	$c++;          	}  		} while (!$this->startsWith($line, 'exp1', true, true)); -		 +  		if ($this->parseResult($line) == 0) {  			$this->selected = ''; // state has changed, need to reselect  			return $c; @@ -1420,13 +1431,13 @@ class rcube_imap_generic  	    if ($mod != '+' && $mod != '-') {  	        return -1;  	    } -     +  	    $flag = $this->flags[strtoupper($flag)]; -     +  	    if (!$this->select($mailbox)) {  	        return -1;  	    } -     +          $c = 0;  	    if (!$this->putLine("flg UID STORE $messages {$mod}FLAGS ($flag)")) {              return false; @@ -1464,11 +1475,11 @@ class rcube_imap_generic  	    if (empty($from) || empty($to)) {  	        return -1;  	    } -     +  	    if (!$this->select($from)) {              return -1;  	    } -	 +          $this->putLine("cpy1 UID COPY $messages \"".$this->escape($to)."\"");  	    $line = $this->readReply();  	    return $this->parseResult($line); @@ -1529,7 +1540,7 @@ class rcube_imap_generic  		    	$node += $this->parseThread($str, $start + 1, $off - 1, $root, $parent, $depth, $depthmap, $haschildren);  		    }  	    } -	 +  	    return $node;      } @@ -1542,7 +1553,7 @@ class rcube_imap_generic      	$encoding  = $encoding ? trim($encoding) : 'US-ASCII';  	    $algorithm = $algorithm ? trim($algorithm) : 'REFERENCES';  	    $criteria  = $criteria ? 'ALL '.trim($criteria) : 'ALL'; -		 +  	    if (!$this->putLineC("thrd1 THREAD $algorithm $encoding $criteria")) {  		    return false;  	    } @@ -1562,7 +1573,7 @@ class rcube_imap_generic  	    }      	$this->error = "Thread: $line"; -	    return false;	 +	    return false;      }      function search($folder, $criteria, $return_uid=false) @@ -1593,7 +1604,7 @@ class rcube_imap_generic  	    }      	$this->error = "Search: $line"; -	    return false;	 +	    return false;      }      function move($messages, $from, $to) @@ -1601,7 +1612,7 @@ class rcube_imap_generic          if (!$from || !$to) {              return -1;          } -     +          $r = $this->copy($messages, $from, $to);          if ($r==0) { @@ -1625,11 +1636,11 @@ class rcube_imap_generic  		if (empty($mailbox)) {  	        $mailbox = '*';  	    } -	 +  	    if (empty($ref) && $this->rootdir) {  	        $ref = $this->rootdir;  	    } -     +          if ($subscribed) {              $key     = 'lsb';              $command = 'LSUB'; @@ -1644,7 +1655,7 @@ class rcube_imap_generic  		    $this->error = "Couldn't send $command command";  	        return false;  	    } -     +  	    // get folder list  	    do {  		    $line = $this->readLine(500); @@ -1677,7 +1688,7 @@ class rcube_imap_generic  	    if (!$this->select($mailbox)) {  		    return false;  	    } -	 +      	$result = false;  	    $parts  = (array) $parts;      	$key    = 'fmh0'; @@ -1688,14 +1699,14 @@ class rcube_imap_generic  	    // format request  	    foreach($parts as $part)  		    $peeks[] = "BODY.PEEK[$part.$type]"; -	 +  	    $request = "$key FETCH $id (" . implode(' ', $peeks) . ')';  	    // send request  	    if (!$this->putLine($request)) {  	        return false;  	    } -         +  	    do {          	$line = $this->readLine(1000);          	$line = $this->multLine($line); @@ -1740,7 +1751,7 @@ class rcube_imap_generic  	    	default:  		    	$mode = 0;  	    } -	 +     		$reply_key = '* ' . $id;      	$result = false; @@ -1788,11 +1799,11 @@ class rcube_imap_generic  	        $sizeStr  = substr($line, $from, $len);          	$bytes    = (int)$sizeStr;  			$prev	  = ''; -			 +          	while ($bytes > 0) {      		    $line = $this->readLine(1024);              	$len  = strlen($line); -                 +  		        if ($len > $bytes) {              		$line = substr($line, 0, $bytes);  					$len = strlen($line); @@ -1811,7 +1822,7 @@ class rcube_imap_generic  					}  					else  						$prev = ''; -						 +  					if ($file)  						fwrite($file, base64_decode($line));              		else if ($print) @@ -1847,7 +1858,7 @@ class rcube_imap_generic  				}          	}      	} -	     +          // read in anything up until last line  		if (!$end)  			do { @@ -1922,7 +1933,7 @@ class rcube_imap_generic      {          $query = 'usub1 UNSUBSCRIBE "' . $this->escape($folder) . '"';  	    $this->putLine($query); -     +  	    $line = trim($this->readLine(512));  	    return ($this->parseResult($line) == 0);      } @@ -1959,7 +1970,7 @@ class rcube_imap_generic  		    do {  			    $line = $this->readLine();      		} while (!$this->startsWith($line, 'a ', true, true)); -	 +  	    	$result = ($this->parseResult($line) == 0);  		    if (!$result) {  		        $this->error = $line; @@ -1976,17 +1987,17 @@ class rcube_imap_generic  	    if (!$folder) {  	        return false;  	    } -     +  	    // open message file  	    $in_fp = false;  	    if (file_exists(realpath($path))) {  		    $in_fp = fopen($path, 'r');  	    } -	    if (!$in_fp) {  +	    if (!$in_fp) {  		    $this->error = "Couldn't open $path for reading";  		    return false;  	    } -	 +  	    $len = filesize($path);  	    if (!$len) {  		    return false; @@ -2036,7 +2047,7 @@ class rcube_imap_generic  		    return $result;  	    } -	 +      	$this->error = "Couldn't send command \"$request\"";  	    return false;      } @@ -2074,7 +2085,7 @@ class rcube_imap_generic           */  	    $result      = false;  	    $quota_lines = array(); -	 +  	    // get line(s) containing quota info  	    if ($this->putLine('QUOT1 GETQUOTAROOT "INBOX"')) {  		    do { @@ -2084,24 +2095,24 @@ class rcube_imap_generic          		}  		    } while (!$this->startsWith($line, 'QUOT1', true, true));  	    } -	 +  	    // return false if not found, parse if found  	    $min_free = PHP_INT_MAX;  	    foreach ($quota_lines as $key => $quota_line) {  		    $quota_line   = preg_replace('/[()]/', '', $quota_line);  		    $parts        = explode(' ', $quota_line);  		    $storage_part = array_search('STORAGE', $parts); -		 +  		    if (!$storage_part)                  continue; -	 +  		    $used  = intval($parts[$storage_part+1]);  		    $total = intval($parts[$storage_part+2]); -		    $free  = $total - $used;  -	 +		    $free  = $total - $used; +  		    // return lowest available space from all quotas -		    if ($free < $min_free) {  -		        $min_free          = $free;  +		    if ($free < $min_free) { +		        $min_free          = $free;  			    $result['used']    = $used;  			    $result['total']   = $total;  			    $result['percent'] = min(100, round(($used/max(1,$total))*100)); @@ -2137,7 +2148,7 @@ class rcube_imap_generic  	    $ts = (int) $ts; -	    return $ts < 0 ? 0 : $ts;	 +	    return $ts < 0 ? 0 : $ts;      }      private function SplitHeaderLine($string) @@ -2162,7 +2173,7 @@ class rcube_imap_generic  	    $data      = array();  	    $in_quotes = false;  	    $elem      = 0; -	 +          for ($i;$i<$len;$i++) {  		    $c = (string)$str[$i];  		    if ($c == '(' && !$in_quotes) { @@ -2185,18 +2196,18 @@ class rcube_imap_generic  			    $data[$elem].=$c;  		    }  	    } -	     +          return $data;      }      private function escape($string)      { -	    return strtr($string, array('"'=>'\\"', '\\' => '\\\\'));  +	    return strtr($string, array('"'=>'\\"', '\\' => '\\\\'));      }      private function unEscape($string)      { -	    return strtr($string, array('\\"'=>'"', '\\\\' => '\\'));  +	    return strtr($string, array('\\"'=>'"', '\\\\' => '\\'));      }  } | 
