Index: /sandbox/2.2.0.2/services/class.ical.php =================================================================== --- /sandbox/2.2.0.2/services/class.ical.php (revision 4445) +++ /sandbox/2.2.0.2/services/class.ical.php (revision 4445) @@ -0,0 +1,363 @@ +ical = new vcalendar(); + + /* + * Seta propiedades obrigatorias para alguns softwares (Outlook) + */ + $this->ical->setProperty( 'method' , $method ); + $this->ical->setProperty( 'x-wr-calname', 'Calendar Expresso' ); + $this->ical->setProperty( 'X-WR-CALDESC', 'Calendar Expresso' ); + $this->ical->setProperty( 'X-WR-TIMEZONE', date('e') ); + } + + /** + * Adiciona um novo Evento + * + * @license http://www.gnu.org/copyleft/gpl.html GPL + * @author Prognus Software Livre (http://www.prognus.com.br) + * @author Cristiano Corrêa Schmidt + * @param miexed $dtStart 0000-00-00 00:00:00 | array('0000-00-00 00:00:00' => array('XXXX' => 'XXXX')) + * @param miexed $dtEnd 0000-00-00 00:00:00 | array('0000-00-00 00:00:00' => array('XXXX' => 'XXXX')) + * @param miexed $organizer array('xxx@xxx.com.br' => array('cn' => 'XXXXXXXX')) + * @param miexed $summary xxxxx | array('XXXX' => array('XXXX' => 'XXXX')) + * @param miexed $description xxxxx | array( 'XXXX'=> array('XXXX' => 'XXXX')) + * @param miexed $location xxxxx | array( 'XXXX'=> array('XXXX' => 'XXXX')) + * @param array $attendee array('xxx@xxx.com.br' => array('cn') => 'XXXX XXXX')) + * @param array $other array('xxxx' => array('xxx' => array('xxx' =>'xxx')) + * @param array $components + * @param string $uid + * @access public + */ + public function addEvent($dtStart,$dtEnd,$organizer,$summary,$description,$location,$attendee = false,$other = false,$components = false,$uid = false) + { + $vevent = &$this->ical->newComponent( 'vevent' ); + + $this->setP($vevent, 'dtstart', $dtStart); + $this->setP($vevent, 'dtend', $dtEnd); + $this->setP($vevent, 'organizer', $organizer); + $this->setP($vevent, 'summary', $summary); + $this->setP($vevent, 'description', $description); + $this->setP($vevent, 'location', $location); + + if($attendee) + $this->setP($vevent, 'attendee', $attendee); + + if($other) + { + foreach ($other as $property => $value) + $this->setP($vevent, 'attendee', $value); + } + + if($components) + { + foreach ($components as $component) + foreach ($component as $name => $value) + $this->setC($vevent, $name, $value); + } + + if($uid === false) + $uid = time().'@Expresso'; + + $vevent->setProperty( 'uid' , $uid ); + } + + /** + * Seta uma propiedade ao componente + * + * @license http://www.gnu.org/copyleft/gpl.html GPL + * @author Prognus Software Livre (http://www.prognus.com.br) + * @author Cristiano Corrêa Schmidt + * @param mixed $component + * @param string $property Tipo de propiedade + * @param mixed $value + * @access private + */ + private function setP($component,$property,$value) + { + if(is_array($value)) + { + foreach ($value as $value2 => $params) + $component->setProperty( $property , $value2 , $params ); + } + else + $component->setProperty( $property , $value ); + } + + /** + * Seta um componente ao componente + * + * @license http://www.gnu.org/copyleft/gpl.html GPL + * @author Prognus Software Livre (http://www.prognus.com.br) + * @author Cristiano Corrêa Schmidt + * @param mixed $component + * @param string $name Tipo do componente + * @param mixed $value + * @access private + */ + private function setC($component,$name,$value) + { + $comp = & $component->newComponent( $name ); + foreach ($value as $key => $value2) + $this->setP($comp,$key,$value2); + } + + /** + * Importa ical via string ou caminho do arquivo ics + * + * @license http://www.gnu.org/copyleft/gpl.html GPL + * @author Prognus Software Livre (http://www.prognus.com.br) + * @author Cristiano Corrêa Schmidt + * @param string $iCal + * @access public + */ + public function setIcal($iCal) + { + $this->ical = new vcalendar(); + return $this->ical->parse($iCal); + } + + /** + * Retorna todos os componentes do ical parseados + * + * @license http://www.gnu.org/copyleft/gpl.html GPL + * @author Prognus Software Livre (http://www.prognus.com.br) + * @author Cristiano Corrêa Schmidt + * @return array + * @access public + */ + public function getComponents() + { + + $return = array(); + + $componentes = $this->ical->getConfig('compsinfo'); + foreach ($componentes as $key => $value) + { + $return[] = $this->parseComponent($this->ical->getComponent( $key ), $value['type']); + } + return $return; + } + + /** + * Retorna componente especificado, tipo ou o numero do componente + * + * @license http://www.gnu.org/copyleft/gpl.html GPL + * @author Prognus Software Livre (http://www.prognus.com.br) + * @author Cristiano Corrêa Schmidt + * @param mixed $component + * @return array + * @access public + */ + public function getComponent($component) + { + if(is_int($component)) + { + $componentes = $this->ical->getConfig('compsinfo'); + return $this->parseComponent($this->ical->getComponent($component),$componentes[$component]['type']); + } + else + return $this->parseComponent($this->ical->getComponent($component),$component); + } + + /** + * Retorna metodo usado no ical + * + * @license http://www.gnu.org/copyleft/gpl.html GPL + * @author Prognus Software Livre (http://www.prognus.com.br) + * @author Cristiano Corrêa Schmidt + * @return string + * @access public + */ + public function getMethod() + { + return strtoupper($this->ical->getProperty( 'method' )); + } + + /** + * Retorna um array com as informações dos componentes + * + * @license http://www.gnu.org/copyleft/gpl.html GPL + * @author Prognus Software Livre (http://www.prognus.com.br) + * @author Cristiano Corrêa Schmidt + * @return array + * @access public + */ + public function getComponentInfo() + { + return $this->ical->getConfig('compsinfo'); + } + + + /** + * Parseia o componente em um array + * + * @license http://www.gnu.org/copyleft/gpl.html GPL + * @author Prognus Software Livre (http://www.prognus.com.br) + * @author Cristiano Corrêa Schmidt + * @param mixed $component + * @param string $type + * @return array + * @access private + */ + private function parseComponent($component,$type) + { + $return = array(); + + switch (strtoupper($type)) { + case 'VEVENT': + + $return['type'] = 'VEVENT'; + $return['summary'] = $component->getProperty( 'summary' , FALSE , TRUE ); + $return['description'] = $component->getProperty( 'description' ,FALSE,TRUE); + $return['organizer'] = $component->getProperty( 'organizer' , FALSE , TRUE ); + $return['organizer']['value'] = str_replace('MAILTO:', '', $return['organizer']['value']); + $return['location'] = $component->getProperty( 'location', FALSE , TRUE ); + $return['dtstart'] = $component->getProperty( 'dtstart', FALSE , TRUE ); + $return['dtend'] = $component->getProperty( 'dtend', FALSE , TRUE ); + $return['status'] = $component->getProperty( 'status' , FALSE , TRUE ); + $return['class'] = $component->getProperty( 'class' , FALSE , TRUE ); + $return['priority'] = $component->getProperty( 'priority' , FALSE , TRUE ); + $return['uid'] = $component->getProperty( 'uid' , FALSE , TRUE ); + $return['dtstamp'] = $component->getProperty( 'dtstamp' , FALSE , TRUE ); + $return['sequence'] = $component->getProperty( 'sequence' , FALSE , TRUE ); + $return['request-status'] = $component->getProperty( 'request-status' , propOrderNo/FALSE, TRUE ); + $return['rrule'] = $component->getProperty( 'rrule' , propOrderNo/FALSE, TRUE ); + $return['transp'] = $component->getProperty( 'transp' , FALSE , TRUE ); + $return['url'] = $component->getProperty( 'url' , FALSE , TRUE ); + $return['recurrence-id'] = $component->getProperty( 'recurrence-id' , FALSE , TRUE ); + $return['attach'] = $component->getProperty( 'attach' , FALSE , TRUE ); + $return['comment'] = $component->getProperty( 'comment' , FALSE , TRUE ); + $return['created'] = $component->getProperty( 'created' , FALSE , TRUE ); + $return['duration'] = $component->getProperty( 'duration' , FALSE , TRUE ); + $return['geo'] = $component->getProperty( 'geo' , FALSE , TRUE ); + $return['last-modified'] = $component->getProperty( 'last-modified', FALSE , TRUE ); + $return['rdate'] = $component->getProperty( 'rdate' , propOrderNo/FALSE , TRUE ); + $return['related-to'] = $component->getProperty( 'related-to' , propOrderNo/FALSE , TRUE ); + $return['resources'] = $component->getProperty( 'resources' , propOrderNo/FALSE, TRUE ); + + while($property = $component->getProperty( FALSE, propOrderNo/FALSE, TRUE )){$return['x-property'][] = array('name' => $property[0], 'value' => $property[1]['value'],'params' => $property[1]['params']);}; + + while($property = $component->getProperty('attendee',propOrderNo/FALSE , TRUE)) + { + $ateendee = $property; + $ateendee['value'] = str_replace('MAILTO:', '', $ateendee['value']); + $return['attendee'][] = $ateendee; + }; + + while($property = $component->getProperty('categories',propOrderNo/FALSE , TRUE)){$return['categories'][] = $property;}; + while($component->getProperty('contact',propOrderNo/FALSE , TRUE)){$return['contact'][] = $property;}; + while($component->getProperty('exdate',propOrderNo/FALSE , TRUE)){$return['exdate'][] = $property;}; + while($component->getProperty('exrule',propOrderNo/FALSE , TRUE)){$return['exrule'][] = $property;}; + + $return['sub'] = array(); + + $componentes = $component->getConfig('compsinfo'); + foreach ($componentes as $key => $value) + $return['sub'][] = $this->parseComponent($component->getComponent( $key ), $value['type']); + + break; + + case 'VALARM': + $return['type'] = 'VALARM'; + $return['action'] = $component->getProperty( 'action' , FALSE , TRUE ); + $return['attach'] = $component->getProperty( 'attach' , FALSE , TRUE ); + $return['description'] = $component->getProperty( 'description' ,FALSE,TRUE); + $return['duration'] = $component->getProperty( 'duration' , FALSE , TRUE ); + $return['repeat'] = $component->getProperty( 'repeat', FALSE , TRUE ); + $return['summary'] = $component->getProperty( 'summary' , FALSE , TRUE ); + $return['trigger'] = $component->getProperty( 'trigger' , FALSE , TRUE ); + while($property = $component->getProperty( FALSE, propOrderNo/FALSE, TRUE )){$return['x-property'][] = array('name' => $property[0], 'value' => $property[1]['value'],'params' => $property[1]['params']);}; + + break; + default: + break; + } + + + return $return; + } + + /** + * Retorna o ical em uma string + * + * @license http://www.gnu.org/copyleft/gpl.html GPL + * @author Prognus Software Livre (http://www.prognus.com.br) + * @author Cristiano Corrêa Schmidt + * @return string + * @access prublic + */ + public function getICal() + { + return $this->ical->createCalendar(); + } + + /** + * Retorna o ical para download direto + * + * @license http://www.gnu.org/copyleft/gpl.html GPL + * @author Prognus Software Livre (http://www.prognus.com.br) + * @author Cristiano Corrêa Schmidt + * @return string + * @access prublic + */ + public function downloadICal() + { + return $this->ical->returnCalendar(); + } + + /** + * Salva o ical em disco + * + * @license http://www.gnu.org/copyleft/gpl.html GPL + * @author Prognus Software Livre (http://www.prognus.com.br) + * @author Cristiano Corrêa Schmidt + * @param string $directory + * @param string $filename + * @return string + * @access prublic + */ + public function saveICal($directory,$filename) + { + $config = array( 'directory' => $directory, 'filename' => $filename); + $this->ical->setConfig( $config ); + $this->ical->saveCalendar(); + } + +} + +ServiceLocator::register( 'ical', new ICalService() ); + +?> Index: /sandbox/2.2.0.2/services/class.ldap.php =================================================================== --- /sandbox/2.2.0.2/services/class.ldap.php (revision 4445) +++ /sandbox/2.2.0.2/services/class.ldap.php (revision 4445) @@ -0,0 +1,284 @@ +connection = $conection; + + return( $connection ); + } + + function _or( $toWrap ) + { + if( !is_array( $toWrap ) ) + return( $toWrap ); + +// if( count( $toWrap ) <= 1 ) +// return implode( "", $toWrap ); + + return $this->wrap( $toWrap, '|' ); + } + + function _and( $toWrap ) + { + if( !is_array( $toWrap ) ) + return( $toWrap ); + +// if( count( $toWrap ) <= 1 ) +// return implode( "", $toWrap ); + + return $this->wrap( $toWrap, '&' ); + } + + function _not( $toWrap ) + { + return $this->wrap( $toWrap, '!' ); + } + + function wrap( $toWrap, $conditional = "" ) + { + if( !is_array( $toWrap ) ) + $toWrap = array( $toWrap ); + + $toWrap = array_unique( $toWrap ); + + return "(".$conditional.implode( "", $toWrap ).")"; + } + + function getSearchFilter( $search, $targetTypes = false, $customFilter = '', $exact = false ) + { + $search = utf8_encode( $search ); + + if( !$targetTypes ) + $targetTypes = $this->allTargetTypes; + + if( !is_array( $targetTypes ) ) + $targetTypes = array( $targetTypes ); + + $searchFilter = ''; + + foreach( $targetTypes as $targetType ) + { + switch( $targetType ) + { + case 'g': + { + //no caso de grupos, a busca so precisa ser feita em cima do CN + $searchFilter = $this->stemFilter( $search, 'cn' ); + } + break; + + default : + { + //parametros que a busca tem que ser sintaticas + $searchFilter = /*array( */$this->stemFilter( $search, array( + // UID e employeeNumber podem ser iguais ou muito similares, dependendo da organizacao + 'uid', /*'employeeNumber', */'cn', + // givenName e SN sao complementares (nome e sobrenome) + 'givenName', 'sn', 'displayName' ) //), + //parametros que a busca pode ser por aproximacao fonetica + /*$this->approxFilter( $search, array( + // O CN e displayName geralmente sao a mesma coisa + 'cn', 'displayName' ))*/ ); + + $searchFilter = $this->stemFilter( $search, array( 'cn', 'givenName', 'uid', + 'sn', 'displayName' ) ); + } + break; + } + } + + $filter = array(); + + if( $customFilter ) + $filter[] = $customFilter; + if( $search ) + $filter[] = $searchFilter; + + return $this->_and( array( + // Somente objetos relacionados com o Expresso + $this->accountFilter( $targetTypes ), + // Objetos ocultados e/ou desativados pelo Administrador nao podem ser exibidos nas consultas do Expresso + $this->securityFilter( $targetTypes ), + //foco da busca + ( $exact ? $this->_and( $filter ) : $this->_or( $filter ) ) + )); + + // Verificoes extras para validar o resultado + // (& + // // Somente objetos com e-mail no formato da RFC822 + // (mail=*@*) + // ) + } + + function securityFilter( $targetTypes ) + { + if( !$targetTypes ) + $targetTypes = $this->allTargetTypes; + + if( !is_array( $targetTypes ) ) + $targetTypes = array( $targetTypes ); + + $typeFilter = array(); + + foreach( $targetTypes as $targetType ) + { + switch( $targetType ) + { + case 'g': $typeFilter[] = "(objectClass=posixGroup)"; + break; + + default : $typeFilter[] = "(phpgwAccountStatus=A)"; + break; + } + } + + return $this->_and( array( '(!(phpgwAccountVisible=-1))', $this->_or( $typeFilter ) ) ); + } + + function accountFilter( $targetTypes ) + { + if( !$targetTypes ) + $targetTypes = $this->allTargetTypes; + + if( !is_array( $targetTypes ) ) + $targetTypes = array( $targetTypes ); + + $typeFilter = array(); + + foreach( $targetTypes as $targetType ) + $typeFilter[] = '(phpgwAccountType='.$targetType.')'; + + return $this->_and( array( '(objectClass=phpgwAccount)', $this->_or( $typeFilter ) ) ); + } + + function stemFilter( $search, $params ) + { + $search = str_replace( ' ', '*', $search ); + + if( !is_array( $params ) ) + $params = array( $params ); + + foreach( $params as $i => $param ) + $params[$i] = "($param=*$search*)"; + + return $this->_or( $params ); + } + + function phoneticFilter( $search, $params ) + { + if( eregi( "\d", $search ) ) + return( "" ); + + if( !is_array( $params ) ) + $params = array( $params ); + + foreach( $params as $i => $param ) + $params[$i] = "($param~=$search)"; + + return $this->_or( $params ); + } + + function approxFilter( $search, $params ) + { + return $this->_or( array( $this->stemFilter( $search, $params ), + $this->phoneticFilter( $search, $params ) ) ); + } + +// public function search() +// { +// +// } + + public function accountSearch($search, $justthese = "*", $context = false , $accountType = false, $sort = false) + { + if( !$this->connection ) + $this->connect(); + + $filter = $this->getSearchFilter($search,$accountType); + + if( !$context ) + $context = $GLOBALS['phpgw_info']['server']['ldap_context']; + + $ls = ldap_search( $this->connection, utf8_encode($context), $filter, $justthese, 0, $this->limit ); + + if($sort) + ldap_sort( $this->connection, $ls, $sort ); + + $entries = ldap_get_entries( $this->connection, $ls ); + + if( !$entries ) return( null ); + + $return = array(); + + for ($i=0; $i < $entries["count"]; $i++) + { + $entrieTmp = array(); + foreach ($entries[$i] as $index => $value) + { + if(!is_numeric($index) && $index != 'count') + { + if(is_array($value)) + { + if(count($value) == 2) + $entrieTmp[$index] = utf8_decode($value['0']); + else + { + foreach ($value as $index2 =>$value2) + { + if($index != 'count') + $entrieTmp[$index][$index2] = utf8_decode($value2); + } + } + } + else + $entrieTmp[$index] = utf8_decode($value); + } + } + + $return[] = $entrieTmp; + } + + return( $return ); + } + +} + +ServiceLocator::register( 'ldap', new LdapService() ); + Index: /sandbox/2.2.0.2/services/class.mail.php =================================================================== --- /sandbox/2.2.0.2/services/class.mail.php (revision 4445) +++ /sandbox/2.2.0.2/services/class.mail.php (revision 4445) @@ -0,0 +1,172 @@ + '', 'port' => '', 'username' => '', 'password' => '' ); + + public function __construct( $config = null) + { + if( !$config ) + { + require_once ( ROOT.'/header.inc.php' ); + + $boemailadmin = CreateObject('emailadmin.bo'); + $emailadmin = $boemailadmin->getProfileList(); + $emailadmin = $boemailadmin->getProfile($emailadmin[0]['profileID']); + + self::$configuration['host'] = $emailadmin['smtpServer']; + self::$configuration['port'] = $emailadmin['smtpPort']; + +// self::$configuration['username'] = $emailadmin['user']; +// self::$configuration['password'] = $emailadmin['pass']; +// self::$configuration['name'] = $emailadmin['name']; +// self::$configuration['type'] = 'SMTP'; + +// array_merge( $configuration, array( 'auth' => 'login' ) ); + + zend_include( 'Zend/Mail/Transport/Smtp.php' ); + zend_include( 'Zend/Mail/Part.php' ); + set_include_path(LIBRARY); + parent::setDefaultTransport( new Zend_Mail_Transport_Smtp( self::$configuration['host'], self::$configuration ) ); + restore_include_path(); + } + + else + $this->configure( $config ); + } + + public function send( $to, $from, $subject, $body, $bcc = null, $cc = null, $isHTML = true ) + { + set_include_path( LIBRARY ); + if( $body ) + { + if( $isHTML ) + parent::setBodyHtml( $body ); + + else + parent::setBodyText( $body ); + } + + if( $subject ) + parent::setSubject( $subject ); + + if( !$from ) + $from = $GLOBALS['phpgw']->preferences->values['email']; + + parent::setFrom( $from, self::getNameByMail( $from ) ); + +//pra nao ter que fazer os ifs acima... + $destTypes = array( 'to', 'bcc', 'cc' ); + + foreach( $destTypes as $destination ) + { + $dest = $$destination; + + if( $dest ) + { + if( !is_array( $dest ) ) + $dest = array( $dest ); + + foreach( $dest as $d ) + { + $addDestination = 'add'.ucfirst($destination); + + parent::$addDestination( $d, self::getNameByMail( $d ) ); + } + } + } + + parent::send(); + restore_include_path(); + } + + public function configure( $config ) + { + if( !$config ) return( false ); + + foreach( $config as $key => $value ) + { + if( $value && isset( self::$configuration[$key] ) ) + { + self::$configuration[$key] = $value; + } + } + } + + //hook + public function getNameByMail( $mail ) + { + return( null ); + } + + public function getAttachment( $attachment ) + { + return( null ); + } + + /** + * Adds attachment to the mail message + * + * @param string $file binary file + * @param string $filename file name + * @param string $type type example: image/gif + * @param Zend_Mime $disposition example: Zend_Mime::DISPOSITION_INLINE + * @param Zend_Mime $encoding example: Zend_Mime::ENCODING_BASE64 + * @return bool + */ + public function addAttachment($file, $filename, $type, $encoding = null, $disposition = 'DISPOSITION_ATTACHMENT') + { + $part = new Zend_Mime_Part( $file ); + + $part->type = $type; + $part->filename = $filename; + + switch ($disposition) + { + case 'DISPOSITION_INLINE': + $part->disposition = Zend_Mime::DISPOSITION_INLINE; + break; + case 'DISPOSITION_ATTACHMENT': + $part->disposition = Zend_Mime::DISPOSITION_ATTACHMENT; + break; + default: + break; + } + + switch ($encoding) + { + case 'ENCODING_7BIT': + $part->encoding = Zend_Mime::ENCODING_7BIT; + break; + case 'ENCODING_8BIT:': + $part->encoding = Zend_Mime::ENCODING_8BIT; + break; + case 'ENCODING_QUOTEDPRINTABLE:': + $part->encoding = Zend_Mime::ENCODING_QUOTEDPRINTABLE; + break; + default: + $part->encoding = Zend_Mime::ENCODING_BASE64; + break; + } + + parent::addAttachment( $part ); + + return; + } +} + +ServiceLocator::register( 'mail', new MailService() ); + Index: /sandbox/2.2.0.2/library/Zend/Ldap.php =================================================================== --- /sandbox/2.2.0.2/library/Zend/Ldap.php (revision 4445) +++ /sandbox/2.2.0.2/library/Zend/Ldap.php (revision 4445) @@ -0,0 +1,1594 @@ +setOptions($options); + } + + /** + * Destructor. + * + * @return void + */ + public function __destruct() + { + $this->disconnect(); + } + + /** + * @return resource The raw LDAP extension resource. + */ + public function getResource() + { + if (!is_resource($this->_resource) || $this->_boundUser === false) { + $this->bind(); + } + return $this->_resource; + } + + /** + * Return the LDAP error number of the last LDAP command + * + * @return int + */ + public function getLastErrorCode() + { + $ret = @ldap_get_option($this->_resource, LDAP_OPT_ERROR_NUMBER, $err); + if ($ret === true) { + if ($err <= -1 && $err >= -17) { + /** + * @see Zend_Ldap_Exception + */ + require_once 'Zend/Ldap/Exception.php'; + /* For some reason draft-ietf-ldapext-ldap-c-api-xx.txt error + * codes in OpenLDAP are negative values from -1 to -17. + */ + $err = Zend_Ldap_Exception::LDAP_SERVER_DOWN + (-$err - 1); + } + return $err; + } + return 0; + } + + /** + * Return the LDAP error message of the last LDAP command + * + * @param int $errorCode + * @param array $errorMessages + * @return string + */ + public function getLastError(&$errorCode = null, array &$errorMessages = null) + { + $errorCode = $this->getLastErrorCode(); + $errorMessages = array(); + + /* The various error retrieval functions can return + * different things so we just try to collect what we + * can and eliminate dupes. + */ + $estr1 = @ldap_error($this->_resource); + if ($errorCode !== 0 && $estr1 === 'Success') { + $estr1 = @ldap_err2str($errorCode); + } + if (!empty($estr1)) { + $errorMessages[] = $estr1; + } + + @ldap_get_option($this->_resource, LDAP_OPT_ERROR_STRING, $estr2); + if (!empty($estr2) && !in_array($estr2, $errorMessages)) { + $errorMessages[] = $estr2; + } + + $message = ''; + if ($errorCode > 0) { + $message = '0x' . dechex($errorCode) . ' '; + } else { + $message = ''; + } + if (count($errorMessages) > 0) { + $message .= '(' . implode('; ', $errorMessages) . ')'; + } else { + $message .= '(no error message from LDAP)'; + } + return $message; + } + + /** + * Get the currently bound user + * + * FALSE if no user is bound to the LDAP resource + * NULL if there has been an anonymous bind + * username of the currently bound user + * + * @return false|null|string + */ + public function getBoundUser() + { + return $this->_boundUser; + } + + /** + * Sets the options used in connecting, binding, etc. + * + * Valid option keys: + * host + * port + * useSsl + * username + * password + * bindRequiresDn + * baseDn + * accountCanonicalForm + * accountDomainName + * accountDomainNameShort + * accountFilterFormat + * allowEmptyPassword + * useStartTls + * optRefferals + * tryUsernameSplit + * + * @param array|Zend_Config $options Options used in connecting, binding, etc. + * @return Zend_Ldap Provides a fluent interface + * @throws Zend_Ldap_Exception + */ + public function setOptions($options) + { + if ($options instanceof Zend_Config) { + $options = $options->toArray(); + } + + $permittedOptions = array( + 'host' => null, + 'port' => 0, + 'useSsl' => false, + 'username' => null, + 'password' => null, + 'bindRequiresDn' => false, + 'baseDn' => null, + 'accountCanonicalForm' => null, + 'accountDomainName' => null, + 'accountDomainNameShort' => null, + 'accountFilterFormat' => null, + 'allowEmptyPassword' => false, + 'useStartTls' => false, + 'optReferrals' => false, + 'tryUsernameSplit' => true, + ); + + foreach ($permittedOptions as $key => $val) { + if (array_key_exists($key, $options)) { + $val = $options[$key]; + unset($options[$key]); + /* Enforce typing. This eliminates issues like Zend_Config_Ini + * returning '1' as a string (ZF-3163). + */ + switch ($key) { + case 'port': + case 'accountCanonicalForm': + $permittedOptions[$key] = (int)$val; + break; + case 'useSsl': + case 'bindRequiresDn': + case 'allowEmptyPassword': + case 'useStartTls': + case 'optReferrals': + case 'tryUsernameSplit': + $permittedOptions[$key] = ($val === true || + $val === '1' || strcasecmp($val, 'true') == 0); + break; + default: + $permittedOptions[$key] = trim($val); + break; + } + } + } + if (count($options) > 0) { + $key = key($options); + /** + * @see Zend_Ldap_Exception + */ + require_once 'Zend/Ldap/Exception.php'; + throw new Zend_Ldap_Exception(null, "Unknown Zend_Ldap option: $key"); + } + $this->_options = $permittedOptions; + return $this; + } + + /** + * @return array The current options. + */ + public function getOptions() + { + return $this->_options; + } + + /** + * @return string The hostname of the LDAP server being used to authenticate accounts + */ + protected function _getHost() + { + return $this->_options['host']; + } + + /** + * @return int The port of the LDAP server or 0 to indicate that no port value is set + */ + protected function _getPort() + { + return $this->_options['port']; + } + + /** + * @return boolean The default SSL / TLS encrypted transport control + */ + protected function _getUseSsl() + { + return $this->_options['useSsl']; + } + + /** + * @return string The default acctname for binding + */ + protected function _getUsername() + { + return $this->_options['username']; + } + + /** + * @return string The default password for binding + */ + protected function _getPassword() + { + return $this->_options['password']; + } + + /** + * @return boolean Bind requires DN + */ + protected function _getBindRequiresDn() + { + return $this->_options['bindRequiresDn']; + } + + /** + * Gets the base DN under which objects of interest are located + * + * @return string + */ + public function getBaseDn() + { + return $this->_options['baseDn']; + } + + /** + * @return integer Either ACCTNAME_FORM_BACKSLASH, ACCTNAME_FORM_PRINCIPAL or + * ACCTNAME_FORM_USERNAME indicating the form usernames should be canonicalized to. + */ + protected function _getAccountCanonicalForm() + { + /* Account names should always be qualified with a domain. In some scenarios + * using non-qualified account names can lead to security vulnerabilities. If + * no account canonical form is specified, we guess based in what domain + * names have been supplied. + */ + + $accountCanonicalForm = $this->_options['accountCanonicalForm']; + if (!$accountCanonicalForm) { + $accountDomainName = $this->_getAccountDomainName(); + $accountDomainNameShort = $this->_getAccountDomainNameShort(); + if ($accountDomainNameShort) { + $accountCanonicalForm = Zend_Ldap::ACCTNAME_FORM_BACKSLASH; + } else if ($accountDomainName) { + $accountCanonicalForm = Zend_Ldap::ACCTNAME_FORM_PRINCIPAL; + } else { + $accountCanonicalForm = Zend_Ldap::ACCTNAME_FORM_USERNAME; + } + } + + return $accountCanonicalForm; + } + + /** + * @return string The account domain name + */ + protected function _getAccountDomainName() + { + return $this->_options['accountDomainName']; + } + + /** + * @return string The short account domain name + */ + protected function _getAccountDomainNameShort() + { + return $this->_options['accountDomainNameShort']; + } + + /** + * @return string A format string for building an LDAP search filter to match + * an account + */ + protected function _getAccountFilterFormat() + { + return $this->_options['accountFilterFormat']; + } + + /** + * @return boolean Allow empty passwords + */ + protected function _getAllowEmptyPassword() + { + return $this->_options['allowEmptyPassword']; + } + + /** + * @return boolean The default SSL / TLS encrypted transport control + */ + protected function _getUseStartTls() + { + return $this->_options['useStartTls']; + } + + /** + * @return boolean Opt. Referrals + */ + protected function _getOptReferrals() + { + return $this->_options['optReferrals']; + } + + /** + * @return boolean Try splitting the username into username and domain + */ + protected function _getTryUsernameSplit() + { + return $this->_options['tryUsernameSplit']; + } + + /** + * @return string The LDAP search filter for matching directory accounts + */ + protected function _getAccountFilter($acctname) + { + /** + * @see Zend_Ldap_Filter_Abstract + */ + require_once 'Zend/Ldap/Filter/Abstract.php'; + $this->_splitName($acctname, $dname, $aname); + $accountFilterFormat = $this->_getAccountFilterFormat(); + $aname = Zend_Ldap_Filter_Abstract::escapeValue($aname); + if ($accountFilterFormat) { + return sprintf($accountFilterFormat, $aname); + } + if (!$this->_getBindRequiresDn()) { + // is there a better way to detect this? + return sprintf("(&(objectClass=user)(sAMAccountName=%s))", $aname); + } + return sprintf("(&(objectClass=posixAccount)(uid=%s))", $aname); + } + + /** + * @param string $name The name to split + * @param string $dname The resulting domain name (this is an out parameter) + * @param string $aname The resulting account name (this is an out parameter) + * @return void + */ + protected function _splitName($name, &$dname, &$aname) + { + $dname = null; + $aname = $name; + + if (!$this->_getTryUsernameSplit()) { + return; + } + + $pos = strpos($name, '@'); + if ($pos) { + $dname = substr($name, $pos + 1); + $aname = substr($name, 0, $pos); + } else { + $pos = strpos($name, '\\'); + if ($pos) { + $dname = substr($name, 0, $pos); + $aname = substr($name, $pos + 1); + } + } + } + + /** + * @param string $acctname The name of the account + * @return string The DN of the specified account + * @throws Zend_Ldap_Exception + */ + protected function _getAccountDn($acctname) + { + /** + * @see Zend_Ldap_Dn + */ + require_once 'Zend/Ldap/Dn.php'; + if (Zend_Ldap_Dn::checkDn($acctname)) return $acctname; + $acctname = $this->getCanonicalAccountName($acctname, Zend_Ldap::ACCTNAME_FORM_USERNAME); + $acct = $this->_getAccount($acctname, array('dn')); + return $acct['dn']; + } + + /** + * @param string $dname The domain name to check + * @return boolean + */ + protected function _isPossibleAuthority($dname) + { + if ($dname === null) { + return true; + } + $accountDomainName = $this->_getAccountDomainName(); + $accountDomainNameShort = $this->_getAccountDomainNameShort(); + if ($accountDomainName === null && $accountDomainNameShort === null) { + return true; + } + if (strcasecmp($dname, $accountDomainName) == 0) { + return true; + } + if (strcasecmp($dname, $accountDomainNameShort) == 0) { + return true; + } + return false; + } + + /** + * @param string $acctname The name to canonicalize + * @param int $type The desired form of canonicalization + * @return string The canonicalized name in the desired form + * @throws Zend_Ldap_Exception + */ + public function getCanonicalAccountName($acctname, $form = 0) + { + $this->_splitName($acctname, $dname, $uname); + + if (!$this->_isPossibleAuthority($dname)) { + /** + * @see Zend_Ldap_Exception + */ + require_once 'Zend/Ldap/Exception.php'; + throw new Zend_Ldap_Exception(null, + "Binding domain is not an authority for user: $acctname", + Zend_Ldap_Exception::LDAP_X_DOMAIN_MISMATCH); + } + + if (!$uname) { + /** + * @see Zend_Ldap_Exception + */ + require_once 'Zend/Ldap/Exception.php'; + throw new Zend_Ldap_Exception(null, "Invalid account name syntax: $acctname"); + } + + if (function_exists('mb_strtolower')) { + $uname = mb_strtolower($uname, 'UTF-8'); + } else { + $uname = strtolower($uname); + } + + if ($form === 0) { + $form = $this->_getAccountCanonicalForm(); + } + + switch ($form) { + case Zend_Ldap::ACCTNAME_FORM_DN: + return $this->_getAccountDn($acctname); + case Zend_Ldap::ACCTNAME_FORM_USERNAME: + return $uname; + case Zend_Ldap::ACCTNAME_FORM_BACKSLASH: + $accountDomainNameShort = $this->_getAccountDomainNameShort(); + if (!$accountDomainNameShort) { + /** + * @see Zend_Ldap_Exception + */ + require_once 'Zend/Ldap/Exception.php'; + throw new Zend_Ldap_Exception(null, 'Option required: accountDomainNameShort'); + } + return "$accountDomainNameShort\\$uname"; + case Zend_Ldap::ACCTNAME_FORM_PRINCIPAL: + $accountDomainName = $this->_getAccountDomainName(); + if (!$accountDomainName) { + /** + * @see Zend_Ldap_Exception + */ + require_once 'Zend/Ldap/Exception.php'; + throw new Zend_Ldap_Exception(null, 'Option required: accountDomainName'); + } + return "$uname@$accountDomainName"; + default: + /** + * @see Zend_Ldap_Exception + */ + require_once 'Zend/Ldap/Exception.php'; + throw new Zend_Ldap_Exception(null, "Unknown canonical name form: $form"); + } + } + + /** + * @param array $attrs An array of names of desired attributes + * @return array An array of the attributes representing the account + * @throws Zend_Ldap_Exception + */ + protected function _getAccount($acctname, array $attrs = null) + { + $baseDn = $this->getBaseDn(); + if (!$baseDn) { + /** + * @see Zend_Ldap_Exception + */ + require_once 'Zend/Ldap/Exception.php'; + throw new Zend_Ldap_Exception(null, 'Base DN not set'); + } + + $accountFilter = $this->_getAccountFilter($acctname); + if (!$accountFilter) { + /** + * @see Zend_Ldap_Exception + */ + require_once 'Zend/Ldap/Exception.php'; + throw new Zend_Ldap_Exception(null, 'Invalid account filter'); + } + + if (!is_resource($this->getResource())) { + $this->bind(); + } + + $accounts = $this->search($accountFilter, $baseDn, self::SEARCH_SCOPE_SUB, $attrs); + $count = $accounts->count(); + if ($count === 1) { + $acct = $accounts->getFirst(); + $accounts->close(); + return $acct; + } else if ($count === 0) { + /** + * @see Zend_Ldap_Exception + */ + require_once 'Zend/Ldap/Exception.php'; + $code = Zend_Ldap_Exception::LDAP_NO_SUCH_OBJECT; + $str = "No object found for: $accountFilter"; + } else { + /** + * @see Zend_Ldap_Exception + */ + require_once 'Zend/Ldap/Exception.php'; + $code = Zend_Ldap_Exception::LDAP_OPERATIONS_ERROR; + $str = "Unexpected result count ($count) for: $accountFilter"; + } + $accounts->close(); + /** + * @see Zend_Ldap_Exception + */ + require_once 'Zend/Ldap/Exception.php'; + throw new Zend_Ldap_Exception($this, $str, $code); + } + + /** + * @return Zend_Ldap Provides a fluent interface + */ + public function disconnect() + { + if (is_resource($this->_resource)) { + @ldap_unbind($this->_resource); + } + $this->_resource = null; + $this->_boundUser = false; + return $this; + } + + /** + * To connect using SSL it seems the client tries to verify the server + * certificate by default. One way to disable this behavior is to set + * 'TLS_REQCERT never' in OpenLDAP's ldap.conf and restarting Apache. Or, + * if you really care about the server's cert you can put a cert on the + * web server. + * + * @param string $host The hostname of the LDAP server to connect to + * @param int $port The port number of the LDAP server to connect to + * @param boolean $useSsl Use SSL + * @param boolean $useStartTls Use STARTTLS + * @return Zend_Ldap Provides a fluent interface + * @throws Zend_Ldap_Exception + */ + public function connect($host = null, $port = null, $useSsl = null, $useStartTls = null) + { + if ($host === null) { + $host = $this->_getHost(); + } + if ($port === null) { + $port = $this->_getPort(); + } else { + $port = (int)$port; + } + if ($useSsl === null) { + $useSsl = $this->_getUseSsl(); + } else { + $useSsl = (bool)$useSsl; + } + if ($useStartTls === null) { + $useStartTls = $this->_getUseStartTls(); + } else { + $useStartTls = (bool)$useStartTls; + } + + if (!$host) { + /** + * @see Zend_Ldap_Exception + */ + require_once 'Zend/Ldap/Exception.php'; + throw new Zend_Ldap_Exception(null, 'A host parameter is required'); + } + + $useUri = false; + /* Because ldap_connect doesn't really try to connect, any connect error + * will actually occur during the ldap_bind call. Therefore, we save the + * connect string here for reporting it in error handling in bind(). + */ + $hosts = array(); + if (preg_match_all('~ldap(?:i|s)?://~', $host, $hosts, PREG_SET_ORDER) > 0) { + $this->_connectString = $host; + $useUri = true; + $useSsl = false; + } else { + if ($useSsl) { + $this->_connectString = 'ldaps://' . $host; + $useUri = true; + } else { + $this->_connectString = 'ldap://' . $host; + } + if ($port) { + $this->_connectString .= ':' . $port; + } + } + + $this->disconnect(); + + /* Only OpenLDAP 2.2 + supports URLs so if SSL is not requested, just + * use the old form. + */ + $resource = ($useUri) ? @ldap_connect($this->_connectString) : @ldap_connect($host, $port); + + if (is_resource($resource) === true) { + $this->_resource = $resource; + $this->_boundUser = false; + + $optReferrals = ($this->_getOptReferrals()) ? 1 : 0; + if (@ldap_set_option($resource, LDAP_OPT_PROTOCOL_VERSION, 3) && + @ldap_set_option($resource, LDAP_OPT_REFERRALS, $optReferrals)) { + if ($useSsl || !$useStartTls || @ldap_start_tls($resource)) { + return $this; + } + } + + /** + * @see Zend_Ldap_Exception + */ + require_once 'Zend/Ldap/Exception.php'; + $zle = new Zend_Ldap_Exception($this, "$host:$port"); + $this->disconnect(); + throw $zle; + } + /** + * @see Zend_Ldap_Exception + */ + require_once 'Zend/Ldap/Exception.php'; + throw new Zend_Ldap_Exception(null, "Failed to connect to LDAP server: $host:$port"); + } + + /** + * @param string $username The username for authenticating the bind + * @param string $password The password for authenticating the bind + * @return Zend_Ldap Provides a fluent interface + * @throws Zend_Ldap_Exception + */ + public function bind($username = null, $password = null) + { + $moreCreds = true; + + if ($username === null) { + $username = $this->_getUsername(); + $password = $this->_getPassword(); + $moreCreds = false; + } + + if (empty($username)) { + /* Perform anonymous bind + */ + $username = null; + $password = null; + } else { + /* Check to make sure the username is in DN form. + */ + /** + * @see Zend_Ldap_Dn + */ + require_once 'Zend/Ldap/Dn.php'; + if (!Zend_Ldap_Dn::checkDn($username)) { + if ($this->_getBindRequiresDn()) { + /* moreCreds stops an infinite loop if _getUsername does not + * return a DN and the bind requires it + */ + if ($moreCreds) { + try { + $username = $this->_getAccountDn($username); + } catch (Zend_Ldap_Exception $zle) { + switch ($zle->getCode()) { + case Zend_Ldap_Exception::LDAP_NO_SUCH_OBJECT: + case Zend_Ldap_Exception::LDAP_X_DOMAIN_MISMATCH: + case Zend_Ldap_Exception::LDAP_X_EXTENSION_NOT_LOADED: + throw $zle; + } + throw new Zend_Ldap_Exception(null, + 'Failed to retrieve DN for account: ' . $username . + ' [' . $zle->getMessage() . ']', + Zend_Ldap_Exception::LDAP_OPERATIONS_ERROR); + } + } else { + /** + * @see Zend_Ldap_Exception + */ + require_once 'Zend/Ldap/Exception.php'; + throw new Zend_Ldap_Exception(null, 'Binding requires username in DN form'); + } + } else { + $username = $this->getCanonicalAccountName($username, + $this->_getAccountCanonicalForm()); + } + } + } + + if (!is_resource($this->_resource)) { + $this->connect(); + } + + if ($username !== null && $password === '' && $this->_getAllowEmptyPassword() !== true) { + /** + * @see Zend_Ldap_Exception + */ + require_once 'Zend/Ldap/Exception.php'; + $zle = new Zend_Ldap_Exception(null, + 'Empty password not allowed - see allowEmptyPassword option.'); + } else { + if (@ldap_bind($this->_resource, $username, $password)) { + $this->_boundUser = $username; + return $this; + } + + $message = ($username === null) ? $this->_connectString : $username; + /** + * @see Zend_Ldap_Exception + */ + require_once 'Zend/Ldap/Exception.php'; + switch ($this->getLastErrorCode()) { + case Zend_Ldap_Exception::LDAP_SERVER_DOWN: + /* If the error is related to establishing a connection rather than binding, + * the connect string is more informative than the username. + */ + $message = $this->_connectString; + } + + $zle = new Zend_Ldap_Exception($this, $message); + } + $this->disconnect(); + throw $zle; + } + + /** + * A global LDAP search routine for finding information. + * + * Options can be either passed as single parameters according to the + * method signature or as an array with one or more of the following keys + * - filter + * - baseDn + * - scope + * - attributes + * - sort + * - collectionClass + * - sizelimit + * - timelimit + * + * @param string|Zend_Ldap_Filter_Abstract|array $filter + * @param string|Zend_Ldap_Dn|null $basedn + * @param integer $scope + * @param array $attributes + * @param string|null $sort + * @param string|null $collectionClass + * @param integer $sizelimit + * @param integer $timelimit + * @return Zend_Ldap_Collection + * @throws Zend_Ldap_Exception + */ + public function search($filter, $basedn = null, $scope = self::SEARCH_SCOPE_SUB, array $attributes = array(), + $sort = null, $collectionClass = null, $sizelimit = 0, $timelimit = 0) + { + if (is_array($filter)) { + $options = array_change_key_case($filter, CASE_LOWER); + foreach ($options as $key => $value) { + switch ($key) { + case 'filter': + case 'basedn': + case 'scope': + case 'sort': + $$key = $value; + break; + case 'attributes': + if (is_array($value)) { + $attributes = $value; + } + break; + case 'collectionclass': + $collectionClass = $value; + break; + case 'sizelimit': + case 'timelimit': + $$key = (int)$value; + } + } + } + + if ($basedn === null) { + $basedn = $this->getBaseDn(); + } + else if ($basedn instanceof Zend_Ldap_Dn) { + $basedn = $basedn->toString(); + } + + if ($filter instanceof Zend_Ldap_Filter_Abstract) { + $filter = $filter->toString(); + } + + switch ($scope) { + case self::SEARCH_SCOPE_ONE: + $search = @ldap_list($this->getResource(), $basedn, $filter, $attributes, 0, $sizelimit, $timelimit); + break; + case self::SEARCH_SCOPE_BASE: + $search = @ldap_read($this->getResource(), $basedn, $filter, $attributes, 0, $sizelimit, $timelimit); + break; + case self::SEARCH_SCOPE_SUB: + default: + $search = @ldap_search($this->getResource(), $basedn, $filter, $attributes, 0, $sizelimit, $timelimit); + break; + } + + if($search === false) { + /** + * @see Zend_Ldap_Exception + */ + require_once 'Zend/Ldap/Exception.php'; + throw new Zend_Ldap_Exception($this, 'searching: ' . $filter); + } + if ($sort !== null && is_string($sort)) { + $isSorted = @ldap_sort($this->getResource(), $search, $sort); + if($isSorted === false) { + /** + * @see Zend_Ldap_Exception + */ + require_once 'Zend/Ldap/Exception.php'; + throw new Zend_Ldap_Exception($this, 'sorting: ' . $sort); + } + } + + /** + * Zend_Ldap_Collection_Iterator_Default + */ + require_once 'Zend/Ldap/Collection/Iterator/Default.php'; + $iterator = new Zend_Ldap_Collection_Iterator_Default($this, $search); + return $this->_createCollection($iterator, $collectionClass); + } + + /** + * Extension point for collection creation + * + * @param Zend_Ldap_Collection_Iterator_Default $iterator + * @param string|null $collectionClass + * @return Zend_Ldap_Collection + * @throws Zend_Ldap_Exception + */ + protected function _createCollection(Zend_Ldap_Collection_Iterator_Default $iterator, $collectionClass) + { + if ($collectionClass === null) { + /** + * Zend_Ldap_Collection + */ + require_once 'Zend/Ldap/Collection.php'; + return new Zend_Ldap_Collection($iterator); + } else { + $collectionClass = (string)$collectionClass; + if (!class_exists($collectionClass)) { + /** + * @see Zend_Ldap_Exception + */ + require_once 'Zend/Ldap/Exception.php'; + throw new Zend_Ldap_Exception(null, + "Class '$collectionClass' can not be found"); + } + if (!is_subclass_of($collectionClass, 'Zend_Ldap_Collection')) { + /** + * @see Zend_Ldap_Exception + */ + require_once 'Zend/Ldap/Exception.php'; + throw new Zend_Ldap_Exception(null, + "Class '$collectionClass' must subclass 'Zend_Ldap_Collection'"); + } + return new $collectionClass($iterator); + } + } + + /** + * Count items found by given filter. + * + * @param string|Zend_Ldap_Filter_Abstract $filter + * @param string|Zend_Ldap_Dn|null $basedn + * @param integer $scope + * @return integer + * @throws Zend_Ldap_Exception + */ + public function count($filter, $basedn = null, $scope = self::SEARCH_SCOPE_SUB) + { + try { + $result = $this->search($filter, $basedn, $scope, array('dn'), null); + } catch (Zend_Ldap_Exception $e) { + if ($e->getCode() === Zend_Ldap_Exception::LDAP_NO_SUCH_OBJECT) return 0; + else throw $e; + } + return $result->count(); + } + + /** + * Count children for a given DN. + * + * @param string|Zend_Ldap_Dn $dn + * @return integer + * @throws Zend_Ldap_Exception + */ + public function countChildren($dn) + { + return $this->count('(objectClass=*)', $dn, self::SEARCH_SCOPE_ONE); + } + + /** + * Check if a given DN exists. + * + * @param string|Zend_Ldap_Dn $dn + * @return boolean + * @throws Zend_Ldap_Exception + */ + public function exists($dn) + { + return ($this->count('(objectClass=*)', $dn, self::SEARCH_SCOPE_BASE) == 1); + } + + /** + * Search LDAP registry for entries matching filter and optional attributes + * + * Options can be either passed as single parameters according to the + * method signature or as an array with one or more of the following keys + * - filter + * - baseDn + * - scope + * - attributes + * - sort + * - reverseSort + * - sizelimit + * - timelimit + * + * @param string|Zend_Ldap_Filter_Abstract|array $filter + * @param string|Zend_Ldap_Dn|null $basedn + * @param integer $scope + * @param array $attributes + * @param string|null $sort + * @param boolean $reverseSort + * @param integer $sizelimit + * @param integer $timelimit + * @return array + * @throws Zend_Ldap_Exception + */ + public function searchEntries($filter, $basedn = null, $scope = self::SEARCH_SCOPE_SUB, + array $attributes = array(), $sort = null, $reverseSort = false, $sizelimit = 0, $timelimit = 0) + { + if (is_array($filter)) { + $filter = array_change_key_case($filter, CASE_LOWER); + if (isset($filter['collectionclass'])) { + unset($filter['collectionclass']); + } + if (isset($filter['reversesort'])) { + $reverseSort = $filter['reversesort']; + unset($filter['reversesort']); + } + } + $result = $this->search($filter, $basedn, $scope, $attributes, $sort, null, $sizelimit, $timelimit); + $items = $result->toArray(); + if ((bool)$reverseSort === true) { + $items = array_reverse($items, false); + } + return $items; + } + + /** + * Get LDAP entry by DN + * + * @param string|Zend_Ldap_Dn $dn + * @param array $attributes + * @param boolean $throwOnNotFound + * @return array + * @throws Zend_Ldap_Exception + */ + public function getEntry($dn, array $attributes = array(), $throwOnNotFound = false) + { + try { + $result = $this->search("(objectClass=*)", $dn, self::SEARCH_SCOPE_BASE, + $attributes, null); + return $result->getFirst(); + } catch (Zend_Ldap_Exception $e){ + if ($throwOnNotFound !== false) throw $e; + } + return null; + } + + /** + * Prepares an ldap data entry array for insert/update operation + * + * @param array $entry + * @return void + * @throws InvalidArgumentException + */ + public static function prepareLdapEntryArray(array &$entry) + { + if (array_key_exists('dn', $entry)) unset($entry['dn']); + foreach ($entry as $key => $value) { + if (is_array($value)) { + foreach ($value as $i => $v) { + if ($v === null) unset($value[$i]); + else if (!is_scalar($v)) { + throw new InvalidArgumentException('Only scalar values allowed in LDAP data'); + } else { + $v = (string)$v; + if (strlen($v) == 0) { + unset($value[$i]); + } else { + $value[$i] = $v; + } + } + } + $entry[$key] = array_values($value); + } else { + if ($value === null) $entry[$key] = array(); + else if (!is_scalar($value)) { + throw new InvalidArgumentException('Only scalar values allowed in LDAP data'); + } else { + $value = (string)$value; + if (strlen($value) == 0) { + $entry[$key] = array(); + } else { + $entry[$key] = array($value); + } + } + } + } + $entry = array_change_key_case($entry, CASE_LOWER); + } + + /** + * Add new information to the LDAP repository + * + * @param string|Zend_Ldap_Dn $dn + * @param array $entry + * @return Zend_Ldap Provides a fluid interface + * @throws Zend_Ldap_Exception + */ + public function add($dn, array $entry) + { + if (!($dn instanceof Zend_Ldap_Dn)) { + $dn = Zend_Ldap_Dn::factory($dn, null); + } + self::prepareLdapEntryArray($entry); + foreach ($entry as $key => $value) { + if (is_array($value) && count($value) === 0) { + unset($entry[$key]); + } + } + + $rdnParts = $dn->getRdn(Zend_Ldap_Dn::ATTR_CASEFOLD_LOWER); + foreach ($rdnParts as $key => $value) { + $value = Zend_Ldap_Dn::unescapeValue($value); + if (!array_key_exists($key, $entry)) { + $entry[$key] = array($value); + } else if (!in_array($value, $entry[$key])) { + $entry[$key] = array_merge(array($value), $entry[$key]); + } + } + $adAttributes = array('distinguishedname', 'instancetype', 'name', 'objectcategory', + 'objectguid', 'usnchanged', 'usncreated', 'whenchanged', 'whencreated'); + foreach ($adAttributes as $attr) { + if (array_key_exists($attr, $entry)) { + unset($entry[$attr]); + } + } + + $isAdded = @ldap_add($this->getResource(), $dn->toString(), $entry); + if($isAdded === false) { + /** + * @see Zend_Ldap_Exception + */ + require_once 'Zend/Ldap/Exception.php'; + throw new Zend_Ldap_Exception($this, 'adding: ' . $dn->toString()); + } + return $this; + } + + /** + * Update LDAP registry + * + * @param string|Zend_Ldap_Dn $dn + * @param array $entry + * @return Zend_Ldap Provides a fluid interface + * @throws Zend_Ldap_Exception + */ + public function update($dn, array $entry) + { + if (!($dn instanceof Zend_Ldap_Dn)) { + $dn = Zend_Ldap_Dn::factory($dn, null); + } + self::prepareLdapEntryArray($entry); + + $rdnParts = $dn->getRdn(Zend_Ldap_Dn::ATTR_CASEFOLD_LOWER); + foreach ($rdnParts as $key => $value) { + $value = Zend_Ldap_Dn::unescapeValue($value); + if (array_key_exists($key, $entry) && !in_array($value, $entry[$key])) { + $entry[$key] = array_merge(array($value), $entry[$key]); + } + } + + $adAttributes = array('distinguishedname', 'instancetype', 'name', 'objectcategory', + 'objectguid', 'usnchanged', 'usncreated', 'whenchanged', 'whencreated'); + foreach ($adAttributes as $attr) { + if (array_key_exists($attr, $entry)) { + unset($entry[$attr]); + } + } + + if (count($entry) > 0) { + $isModified = @ldap_modify($this->getResource(), $dn->toString(), $entry); + if($isModified === false) { + /** + * @see Zend_Ldap_Exception + */ + require_once 'Zend/Ldap/Exception.php'; + throw new Zend_Ldap_Exception($this, 'updating: ' . $dn->toString()); + } + } + return $this; + } + + /** + * Save entry to LDAP registry. + * + * Internally decides if entry will be updated to added by calling + * {@link exists()}. + * + * @param string|Zend_Ldap_Dn $dn + * @param array $entry + * @return Zend_Ldap Provides a fluid interface + * @throws Zend_Ldap_Exception + */ + public function save($dn, array $entry) + { + if ($dn instanceof Zend_Ldap_Dn) { + $dn = $dn->toString(); + } + if ($this->exists($dn)) $this->update($dn, $entry); + else $this->add($dn, $entry); + return $this; + } + + /** + * Delete an LDAP entry + * + * @param string|Zend_Ldap_Dn $dn + * @param boolean $recursively + * @return Zend_Ldap Provides a fluid interface + * @throws Zend_Ldap_Exception + */ + public function delete($dn, $recursively = false) + { + if ($dn instanceof Zend_Ldap_Dn) { + $dn = $dn->toString(); + } + if ($recursively === true) { + if ($this->countChildren($dn)>0) { + $children = $this->_getChildrenDns($dn); + foreach ($children as $c) { + $this->delete($c, true); + } + } + } + $isDeleted = @ldap_delete($this->getResource(), $dn); + if($isDeleted === false) { + /** + * @see Zend_Ldap_Exception + */ + require_once 'Zend/Ldap/Exception.php'; + throw new Zend_Ldap_Exception($this, 'deleting: ' . $dn); + } + return $this; + } + + /** + * Retrieve the immediate children DNs of the given $parentDn + * + * This method is used in recursive methods like {@see delete()} + * or {@see copy()} + * + * @param string|Zend_Ldap_Dn $parentDn + * @return array of DNs + */ + protected function _getChildrenDns($parentDn) + { + if ($parentDn instanceof Zend_Ldap_Dn) { + $parentDn = $parentDn->toString(); + } + $children = array(); + $search = @ldap_list($this->getResource(), $parentDn, '(objectClass=*)', array('dn')); + for ($entry = @ldap_first_entry($this->getResource(), $search); + $entry !== false; + $entry = @ldap_next_entry($this->getResource(), $entry)) { + $childDn = @ldap_get_dn($this->getResource(), $entry); + if ($childDn === false) { + /** + * @see Zend_Ldap_Exception + */ + require_once 'Zend/Ldap/Exception.php'; + throw new Zend_Ldap_Exception($this, 'getting dn'); + } + $children[] = $childDn; + } + @ldap_free_result($search); + return $children; + } + + /** + * Moves a LDAP entry from one DN to another subtree. + * + * @param string|Zend_Ldap_Dn $from + * @param string|Zend_Ldap_Dn $to + * @param boolean $recursively + * @param boolean $alwaysEmulate + * @return Zend_Ldap Provides a fluid interface + * @throws Zend_Ldap_Exception + */ + public function moveToSubtree($from, $to, $recursively = false, $alwaysEmulate = false) + { + if ($from instanceof Zend_Ldap_Dn) { + $orgDnParts = $from->toArray(); + } else { + $orgDnParts = Zend_Ldap_Dn::explodeDn($from); + } + + if ($to instanceof Zend_Ldap_Dn) { + $newParentDnParts = $to->toArray(); + } else { + $newParentDnParts = Zend_Ldap_Dn::explodeDn($to); + } + + $newDnParts = array_merge(array(array_shift($orgDnParts)), $newParentDnParts); + $newDn = Zend_Ldap_Dn::fromArray($newDnParts); + return $this->rename($from, $newDn, $recursively, $alwaysEmulate); + } + + /** + * Moves a LDAP entry from one DN to another DN. + * + * This is an alias for {@link rename()} + * + * @param string|Zend_Ldap_Dn $from + * @param string|Zend_Ldap_Dn $to + * @param boolean $recursively + * @param boolean $alwaysEmulate + * @return Zend_Ldap Provides a fluid interface + * @throws Zend_Ldap_Exception + */ + public function move($from, $to, $recursively = false, $alwaysEmulate = false) + { + return $this->rename($from, $to, $recursively, $alwaysEmulate); + } + + /** + * Renames a LDAP entry from one DN to another DN. + * + * This method implicitely moves the entry to another location within the tree. + * + * @param string|Zend_Ldap_Dn $from + * @param string|Zend_Ldap_Dn $to + * @param boolean $recursively + * @param boolean $alwaysEmulate + * @return Zend_Ldap Provides a fluid interface + * @throws Zend_Ldap_Exception + */ + public function rename($from, $to, $recursively = false, $alwaysEmulate = false) + { + $emulate = (bool)$alwaysEmulate; + if (!function_exists('ldap_rename')) $emulate = true; + else if ($recursively) $emulate = true; + + if ($emulate === false) { + if ($from instanceof Zend_Ldap_Dn) { + $from = $from->toString(); + } + + if ($to instanceof Zend_Ldap_Dn) { + $newDnParts = $to->toArray(); + } else { + $newDnParts = Zend_Ldap_Dn::explodeDn($to); + } + + $newRdn = Zend_Ldap_Dn::implodeRdn(array_shift($newDnParts)); + $newParent = Zend_Ldap_Dn::implodeDn($newDnParts); + $isOK = @ldap_rename($this->getResource(), $from, $newRdn, $newParent, true); + if($isOK === false) { + /** + * @see Zend_Ldap_Exception + */ + require_once 'Zend/Ldap/Exception.php'; + throw new Zend_Ldap_Exception($this, 'renaming ' . $from . ' to ' . $to); + } + else if (!$this->exists($to)) $emulate = true; + } + if ($emulate) { + $this->copy($from, $to, $recursively); + $this->delete($from, $recursively); + } + return $this; + } + + /** + * Copies a LDAP entry from one DN to another subtree. + * + * @param string|Zend_Ldap_Dn $from + * @param string|Zend_Ldap_Dn $to + * @param boolean $recursively + * @return Zend_Ldap Provides a fluid interface + * @throws Zend_Ldap_Exception + */ + public function copyToSubtree($from, $to, $recursively = false) + { + if ($from instanceof Zend_Ldap_Dn) { + $orgDnParts = $from->toArray(); + } else { + $orgDnParts = Zend_Ldap_Dn::explodeDn($from); + } + + if ($to instanceof Zend_Ldap_Dn) { + $newParentDnParts = $to->toArray(); + } else { + $newParentDnParts = Zend_Ldap_Dn::explodeDn($to); + } + + $newDnParts = array_merge(array(array_shift($orgDnParts)), $newParentDnParts); + $newDn = Zend_Ldap_Dn::fromArray($newDnParts); + return $this->copy($from, $newDn, $recursively); + } + + /** + * Copies a LDAP entry from one DN to another DN. + * + * @param string|Zend_Ldap_Dn $from + * @param string|Zend_Ldap_Dn $to + * @param boolean $recursively + * @return Zend_Ldap Provides a fluid interface + * @throws Zend_Ldap_Exception + */ + public function copy($from, $to, $recursively = false) + { + $entry = $this->getEntry($from, array(), true); + + if ($to instanceof Zend_Ldap_Dn) { + $toDnParts = $to->toArray(); + } else { + $toDnParts = Zend_Ldap_Dn::explodeDn($to); + } + $this->add($to, $entry); + + if ($recursively === true && $this->countChildren($from)>0) { + $children = $this->_getChildrenDns($from); + foreach ($children as $c) { + $cDnParts = Zend_Ldap_Dn::explodeDn($c); + $newChildParts = array_merge(array(array_shift($cDnParts)), $toDnParts); + $newChild = Zend_Ldap_Dn::implodeDn($newChildParts); + $this->copy($c, $newChild, true); + } + } + return $this; + } + + /** + * Returns the specified DN as a Zend_Ldap_Node + * + * @param string|Zend_Ldap_Dn $dn + * @return Zend_Ldap_Node|null + * @throws Zend_Ldap_Exception + */ + public function getNode($dn) + { + /** + * Zend_Ldap_Node + */ + require_once 'Zend/Ldap/Node.php'; + return Zend_Ldap_Node::fromLdap($dn, $this); + } + + /** + * Returns the base node as a Zend_Ldap_Node + * + * @return Zend_Ldap_Node + * @throws Zend_Ldap_Exception + */ + public function getBaseNode() + { + return $this->getNode($this->getBaseDn(), $this); + } + + /** + * Returns the RootDSE + * + * @return Zend_Ldap_Node_RootDse + * @throws Zend_Ldap_Exception + */ + public function getRootDse() + { + if ($this->_rootDse === null) { + /** + * @see Zend_Ldap_Node_Schema + */ + require_once 'Zend/Ldap/Node/RootDse.php'; + $this->_rootDse = Zend_Ldap_Node_RootDse::create($this); + } + return $this->_rootDse; + } + + /** + * Returns the schema + * + * @return Zend_Ldap_Node_Schema + * @throws Zend_Ldap_Exception + */ + public function getSchema() + { + if ($this->_schema === null) { + /** + * @see Zend_Ldap_Node_Schema + */ + require_once 'Zend/Ldap/Node/Schema.php'; + $this->_schema = Zend_Ldap_Node_Schema::create($this); + } + return $this->_schema; + } +} Index: /sandbox/2.2.0.2/library/Zend/Mail.php =================================================================== --- /sandbox/2.2.0.2/library/Zend/Mail.php (revision 4445) +++ /sandbox/2.2.0.2/library/Zend/Mail.php (revision 4445) @@ -0,0 +1,1277 @@ +_charset = $charset; + } + } + + /** + * Return charset string + * + * @return string + */ + public function getCharset() + { + return $this->_charset; + } + + /** + * Set content type + * + * Should only be used for manually setting multipart content types. + * + * @param string $type Content type + * @return Zend_Mail Implements fluent interface + * @throws Zend_Mail_Exception for types not supported by Zend_Mime + */ + public function setType($type) + { + $allowed = array( + Zend_Mime::MULTIPART_ALTERNATIVE, + Zend_Mime::MULTIPART_MIXED, + Zend_Mime::MULTIPART_RELATED, + ); + if (!in_array($type, $allowed)) { + /** + * @see Zend_Mail_Exception + */ + require_once 'Zend/Mail/Exception.php'; + throw new Zend_Mail_Exception('Invalid content type "' . $type . '"'); + } + + $this->_type = $type; + return $this; + } + + /** + * Get content type of the message + * + * @return string + */ + public function getType() + { + return $this->_type; + } + + /** + * Set an arbitrary mime boundary for the message + * + * If not set, Zend_Mime will generate one. + * + * @param string $boundary + * @return Zend_Mail Provides fluent interface + */ + public function setMimeBoundary($boundary) + { + $this->_mimeBoundary = $boundary; + + return $this; + } + + /** + * Return the boundary string used for the message + * + * @return string + */ + public function getMimeBoundary() + { + return $this->_mimeBoundary; + } + + /** + * Return encoding of mail headers + * + * @deprecated use {@link getHeaderEncoding()} instead + * @return string + */ + public function getEncodingOfHeaders() + { + return $this->getHeaderEncoding(); + } + + /** + * Return the encoding of mail headers + * + * Either Zend_Mime::ENCODING_QUOTEDPRINTABLE or Zend_Mime::ENCODING_BASE64 + * + * @return string + */ + public function getHeaderEncoding() + { + return $this->_headerEncoding; + } + + /** + * Set the encoding of mail headers + * + * @deprecated Use {@link setHeaderEncoding()} instead. + * @param string $encoding + * @return Zend_Mail + */ + public function setEncodingOfHeaders($encoding) + { + return $this->setHeaderEncoding($encoding); + } + + /** + * Set the encoding of mail headers + * + * @param string $encoding Zend_Mime::ENCODING_QUOTEDPRINTABLE or Zend_Mime::ENCODING_BASE64 + * @return Zend_Mail Provides fluent interface + */ + public function setHeaderEncoding($encoding) + { + $allowed = array( + Zend_Mime::ENCODING_BASE64, + Zend_Mime::ENCODING_QUOTEDPRINTABLE + ); + if (!in_array($encoding, $allowed)) { + /** + * @see Zend_Mail_Exception + */ + require_once 'Zend/Mail/Exception.php'; + throw new Zend_Mail_Exception('Invalid encoding "' . $encoding . '"'); + } + $this->_headerEncoding = $encoding; + + return $this; + } + + /** + * Sets the text body for the message. + * + * @param string $txt + * @param string $charset + * @param string $encoding + * @return Zend_Mail Provides fluent interface + */ + public function setBodyText($txt, $charset = null, $encoding = Zend_Mime::ENCODING_QUOTEDPRINTABLE) + { + if ($charset === null) { + $charset = $this->_charset; + } + + $mp = new Zend_Mime_Part($txt); + $mp->encoding = $encoding; + $mp->type = Zend_Mime::TYPE_TEXT; + $mp->disposition = Zend_Mime::DISPOSITION_INLINE; + $mp->charset = $charset; + + $this->_bodyText = $mp; + + return $this; + } + + /** + * Return text body Zend_Mime_Part or string + * + * @param bool textOnly Whether to return just the body text content or the MIME part; defaults to false, the MIME part + * @return false|Zend_Mime_Part|string + */ + public function getBodyText($textOnly = false) + { + if ($textOnly && $this->_bodyText) { + $body = $this->_bodyText; + return $body->getContent(); + } + + return $this->_bodyText; + } + + /** + * Sets the HTML body for the message + * + * @param string $html + * @param string $charset + * @param string $encoding + * @return Zend_Mail Provides fluent interface + */ + public function setBodyHtml($html, $charset = null, $encoding = Zend_Mime::ENCODING_QUOTEDPRINTABLE) + { + if ($charset === null) { + $charset = $this->_charset; + } + + $mp = new Zend_Mime_Part($html); + $mp->encoding = $encoding; + $mp->type = Zend_Mime::TYPE_HTML; + $mp->disposition = Zend_Mime::DISPOSITION_INLINE; + $mp->charset = $charset; + + $this->_bodyHtml = $mp; + + return $this; + } + + /** + * Return Zend_Mime_Part representing body HTML + * + * @param bool $htmlOnly Whether to return the body HTML only, or the MIME part; defaults to false, the MIME part + * @return false|Zend_Mime_Part|string + */ + public function getBodyHtml($htmlOnly = false) + { + if ($htmlOnly && $this->_bodyHtml) { + $body = $this->_bodyHtml; + return $body->getContent(); + } + + return $this->_bodyHtml; + } + + /** + * Adds an existing attachment to the mail message + * + * @param Zend_Mime_Part $attachment + * @return Zend_Mail Provides fluent interface + */ + public function addAttachment(Zend_Mime_Part $attachment) + { + $this->addPart($attachment); + $this->hasAttachments = true; + + return $this; + } + + /** + * Creates a Zend_Mime_Part attachment + * + * Attachment is automatically added to the mail object after creation. The + * attachment object is returned to allow for further manipulation. + * + * @param string $body + * @param string $mimeType + * @param string $disposition + * @param string $encoding + * @param string $filename OPTIONAL A filename for the attachment + * @return Zend_Mime_Part Newly created Zend_Mime_Part object (to allow + * advanced settings) + */ + public function createAttachment($body, + $mimeType = Zend_Mime::TYPE_OCTETSTREAM, + $disposition = Zend_Mime::DISPOSITION_ATTACHMENT, + $encoding = Zend_Mime::ENCODING_BASE64, + $filename = null) + { + + $mp = new Zend_Mime_Part($body); + $mp->encoding = $encoding; + $mp->type = $mimeType; + $mp->disposition = $disposition; + $mp->filename = $filename; + + $this->addAttachment($mp); + + return $mp; + } + + /** + * Return a count of message parts + * + * @return integer + */ + public function getPartCount() + { + return count($this->_parts); + } + + /** + * Encode header fields + * + * Encodes header content according to RFC1522 if it contains non-printable + * characters. + * + * @param string $value + * @return string + */ + protected function _encodeHeader($value) + { + if (Zend_Mime::isPrintable($value) === false) { + if ($this->getHeaderEncoding() === Zend_Mime::ENCODING_QUOTEDPRINTABLE) { + $value = Zend_Mime::encodeQuotedPrintableHeader($value, $this->getCharset(), Zend_Mime::LINELENGTH, Zend_Mime::LINEEND); + } else { + $value = Zend_Mime::encodeBase64Header($value, $this->getCharset(), Zend_Mime::LINELENGTH, Zend_Mime::LINEEND); + } + } + + return $value; + } + + /** + * Add a header to the message + * + * Adds a header to this message. If append is true and the header already + * exists, raises a flag indicating that the header should be appended. + * + * @param string $headerName + * @param string $value + * @param bool $append + */ + protected function _storeHeader($headerName, $value, $append = false) + { + if (isset($this->_headers[$headerName])) { + $this->_headers[$headerName][] = $value; + } else { + $this->_headers[$headerName] = array($value); + } + + if ($append) { + $this->_headers[$headerName]['append'] = true; + } + + } + + /** + * Clear header from the message + * + * @param string $headerName + * @deprecated use public method directly + */ + protected function _clearHeader($headerName) + { + $this->clearHeader($headerName); + } + + /** + * Helper function for adding a recipient and the corresponding header + * + * @param string $headerName + * @param string $email + * @param string $name + */ + protected function _addRecipientAndHeader($headerName, $email, $name) + { + $email = $this->_filterEmail($email); + $name = $this->_filterName($name); + // prevent duplicates + $this->_recipients[$email] = 1; + $this->_storeHeader($headerName, $this->_formatAddress($email, $name), true); + } + + /** + * Adds To-header and recipient, $email can be an array, or a single string address + * + * @param string|array $email + * @param string $name + * @return Zend_Mail Provides fluent interface + */ + public function addTo($email, $name='') + { + if (!is_array($email)) { + $email = array($name => $email); + } + + foreach ($email as $n => $recipient) { + $this->_addRecipientAndHeader('To', $recipient, is_int($n) ? '' : $n); + $this->_to[] = $recipient; + } + + return $this; + } + + /** + * Adds Cc-header and recipient, $email can be an array, or a single string address + * + * @param string|array $email + * @param string $name + * @return Zend_Mail Provides fluent interface + */ + public function addCc($email, $name='') + { + if (!is_array($email)) { + $email = array($name => $email); + } + + foreach ($email as $n => $recipient) { + $this->_addRecipientAndHeader('Cc', $recipient, is_int($n) ? '' : $n); + } + + return $this; + } + + /** + * Adds Bcc recipient, $email can be an array, or a single string address + * + * @param string|array $email + * @return Zend_Mail Provides fluent interface + */ + public function addBcc($email) + { + if (!is_array($email)) { + $email = array($email); + } + + foreach ($email as $recipient) { + $this->_addRecipientAndHeader('Bcc', $recipient, ''); + } + + return $this; + } + + /** + * Return list of recipient email addresses + * + * @return array (of strings) + */ + public function getRecipients() + { + return array_keys($this->_recipients); + } + + /** + * Clear header from the message + * + * @param string $headerName + * @return Zend_Mail Provides fluent inter + */ + public function clearHeader($headerName) + { + if (isset($this->_headers[$headerName])){ + unset($this->_headers[$headerName]); + } + return $this; + } + + /** + * Clears list of recipient email addresses + * + * @return Zend_Mail Provides fluent interface + */ + public function clearRecipients() + { + $this->_recipients = array(); + $this->_to = array(); + + $this->clearHeader('To'); + $this->clearHeader('Cc'); + $this->clearHeader('Bcc'); + + return $this; + } + + /** + * Sets From-header and sender of the message + * + * @param string $email + * @param string $name + * @return Zend_Mail Provides fluent interface + * @throws Zend_Mail_Exception if called subsequent times + */ + public function setFrom($email, $name = null) + { + if (null !== $this->_from) { + /** + * @see Zend_Mail_Exception + */ + require_once 'Zend/Mail/Exception.php'; + throw new Zend_Mail_Exception('From Header set twice'); + } + + $email = $this->_filterEmail($email); + $name = $this->_filterName($name); + $this->_from = $email; + $this->_storeHeader('From', $this->_formatAddress($email, $name), true); + + return $this; + } + + /** + * Set Reply-To Header + * + * @param string $email + * @param string $name + * @return Zend_Mail + * @throws Zend_Mail_Exception if called more than one time + */ + public function setReplyTo($email, $name = null) + { + if (null !== $this->_replyTo) { + /** + * @see Zend_Mail_Exception + */ + require_once 'Zend/Mail/Exception.php'; + throw new Zend_Mail_Exception('Reply-To Header set twice'); + } + + $email = $this->_filterEmail($email); + $name = $this->_filterName($name); + $this->_replyTo = $email; + $this->_storeHeader('Reply-To', $this->_formatAddress($email, $name), true); + + return $this; + } + + /** + * Returns the sender of the mail + * + * @return string + */ + public function getFrom() + { + return $this->_from; + } + + /** + * Returns the current Reply-To address of the message + * + * @return string|null Reply-To address, null when not set + */ + public function getReplyTo() + { + return $this->_replyTo; + } + + /** + * Clears the sender from the mail + * + * @return Zend_Mail Provides fluent interface + */ + public function clearFrom() + { + $this->_from = null; + $this->clearHeader('From'); + + return $this; + } + + /** + * Clears the current Reply-To address from the message + * + * @return Zend_Mail Provides fluent interface + */ + public function clearReplyTo() + { + $this->_replyTo = null; + $this->clearHeader('Reply-To'); + + return $this; + } + + /** + * Sets Default From-email and name of the message + * + * @param string $email + * @param string Optional $name + * @return void + */ + public static function setDefaultFrom($email, $name = null) + { + self::$_defaultFrom = array('email' => $email, 'name' => $name); + } + + /** + * Returns the default sender of the mail + * + * @return null|array Null if none was set. + */ + public static function getDefaultFrom() + { + return self::$_defaultFrom; + } + + /** + * Clears the default sender from the mail + * + * @return void + */ + public static function clearDefaultFrom() + { + self::$_defaultFrom = null; + } + + /** + * Sets From-name and -email based on the defaults + * + * @return Zend_Mail Provides fluent interface + */ + public function setFromToDefaultFrom() { + $from = self::getDefaultFrom(); + if($from === null) { + require_once 'Zend/Mail/Exception.php'; + throw new Zend_Mail_Exception( + 'No default From Address set to use'); + } + + $this->setFrom($from['email'], $from['name']); + + return $this; + } + + /** + * Sets Default ReplyTo-address and -name of the message + * + * @param string $email + * @param string Optional $name + * @return void + */ + public static function setDefaultReplyTo($email, $name = null) + { + self::$_defaultReplyTo = array('email' => $email, 'name' => $name); + } + + /** + * Returns the default Reply-To Address and Name of the mail + * + * @return null|array Null if none was set. + */ + public static function getDefaultReplyTo() + { + return self::$_defaultReplyTo; + } + + /** + * Clears the default ReplyTo-address and -name from the mail + * + * @return void + */ + public static function clearDefaultReplyTo() + { + self::$_defaultReplyTo = null; + } + + /** + * Sets ReplyTo-name and -email based on the defaults + * + * @return Zend_Mail Provides fluent interface + */ + public function setReplyToFromDefault() { + $replyTo = self::getDefaultReplyTo(); + if($replyTo === null) { + require_once 'Zend/Mail/Exception.php'; + throw new Zend_Mail_Exception( + 'No default Reply-To Address set to use'); + } + + $this->setReplyTo($replyTo['email'], $replyTo['name']); + + return $this; + } + + /** + * Sets the Return-Path header of the message + * + * @param string $email + * @return Zend_Mail Provides fluent interface + * @throws Zend_Mail_Exception if set multiple times + */ + public function setReturnPath($email) + { + if ($this->_returnPath === null) { + $email = $this->_filterEmail($email); + $this->_returnPath = $email; + $this->_storeHeader('Return-Path', $email, false); + } else { + /** + * @see Zend_Mail_Exception + */ + require_once 'Zend/Mail/Exception.php'; + throw new Zend_Mail_Exception('Return-Path Header set twice'); + } + return $this; + } + + /** + * Returns the current Return-Path address of the message + * + * If no Return-Path header is set, returns the value of {@link $_from}. + * + * @return string + */ + public function getReturnPath() + { + if (null !== $this->_returnPath) { + return $this->_returnPath; + } + + return $this->_from; + } + + /** + * Clears the current Return-Path address from the message + * + * @return Zend_Mail Provides fluent interface + */ + public function clearReturnPath() + { + $this->_returnPath = null; + $this->clearHeader('Return-Path'); + + return $this; + } + + /** + * Sets the subject of the message + * + * @param string $subject + * @return Zend_Mail Provides fluent interface + * @throws Zend_Mail_Exception + */ + public function setSubject($subject) + { + if ($this->_subject === null) { + $subject = $this->_filterOther($subject); + $this->_subject = $this->_encodeHeader($subject); + $this->_storeHeader('Subject', $this->_subject); + } else { + /** + * @see Zend_Mail_Exception + */ + require_once 'Zend/Mail/Exception.php'; + throw new Zend_Mail_Exception('Subject set twice'); + } + return $this; + } + + /** + * Returns the encoded subject of the message + * + * @return string + */ + public function getSubject() + { + return $this->_subject; + } + + /** + * Clears the encoded subject from the message + * + * @return Zend_Mail Provides fluent interface + */ + public function clearSubject() + { + $this->_subject = null; + $this->clearHeader('Subject'); + + return $this; + } + + /** + * Sets Date-header + * + * @param timestamp|string|Zend_Date $date + * @return Zend_Mail Provides fluent interface + * @throws Zend_Mail_Exception if called subsequent times or wrong date format. + */ + public function setDate($date = null) + { + if ($this->_date === null) { + if ($date === null) { + $date = date('r'); + } else if (is_int($date)) { + $date = date('r', $date); + } else if (is_string($date)) { + $date = strtotime($date); + if ($date === false || $date < 0) { + /** + * @see Zend_Mail_Exception + */ + require_once 'Zend/Mail/Exception.php'; + throw new Zend_Mail_Exception('String representations of Date Header must be ' . + 'strtotime()-compatible'); + } + $date = date('r', $date); + } else if ($date instanceof Zend_Date) { + $date = $date->get(Zend_Date::RFC_2822); + } else { + /** + * @see Zend_Mail_Exception + */ + require_once 'Zend/Mail/Exception.php'; + throw new Zend_Mail_Exception(__METHOD__ . ' only accepts UNIX timestamps, Zend_Date objects, ' . + ' and strtotime()-compatible strings'); + } + $this->_date = $date; + $this->_storeHeader('Date', $date); + } else { + /** + * @see Zend_Mail_Exception + */ + require_once 'Zend/Mail/Exception.php'; + throw new Zend_Mail_Exception('Date Header set twice'); + } + return $this; + } + + /** + * Returns the formatted date of the message + * + * @return string + */ + public function getDate() + { + return $this->_date; + } + + /** + * Clears the formatted date from the message + * + * @return Zend_Mail Provides fluent interface + */ + public function clearDate() + { + $this->_date = null; + $this->clearHeader('Date'); + + return $this; + } + + /** + * Sets the Message-ID of the message + * + * @param boolean|string $id + * true :Auto + * false :No set + * null :No set + * string:Sets given string (Angle brackets is not necessary) + * @return Zend_Mail Provides fluent interface + * @throws Zend_Mail_Exception + */ + public function setMessageId($id = true) + { + if ($id === null || $id === false) { + return $this; + } elseif ($id === true) { + $id = $this->createMessageId(); + } + + if ($this->_messageId === null) { + $id = $this->_filterOther($id); + $this->_messageId = $id; + $this->_storeHeader('Message-Id', '<' . $this->_messageId . '>'); + } else { + /** + * @see Zend_Mail_Exception + */ + require_once 'Zend/Mail/Exception.php'; + throw new Zend_Mail_Exception('Message-ID set twice'); + } + + return $this; + } + + /** + * Returns the Message-ID of the message + * + * @return string + */ + public function getMessageId() + { + return $this->_messageId; + } + + + /** + * Clears the Message-ID from the message + * + * @return Zend_Mail Provides fluent interface + */ + public function clearMessageId() + { + $this->_messageId = null; + $this->clearHeader('Message-Id'); + + return $this; + } + + /** + * Creates the Message-ID + * + * @return string + */ + public function createMessageId() { + + $time = time(); + + if ($this->_from !== null) { + $user = $this->_from; + } elseif (isset($_SERVER['REMOTE_ADDR'])) { + $user = $_SERVER['REMOTE_ADDR']; + } else { + $user = getmypid(); + } + + $rand = mt_rand(); + + if ($this->_recipients !== array()) { + $recipient = array_rand($this->_recipients); + } else { + $recipient = 'unknown'; + } + + if (isset($_SERVER["SERVER_NAME"])) { + $hostName = $_SERVER["SERVER_NAME"]; + } else { + $hostName = php_uname('n'); + } + + return sha1($time . $user . $rand . $recipient) . '@' . $hostName; + } + + /** + * Add a custom header to the message + * + * @param string $name + * @param string $value + * @param boolean $append + * @return Zend_Mail Provides fluent interface + * @throws Zend_Mail_Exception on attempts to create standard headers + */ + public function addHeader($name, $value, $append = false) + { + $prohibit = array('to', 'cc', 'bcc', 'from', 'subject', + 'reply-to', 'return-path', + 'date', 'message-id', + ); + if (in_array(strtolower($name), $prohibit)) { + /** + * @see Zend_Mail_Exception + */ + require_once 'Zend/Mail/Exception.php'; + throw new Zend_Mail_Exception('Cannot set standard header from addHeader()'); + } + + $value = $this->_filterOther($value); + $value = $this->_encodeHeader($value); + $this->_storeHeader($name, $value, $append); + + return $this; + } + + /** + * Return mail headers + * + * @return void + */ + public function getHeaders() + { + return $this->_headers; + } + + /** + * Sends this email using the given transport or a previously + * set DefaultTransport or the internal mail function if no + * default transport had been set. + * + * @param Zend_Mail_Transport_Abstract $transport + * @return Zend_Mail Provides fluent interface + */ + public function send($transport = null) + { + if ($transport === null) { + if (! self::$_defaultTransport instanceof Zend_Mail_Transport_Abstract) { + require_once 'Zend/Mail/Transport/Sendmail.php'; + $transport = new Zend_Mail_Transport_Sendmail(); + } else { + $transport = self::$_defaultTransport; + } + } + + if ($this->_date === null) { + $this->setDate(); + } + + if(null === $this->_from && null !== self::getDefaultFrom()) { + $this->setFromToDefaultFrom(); + } + + if(null === $this->_replyTo && null !== self::getDefaultReplyTo()) { + $this->setReplyToFromDefault(); + } + + $transport->send($this); + + return $this; + } + + /** + * Filter of email data + * + * @param string $email + * @return string + */ + protected function _filterEmail($email) + { + $rule = array("\r" => '', + "\n" => '', + "\t" => '', + '"' => '', + ',' => '', + '<' => '', + '>' => '', + ); + + return strtr($email, $rule); + } + + /** + * Filter of name data + * + * @param string $name + * @return string + */ + protected function _filterName($name) + { + $rule = array("\r" => '', + "\n" => '', + "\t" => '', + '"' => "'", + '<' => '[', + '>' => ']', + ); + + return trim(strtr($name, $rule)); + } + + /** + * Filter of other data + * + * @param string $data + * @return string + */ + protected function _filterOther($data) + { + $rule = array("\r" => '', + "\n" => '', + "\t" => '', + ); + + return strtr($data, $rule); + } + + /** + * Formats e-mail address + * + * @param string $email + * @param string $name + * @return string + */ + protected function _formatAddress($email, $name) + { + if ($name === '' || $name === null || $name === $email) { + return $email; + } else { + $encodedName = $this->_encodeHeader($name); + if ($encodedName === $name && + ((strpos($name, '@') !== false) || (strpos($name, ',') !== false))) { + $format = '"%s" <%s>'; + } else { + $format = '%s <%s>'; + } + return sprintf($format, $encodedName, $email); + } + } + +} Index: /sandbox/2.2.0.2/library/Zend/Mime.php =================================================================== --- /sandbox/2.2.0.2/library/Zend/Mime.php (revision 4445) +++ /sandbox/2.2.0.2/library/Zend/Mime.php (revision 4445) @@ -0,0 +1,365 @@ + $lineLength) { + $ptr = $lineLength; + } + + // Ensure we are not splitting across an encoded character + $pos = strrpos(substr($str, 0, $ptr), '='); + if ($pos !== false && $pos >= $ptr - 2) { + $ptr = $pos; + } + + // Check if there is a space at the end of the line and rewind + if ($ptr > 0 && $str[$ptr - 1] == ' ') { + --$ptr; + } + + // Add string and continue + $out .= substr($str, 0, $ptr) . '=' . $lineEnd; + $str = substr($str, $ptr); + } + + $out = rtrim($out, $lineEnd); + $out = rtrim($out, '='); + return $out; + } + + /** + * Converts a string into quoted printable format. + * + * @param string $str + * @return string + */ + private static function _encodeQuotedPrintable($str) + { + $str = str_replace('=', '=3D', $str); + $str = str_replace(self::$qpKeys, self::$qpReplaceValues, $str); + $str = rtrim($str); + return $str; + } + + /** + * Encode a given string with the QUOTED_PRINTABLE mechanism for Mail Headers. + * + * Mail headers depend on an extended quoted printable algorithm otherwise + * a range of bugs can occur. + * + * @param string $str + * @param string $charset + * @param int $lineLength Defaults to {@link LINELENGTH} + * @param int $lineEnd Defaults to {@link LINEEND} + * @return string + */ + public static function encodeQuotedPrintableHeader($str, $charset, + $lineLength = self::LINELENGTH, + $lineEnd = self::LINEEND) + { + // Reduce line-length by the length of the required delimiter, charsets and encoding + $prefix = sprintf('=?%s?Q?', $charset); + $lineLength = $lineLength-strlen($prefix)-3; + + $str = self::_encodeQuotedPrintable($str); + + // Mail-Header required chars have to be encoded also: + $str = str_replace(array('?', ' ', '_'), array('=3F', '=20', '=5F'), $str); + + // initialize first line, we need it anyways + $lines = array(0 => ""); + + // Split encoded text into separate lines + $tmp = ""; + while(strlen($str) > 0) { + $currentLine = max(count($lines)-1, 0); + $token = self::getNextQuotedPrintableToken($str); + $str = substr($str, strlen($token)); + + $tmp .= $token; + if($token == '=20') { + // only if we have a single char token or space, we can append the + // tempstring it to the current line or start a new line if necessary. + if(strlen($lines[$currentLine].$tmp) > $lineLength) { + $lines[$currentLine+1] = $tmp; + } else { + $lines[$currentLine] .= $tmp; + } + $tmp = ""; + } + // don't forget to append the rest to the last line + if(strlen($str) == 0) { + $lines[$currentLine] .= $tmp; + } + } + + // assemble the lines together by pre- and appending delimiters, charset, encoding. + for($i = 0; $i < count($lines); $i++) { + $lines[$i] = " ".$prefix.$lines[$i]."?="; + } + $str = trim(implode($lineEnd, $lines)); + return $str; + } + + /** + * Retrieves the first token from a quoted printable string. + * + * @param string $str + * @return string + */ + private static function getNextQuotedPrintableToken($str) + { + if(substr($str, 0, 1) == "=") { + $token = substr($str, 0, 3); + } else { + $token = substr($str, 0, 1); + } + return $token; + } + + /** + * Encode a given string in mail header compatible base64 encoding. + * + * @param string $str + * @param string $charset + * @param int $lineLength Defaults to {@link LINELENGTH} + * @param int $lineEnd Defaults to {@link LINEEND} + * @return string + */ + public static function encodeBase64Header($str, + $charset, + $lineLength = self::LINELENGTH, + $lineEnd = self::LINEEND) + { + $prefix = '=?' . $charset . '?B?'; + $suffix = '?='; + $remainingLength = $lineLength - strlen($prefix) - strlen($suffix); + + $encodedValue = self::encodeBase64($str, $remainingLength, $lineEnd); + $encodedValue = str_replace($lineEnd, $suffix . $lineEnd . ' ' . $prefix, $encodedValue); + $encodedValue = $prefix . $encodedValue . $suffix; + return $encodedValue; + } + + /** + * Encode a given string in base64 encoding and break lines + * according to the maximum linelength. + * + * @param string $str + * @param int $lineLength Defaults to {@link LINELENGTH} + * @param int $lineEnd Defaults to {@link LINEEND} + * @return string + */ + public static function encodeBase64($str, + $lineLength = self::LINELENGTH, + $lineEnd = self::LINEEND) + { + return rtrim(chunk_split(base64_encode($str), $lineLength, $lineEnd)); + } + + /** + * Constructor + * + * @param null|string $boundary + * @access public + * @return void + */ + public function __construct($boundary = null) + { + // This string needs to be somewhat unique + if ($boundary === null) { + $this->_boundary = '=_' . md5(microtime(1) . self::$makeUnique++); + } else { + $this->_boundary = $boundary; + } + } + + /** + * Encode the given string with the given encoding. + * + * @param string $str + * @param string $encoding + * @param string $EOL EOL string; defaults to {@link Zend_Mime::LINEEND} + * @return string + */ + public static function encode($str, $encoding, $EOL = self::LINEEND) + { + switch ($encoding) { + case self::ENCODING_BASE64: + return self::encodeBase64($str, self::LINELENGTH, $EOL); + + case self::ENCODING_QUOTEDPRINTABLE: + return self::encodeQuotedPrintable($str, self::LINELENGTH, $EOL); + + default: + /** + * @todo 7Bit and 8Bit is currently handled the same way. + */ + return $str; + } + } + + /** + * Return a MIME boundary + * + * @access public + * @return string + */ + public function boundary() + { + return $this->_boundary; + } + + /** + * Return a MIME boundary line + * + * @param mixed $EOL Defaults to {@link LINEEND} + * @access public + * @return string + */ + public function boundaryLine($EOL = self::LINEEND) + { + return $EOL . '--' . $this->_boundary . $EOL; + } + + /** + * Return MIME ending + * + * @access public + * @return string + */ + public function mimeEnd($EOL = self::LINEEND) + { + return $EOL . '--' . $this->_boundary . '--' . $EOL; + } +} Index: /sandbox/2.2.0.2/API/class.servicelocator.php =================================================================== --- /sandbox/2.2.0.2/API/class.servicelocator.php (revision 4445) +++ /sandbox/2.2.0.2/API/class.servicelocator.php (revision 4445) @@ -0,0 +1,216 @@ + $serviceName ) + { + self::deploy( $serviceType, $serviceName ); + } + } + + static function deploy( $serviceType, $serviceName = null ) + { + require_once( SERVICES."class.".$serviceType.".php" ); + + if( $serviceName ) + { + self::register( $serviceType, new $serviceName() ); + } + + return( self::$locators[ $serviceType ] ); + } + + //make all the treatment of + static function register( $service, $object ) + { + self::$locators[ $service ] = new ServiceLocator( $service, $object ); + + self::configure( $service ); + + return( self::$locators[ $service ] ); + } + + static function unregister( $service ) + { + $old = self::$locators[ $service ]; + + unset( self::$locators[ $service ] ); + + return( $old ); + } + + //implement + static function configure( $service ) + { + return( null ); + } + + static function locate( $service, $arguments = array(), $target = false ) + { + if( !$target ) + { + list( $target, $service ) = explode( ".", $service ); + } + + if( !is_array( $arguments ) ) + { + $arguments = array( $arguments ); + } + + $locator = self::$locators[ $target ]; + + if( !$locator ) + { + $locator = self::deploy( $target ); + } + if( !$locator ) + { + return( false ); + } + + try + { + return $locator->proxy( $service, $arguments ); + } + catch( Exception $e ) + { + //Implement the exception stack to the fallback handlers treat correctly + //by now - fly it + } + + return( null ); + } + + function __construct( $serviceName, $object ) + { + $this->service = $object; + $this->serviceName = $serviceName; + } + + function proxy( $method, $arguments ) + { + //handle here cases of miss of methods + if( !method_exists( $this->service, $method ) ) return( false ); + + $many = count( $arguments ); + + $proxy = self::$cache[$many]; + + if( !$proxy ) + { + $params = array(); + + for( $i = 0; $i < $many; $params[] = '$params['.$i++.']' ); + + $proxy = create_function( '$method, $params, $obj', 'return $obj->$method('.implode( ', ', $params ).');' ); + + self::$cache[$many] = $proxy; + } + + if( !isset( $arguments ) ) return( $proxy ); + + return $proxy( $method, $arguments, $this->service ); + } + + function call() + { + $arguments = func_get_args(); + + $service = array_pop( $arguments ); + + //handle here dispatch with invalid services + if( $this ) + { + $service = strrpos( $service, "." ) ? $service : $this->serviceName.".".$service; + } + + return self::locate( $service, $arguments ); + } + + function dispatch( $service, $arguments ) + { + //handle here dispatch with invalid services + if( $this ) + { + $service = strrpos( $service, "." ) ? $service : $this->serviceName.".".$service; + } + + return self::locate( $service, $arguments ); + } + + function __call( $method, $arguments ) + { + return self::locate( $method, $arguments, $this->serviceName ); + } + + function __get( $name ) + { + return $this->service->$name; + } + + static function __callStatic( $method, $arguments ) + { + return self::locate( $method, $arguments ); + } + + static function getService( $service ) + { + if( !self::$locators[ $service ] ) + { + self::deploy( $service ); + } + + return( clone self::$locators[ $service ] ); + } +} + +} + +//estudar uma forma mais elegante de carregar os servicos +//ServiceLocator::load( "services.conf" ); + +?> Index: /sandbox/2.2.0.2/expressoAdmin1_2/js/jscode/finder.js =================================================================== --- /sandbox/2.2.0.2/expressoAdmin1_2/js/jscode/finder.js (revision 4445) +++ /sandbox/2.2.0.2/expressoAdmin1_2/js/jscode/finder.js (revision 4445) @@ -0,0 +1,435 @@ + +var current_value = ""; + +var default_limit = 0; + +var sizelimit = 10; + +function Element( id ) +{ + return document.getElementById( id ); +} + +function optionFind( id, selectId, url, ctxId, labelId ) +{ + var fillHandler = function( fill, raw ){ + + return fillContentSelect( fill, selectId ); + + }; + + getAvailable( id, fillHandler, url, ctxId, labelId, true ); +} + +function getAvailable( id, fillHandler, url, ctxId, labelId, bypass ) +{ + if( id ) + { + var sentence = Element( id ); + + sentence = sentence ? sentence.value : id; + + url += "&filter=" + sentence + "&sentence=" + sentence; + } + + if( ctxId ) + { + var ctx = Element( ctxId ); + + ctx = ctx ? ctx.value : ctxId; + + url += "&context=" + ctx; + } + + if( bypass ) + bypass = bypassParser; + + userFinder( sentence, fillHandler, url, bypass, labelId ); +} + +var default_field = "cn"; + +function userFinder( sentence, selectId, url, handler, labelId ) +{ + if( sentence === current_value ) + return; + + //current_value = sentence; + + if( typeof limit === "undefined" ) + limit = default_limit; + + //TODO: tornar esse limite configuravel de acordo com a configuracao do expresso + if( sentence.length < limit ) + return( false ); + + if( typeof handler === "string" && + typeof labelId === "undefined" ) + labelId = handler, + handler = undefined; + + if( typeof get_lang === "undefined" ) + get_lang = function( key ){ + var translator = Element( "txt_" + key ); + + return translator ? translator.value : key; + }; + + var urlHandler = function(){ + + if( labelId ) + Element( labelId ).innerHTML = get_lang('searching') + '...'; + + if( typeof url === "function" ) + url = url(); + + return( url ); + }; + + var defaultParser = function( data, raw ){ + + if( labelId ) + Element( labelId ).innerHTML = ' '; + + var result = false; + + if( handler ) + result = handler( data, raw ); + + if( result ) + return( result ); + + if( typeof data === "string" ) + return( data ); + + return stackParser( data, default_field ); + }; + + var fillHandler = function( fill, raw ) + { + var sizeof = 0; + + if( typeof selectId === "string" ) + sizeof = fillSelect( fill, selectId, default_field ); + else + sizeof = selectId( fill, raw ); + + if( labelId && sizeof >= sizelimit ) + Element( labelId ).innerHTML = 'Muitos resultados encontrados. Por favor, refine sua busca.'; + + return( !sizeof ); + } + + return finder( sentence, fillHandler, urlHandler, defaultParser ); +} + +function finder( sentences, fillHandler, url, parser ) +{ + //caso fillHandler nao seja uma funcao, usar a default +// if( typeof fillHandler === "string" ) +// { +// var selectId = fillHandler; +// +// fillHandler = function( fill ){ +// +// return !fillSelect( fill, selectId, default_field ); +// +// }; +// } + + return lookup( sentences, fillHandler, url, parser, fillHandler ); +} + +function getExp( sentence ) +{ + sentence = sentence.replace(/^\s*/, "").replace(/\s*$/, ""); + + sentence = sentence.replace( / /gi, ".*" ); + + sentence = new RegExp( ".*" + sentence + ".*", "i" ); + + return( sentence ); +} + +var options_cache = {}; + +function setOptions( fill, select, field ) +{ + for( var value in fill ) + { + if( !options_cache[value] ) + options_cache[value] = {}; + + if( !options_cache[value][field] ) + options_cache[value][field] = new Option( fill[value][field], value ); + + select[select.length] = options_cache[value][field]; + } + + return( select ); +} + +function fillSelect( fill, selectId, field ) +{ + //recupera as options do respectivo select + var select = Element( selectId ).options; + + //Limpa todo o select + select.length = 0; + + //Inclui usuario comecando com a pesquisa + select = setOptions( fill, select, field ); + + //chama o server side caso nao encontre resultado nenhum com essa sentenca + return( select.length ); +} + +function fillContentSelect( fill, selectId ) +{ + if( typeof fill === "string" ) + { + var select = Element( selectId ); + + select.innerHTML = fill; + + return( select.options.length ); + } + + var content = ""; + + for( var section in fill ) + { + if( !fill[section] || fill[section] === "" ) + continue; + + var entry = entryTag( section ); + + content += entry.outerHTML; + content += fill[section]; + } + + return fillContentSelect( content, selectId ); +} + + +function entryTag( label, select ) +{ + var line = '-------------------'; + + var option = new Option( line + ' ' + get_lang(label) + ' ' + line + ' ', -1 ); + option.disabled = true; + + if( typeof select === "undefined" ) + return( option ); + + if( typeof select === "string" ) + select = Element( select ).options; + + if( select.options ) + select = select.options; + + select[select.length] = option; +} + +function fillGroupableSelect( fill, selectId, groupHandler, field ) +{ + var groups = {}; + + var select = Element( selectId ).options; + + var sizeof = select.length = 0; + + for( value in fill ) + { + var target = fill[value]; + + var group = groupHandler( target ); + + if( !groups[ group ] ) + groups[ group ] = {}; + + groups[ group ][ value ] = target; + + sizeof++; + } + + for( groupId in groups ) + { + var group = groups[ groupId ]; + + entryTag( groupId, select ); + + select = setOptions( group, select, field ); + } + + return( sizeof ); +} + +function flipParser( data ) +{ + var result = {}; + + for( var section in data ) + { + var target = data[section]; + + for ( var key in target ) + { + if( !result[key] ) + result[key] = {}; + + result[key][section] = target[key]; + } + } + + return( result ); +} + +function stackParser( data, field ) +{ + if( !data ) return( false ); + + for( var section in data ) + data[section] = normalize( data[section], field ); + + return( data ); +} + +function bypassParser( x ){ + return( x ); +} + +var userData = {}; + +function lookup( matchers, fillHandler, url, parser, callback ) +{ + var serverCallback = false; + + if( url ) + { + //handler chamado pelo callback do servidor para repopular. + serverCallback = function( filters, handler ){ + + var refill = function( userd, data ){ + + //no caso de existir um custom callback + if( callback ) + if( !callback( data, userd ) ) + return; + + //filter( filters, handler ); + + }; + + search( url, refill, parser ); + }; + } + + serverCallback( matchers, fillHandler, serverCallback ); +} + +function filter( filters, fillHandler, emptinessHandler ) +{ + filters = normalize( filters ); + + var fill = {}; + + //varrer todas as sentencas e secoes especificas + for( key in userData ) + { + var user = userData[key]; + + if( !user ) continue; + + var filtered = false; + + //populando o mapa filtrando pela determinada sentenca + for( section in filters ) + { + if( filtered ) break; + + //filtro para a secao especifica. + var criteria = filters[section]; + + var target = user[section] || user; + + if( !criteria( target ) ) + filtered = true; + } + + if( !filtered ) + fill[key] = user; + } + + //tenta chamar o handler para popular, caso nao consiga chama o server side + if( fillHandler ) + if( !fillHandler( fill ) && emptinessHandler ) + return emptinessHandler( filters, fillHandler ); + + return( fill ); +} + +function search( url, callback, parser ) +{ + var handler = function( data ) + { + if( !cExecute ) + data = unserialize( data ); + + var dt = false; + + if( typeof data == "string" && data.charAt(0) === '{' ) + { + try{ + dt = data; + data = (new Function("return " + data))(); + } + catch(e){ + } + } + +// if( data && typeof data !== "string" && data.nosession ) +// window.location.reload( false ); + + if( parser ) + data = parser( data, dt ); + + if( callback ) + callback( userData, data ); + } + + if( typeof url === "function" ) + url = url(); + + if( typeof cExecute !== "undefined" ) + return cExecute( url, handler ); + + return this.Connector.newRequest( 'search', url, 'GET', handler ); +} + +function normalize( raw, field ) +{ + if( raw instanceof RegExp ) + { + var exp = raw; + + raw = function( match ){ + return exp.test( match ); + } + } + + if( typeof field !== "undefined" && raw !== "object" ) + { + var content = raw; + + raw = {}; + + raw[field] = content; + } + + if( typeof raw === "object" ) + for( var key in raw ) + raw[key] = normalize( raw[key] ); + + return( raw ); +} Index: /sandbox/2.2.0.2/expressoAdmin1_2/templates/default/body_email.tpl =================================================================== --- /sandbox/2.2.0.2/expressoAdmin1_2/templates/default/body_email.tpl (revision 4445) +++ /sandbox/2.2.0.2/expressoAdmin1_2/templates/default/body_email.tpl (revision 4445) @@ -0,0 +1,17 @@ + +
+ + + +{lang_Your_user_was_add/updated_in_the_shared_account} {shared_account}
+{lang_Your_user_has_the_following_acl}:
+{acl} |