\ No newline at end of file
Index: trunk/core/kernel/parser/construct_tags.php
===================================================================
diff -u -N
--- trunk/core/kernel/parser/construct_tags.php (revision 0)
+++ trunk/core/kernel/parser/construct_tags.php (revision 1560)
@@ -0,0 +1,260 @@
+StopTag = $tag;
+ }
+
+ function StoreSkipMode()
+ {
+ $this->SkipMode = $this->Parser->SkipMode;
+ }
+
+ function RestoreSkipMode()
+ {
+ $this->Parser->SetSkipMode($this->SkipMode);
+ }
+
+ function RestoreThisLevelSkipMode()
+ {
+ $this->SkipMode = $this->Parser->Recursion[$this->Parser->RecursionIndex]->SkipMode;
+ }
+
+ function SuggestSkipMode($mode)
+ {
+ if ($mode >= 1) //if we need to skip - always forcing it
+ $this->Parser->SetSkipMode($mode);
+ else { //if we need to turn of skipping
+ if ($this->SkipMode == parse) //check if initially skipping was off
+ $this->Parser->SetSkipMode(parse); //set it to off only then
+ }
+ }
+
+ function GetLogic()
+ {
+ $check = $this->GetParam('check');
+ if ($check) {
+ if (strpos($check, '_') !== false) {
+ list($prefix, $function) = explode('_', $check, 2);
+ }
+ else {
+ $function = $check;
+ $prefix = $this->Parser->GetParam('PrefixSpecial');
+ }
+ }
+ else {
+ $prefix = $this->GetParam('prefix');
+ $function = $this->GetParam('function');
+ }
+ $this->NP['prefix'] = $prefix;
+ $this->NP['function'] = $function;
+
+ $inverse = $this->GetParam('inverse');
+
+ if ($prefix !== false) {
+ $tag =& new Tag('', $this->Parser);
+ $tag->Tag = $function;
+
+ $tmp = $this->Application->processPrefix($prefix);
+ $tag->Processor = $tmp['prefix'];
+
+ $tag->Prefix=$tmp['prefix'];
+ $tag->Special=$tmp['special'];
+ $tag->NamedParams = $this->NP;
+ $this->Logic = $tag->DoProcessTag();
+ // echo " this->Logic : ".$this->Logic."
";
+ }
+ else
+ {
+ $this->Logic = $function;
+ }
+ if($inverse) $this->Logic = !$this->Logic;
+ }
+
+ function Process()
+ {
+ switch ($this->Tag) {
+ case 'if':
+ case 'ifnot':
+ $this->GetLogic();
+
+ $this->SetStopTag('endif'); //This recursion level should end when 'endif' is found
+ $this->Parser->Recurve($this); //Saving current tag in parser recursion array
+ $this->StoreSkipMode(); //Storing initial SkipMode
+
+ if ($this->Logic) {
+ $this->SuggestSkipMode(parse); //suggest we parse it
+ }
+ else {
+ $this->SuggestSkipMode(skip); //suggest we don't parse it
+ }
+ break;
+ case 'elseif':
+ $if_logic = $this->Parser->Recursion[$this->Parser->RecursionIndex]->Logic;
+ if (!$if_logic) { //if IF or ELSEIF above have not worked
+ $this->GetLogic();
+
+ if ($this->Logic) { //ELSEIF should run
+ $this->Parser->Recursion[$this->Parser->RecursionIndex]->Logic = $this->Logic; //To escape running ELSE or ELSEIF below
+ $this->SuggestSkipMode(parse);
+ }
+ else { //ELSEIF should NOT run
+ $this->SuggestSkipMode(skip);
+ }
+ }
+ else //IF or ELSEIF above HAVE worked - this ELSEIF should NOT run
+ $this->SuggestSkipMode(skip);
+ break;
+ case 'else':
+ $if_logic = $this->Parser->Recursion[$this->Parser->RecursionIndex]->Logic;
+ $this->RestoreThisLevelSkipMode();
+ if (!$if_logic) { //IF was false - ELSE should run
+ $this->SuggestSkipMode(parse);
+ }
+ else { //IF was true - ELSE should not run
+ $this->SuggestSkipMode(skip);
+ }
+ break;
+ }
+ }
+
+ function CheckRecursion(&$tag)
+ {
+ if ($this->CheckEndRecursion($tag)) {
+ if (defined('EXPERIMENTAL_PRE_PARSE')) {
+ if ($tag->Tag == 'if' || $tag->Tag == 'endif') {
+ $this->Parser->AppendCompiledCode('}');
+ $this->Parser->ResetCode();
+ }
+ }
+ $this->RestoreSkipMode(); //Restoring original SkipMode
+ return true;
+ }
+ else {
+ if (defined('EXPERIMENTAL_PRE_PARSE')) {
+ $this->Parser->AppendCode($tag->GetCode());
+// $this->Parser->AppendCompiledCode( $tag->GetCode() );
+ }
+ }
+ return false;
+ }
+
+ function CheckEndRecursion(&$tag)
+ {
+ if ($tag->GetParam('_closing_tag_') == 1 && $tag->Tag == $this->Tag) {
+ return true;
+ }
+ return ($tag->Tag == $this->StopTag); //Tag matches StopTag we are waiting for to close current recursion
+ }
+}
+
+class BlockTag extends ConstructTag {
+ var $BlockName = '';
+ var $InsideBlock = 0;
+
+ function Process()
+ {
+ switch ($this->Tag) {
+ case 'block':
+ case 'DefineElement':
+ if ($this->Tag == 'DefineElement') {
+ $this->SetStopTag('end_define'); //This recursion level should end when 'blockend' is found
+ }
+ else {
+ $this->SetStopTag('blockend'); //This recursion level should end when 'blockend' is found
+ }
+ $this->Parser->Recurve($this); //Saving current tag in parser recursion array
+ $this->Parser->SetBuffer('');
+ $this->BlockName = $this->NP['name']; //Stroing BlockName
+ if (isset($this->NP['args']) ) {
+ $this->Parser->Args = explode(',', $this->NP['args']);
+ }
+ $this->StoreSkipMode();
+ $this->SuggestSkipMode(skip_tags); //We need to skip tags from now
+ break;
+ }
+ }
+
+ function CheckRecursion(&$tag)
+ {
+ if (parent::CheckRecursion($tag)) { //if endtag matches (SkipMode would be restored then)
+ //Creating template from buffer
+
+ //if (defined('EXPERIMENTAL_PRE_PARSE') && isset($this->Application->PreParsedBlocks[$this->BlockName])) return true;
+
+ $template = new Template();
+ $template->SetBody($this->Parser->GetBuffer());
+
+ $templates_cache =& $this->Application->recallObject('TemplatesCache');
+
+ //Adding template to application' cache
+ $templates_cache->SetTemplate($this->BlockName, $template, $this->Parser->TemplateName);
+
+ if (defined('EXPERIMENTAL_PRE_PARSE')) {
+ $code = $this->Parser->GetCode();
+ array_unshift($code, '$o = \'\';');
+ array_unshift($code, '$application =& kApplication::Instance();');
+ array_unshift($code, 'extract($params);');
+
+ $code[] = 'return $o;';
+
+ global $debugger;
+
+ $dbg_functions = $this->Application->isDebugMode() && dbg_ConstOn('DBG_PRINT_PREPARSED');
+
+ $f_body = '';
+ //echo "";
+ $l = 0;
+ if ($dbg_functions) echo "function ".$this->BlockName." {
";
+ foreach ($code as $line) {
+ $l++;
+ if ($dbg_functions) {
+ echo $l.' '.$debugger->highlightString(trim($line)."\n", true);
+ }
+ $f_body .= "\t\t".rtrim($line, "\n")."\n";
+ }
+ if ($dbg_functions) echo "} // function ".$this->BlockName." end
";
+ //echo "
";
+
+ //caching func body
+ $this->Application->PreParsedCache[$this->BlockName] = $f_body;
+
+ $func = create_function('$params', $f_body);
+ $this->Application->PreParsedBlocks[$this->BlockName] = $func;
+ $this->Parser->Args = null;
+ $this->Parser->ResetCode();
+
+ $this->Parser->AppendCompiledFunction($this->BlockName, $f_body);
+ }
+ return true;
+ }
+ else {
+ // append the tag itself to the block - while in block, we check every tag to be 'blockend'
+ // if it is not - we need to append the tag to the buffer, which we'll parse later in 'parse_block'
+ if ($tag->Tag != 'block') {
+ if (defined('EXPERIMENTAL_PRE_PARSE') && isset($this->Application->PreParsedBlocks[$this->BlockName])) {
+ return;
+ }
+ if (defined('EXPERIMENTAL_PRE_PARSE')) {
+ // $this->Parser->AppendCode($tag->GetCode());
+ }
+ else {
+ $this->Parser->AppendOutput($tag->GetFullTag());
+ }
+ }
+ return false;
+ }
+ }
+}
+
+?>
\ No newline at end of file
Index: trunk/core/kernel/utility/smtp_client.php
===================================================================
diff -u -N
--- trunk/core/kernel/utility/smtp_client.php (revision 0)
+++ trunk/core/kernel/utility/smtp_client.php (revision 1560)
@@ -0,0 +1,829 @@
+
+ ** pass - Password for authentication Default:
+ ** timeout - The timeout in seconds for the call Default: 5
+ ** to fsockopen()
+ ***************************************/
+
+ function kSmtpClient($params = array()){
+
+ $this->timeout = 5;
+ $this->status = SMTP_STATUS_NOT_CONNECTED;
+ $this->host = 'localhost';
+ $this->port = 25;
+ $this->helo = 'localhost';
+ $this->auth = FALSE;
+ $this->user = '';
+ $this->pass = '';
+ $this->errors = array();
+ $this->buffer = array();
+ $this->debug=0;
+ foreach($params as $key => $value){
+ $this->$key = $value;
+ }
+ }
+
+ /***************************************
+ ** Connect function. This will, when called
+ ** statically, create a new smtp object,
+ ** call the connect function (ie this function)
+ ** and return it. When not called statically,
+ ** it will connect to the server and send
+ ** the HELO command.
+ ***************************************/
+
+ function connect($params = array()){
+
+ if(!isset($this->status))
+ {
+ $obj = new kSmtpClient($params);
+ if($obj->connect()){
+ $obj->status = SMTP_STATUS_CONNECTED;
+ }
+
+ return $obj;
+
+ }
+ else
+ {
+ foreach($params as $key => $value){
+ $this->$key = $value;
+ }
+ $this->connection = @fsockopen($this->host, $this->port, $errno, $errstr, $this->timeout);
+ if(is_resource($this->connection))
+ {
+ socket_set_timeout($this->connection, 0, 250000);
+ socket_set_blocking($this->connection,TRUE);
+ $greeting = $this->get_data();
+ $this->status = SMTP_STATUS_CONNECTED;
+ return $this->auth ? $this->ehlo() : $this->helo();
+ }
+ else
+ {
+ $this->errors[] = 'Failed to connect to server: '.$errstr;
+ return FALSE;
+ }
+ }
+ }
+
+ function disconnect()
+ {
+ if(is_resource($this->connection))
+ fclose($this->connection);
+ unset($this->connection);
+ $this->status=SMTP_STATUS_NOT_CONNECTED;
+ }
+ /***************************************
+ ** Function which handles sending the mail.
+ ** Arguments:
+ ** $params - Optional assoc array of parameters.
+ ** Can contain:
+ ** recipients - Indexed array of recipients
+ ** from - The from address. (used in MAIL FROM:),
+ ** this will be the return path
+ ** headers - Indexed array of headers, one header per array entry
+ ** body - The body of the email
+ ** It can also contain any of the parameters from the connect()
+ ** function
+ ***************************************/
+
+ function send($params = array()){
+
+ foreach($params as $key => $value){
+ $this->set($key, $value);
+ }
+ if($this->is_connected()){
+
+ // Do we auth or not? Note the distinction between the auth variable and auth() function
+ if($this->auth){
+ if(!$this->auth())
+ return FALSE;
+ }
+ $this->mail($this->from);
+ if(is_array($this->recipients))
+ foreach($this->recipients as $value)
+ $this->rcpt($value);
+ else
+ $this->rcpt($this->recipients);
+
+ if(!$this->data())
+ return FALSE;
+
+ // Transparency
+ $headers = str_replace($this->CRLF.'.', $this->CRLF.'..', trim(implode($this->CRLF, $this->headers)));
+ $body = str_replace($this->CRLF.'.', $this->CRLF.'..', $this->body);
+ $body = $body[0] == '.' ? '.'.$body : $body;
+
+ $this->send_data($headers);
+ $this->send_data('');
+ $this->send_data($body);
+ $this->send_data($this->CRLF.".");
+
+ return (substr(trim($this->get_data()), 0, 3) === '250');
+ }else{
+ $this->errors[] = 'Not connected!';
+ return FALSE;
+ }
+ }
+
+ /***************************************
+ ** Function to implement HELO cmd
+ ***************************************/
+
+ function helo(){
+ if(is_resource($this->connection)
+ AND $this->send_data('HELO '.$this->helo)
+ AND substr(trim($error = $this->get_data()), 0, 3) === '250' ){
+
+ return TRUE;
+
+ }else{
+ $this->errors[] = 'HELO command failed, output: ' . trim(substr(trim($error),3));
+ return FALSE;
+ }
+ }
+
+ /***************************************
+ ** Function to implement EHLO cmd
+ ***************************************/
+
+ function ehlo()
+ {
+ $ret_status=is_resource($this->connection) AND $this->send_data('EHLO '.$this->helo);
+ $success=$this->_parseResponse(250);
+ if(!$ret_status && $success !== true)
+ {
+ $this->errors[] = 'EHLO command failed, output: ' . trim(substr(trim($error),3));
+ return FALSE;
+ }
+
+ foreach ($this->_arguments as $argument) {
+ $verb = strtok($argument, ' ');
+ $arguments = substr($argument, strlen($verb) + 1,
+ strlen($argument) - strlen($verb) - 1);
+ $this->_esmtp[$verb] = $arguments;
+ }
+
+ return TRUE;
+
+
+ }
+
+ /***************************************
+ ** Function to implement AUTH cmd
+ ***************************************/
+
+ function _getBestAuthMethod()
+ {
+ if ($this->authmethod) return $this->authmethod;
+
+ if (!isset($this->_esmtp['AUTH'])) return 'NOAUTH';
+
+ $available_methods = explode(' ', $this->_esmtp['AUTH']);
+
+
+
+ foreach ($this->auth_methods as $method)
+ {
+ if (in_array($method, $available_methods)) return $method;
+ }
+ return false;
+ }
+
+
+ function auth(){
+ if(is_resource($this->connection))
+ {
+ $method=$this->_getBestAuthMethod();
+
+ if ($method == 'NOAUTH') return true;
+
+ switch ($method) {
+ case 'DIGEST-MD5':
+ $result = $this->_authDigest_MD5($this->user, $this->pass);
+ break;
+ case 'CRAM-MD5':
+ $result = $this->_authCRAM_MD5($this->user, $this->pass);
+ break;
+ case 'LOGIN':
+ $result = $this->_authLogin($this->user, $this->pass);
+ break;
+ case 'PLAIN':
+ $result = $this->_authPlain($this->user, $this->pass);
+ break;
+ default:
+ $this->errors[] = 'AUTH command failed: no supported authentication methods';
+ return false;
+ break;
+ }
+ if($result!==true)
+ {
+ $this->errors[] = 'AUTH command failed: '.$result;
+ return FALSE;
+ }
+ return true;
+
+ }else{
+ $this->errors[] = 'AUTH command failed: ' . trim(substr(trim($error),3));
+ return FALSE;
+ }
+ }
+
+// ============= AUTH METHODS: BEGIN ==========================
+/**
+ * Authenticates the user using the DIGEST-MD5 method.
+ *
+ * @param string The userid to authenticate as.
+ * @param string The password to authenticate with.
+ *
+ * @return mixed Returns a PEAR_Error with an error message on any
+ * kind of failure, or true on success.
+ * @access private
+ * @since 1.1.0
+ */
+ function _authDigest_MD5($uid, $pwd)
+ {
+ $this->send_data('AUTH DIGEST-MD5');
+
+ /* 334: Continue authentication request */
+ if(($error=$this->_parseResponse(334)) !== true)
+ {
+ /* 503: Error: already authenticated */
+ if ($this->_code === 503) {
+ return true;
+ }
+ return $error;
+ }
+
+ $challenge = base64_decode($this->_arguments[0]);
+ $auth_str = base64_encode($this->get_digestMD5Auth($uid, $pwd, $challenge,
+ $this->host, "smtp"));
+
+
+ $this->send_data($auth_str);
+
+ /* 334: Continue authentication request */
+ if(($error=$this->_parseResponse(334)) !== true) return $error;
+
+ /*
+ * We don't use the protocol's third step because SMTP doesn't allow
+ * subsequent authentication, so we just silently ignore it.
+ */
+ $this->send_data(' ');
+
+ /* 235: Authentication successful */
+ if(($error=$this->_parseResponse(235)) !== true) return $error;
+ }
+
+
+ /**
+ * Provides the (main) client response for DIGEST-MD5
+ * requires a few extra parameters than the other
+ * mechanisms, which are unavoidable.
+ *
+ * @param string $authcid Authentication id (username)
+ * @param string $pass Password
+ * @param string $challenge The digest challenge sent by the server
+ * @param string $hostname The hostname of the machine you're connecting to
+ * @param string $service The servicename (eg. imap, pop, acap etc)
+ * @param string $authzid Authorization id (username to proxy as)
+ * @return string The digest response (NOT base64 encoded)
+ * @access public
+ */
+ function get_digestMD5Auth($authcid, $pass, $challenge, $hostname, $service, $authzid = '')
+ {
+ $challenge = $this->_parseChallenge($challenge);
+ $authzid_string = '';
+ if ($authzid != '') {
+ $authzid_string = ',authzid="' . $authzid . '"';
+ }
+
+ if (!empty($challenge)) {
+ $cnonce = $this->_getCnonce();
+ $digest_uri = sprintf('%s/%s', $service, $hostname);
+ $response_value = $this->_getResponseValue($authcid, $pass, $challenge['realm'], $challenge['nonce'], $cnonce, $digest_uri, $authzid);
+
+ return sprintf('username="%s",realm="%s"' . $authzid_string . ',nonce="%s",cnonce="%s",nc="00000001",qop=auth,digest-uri="%s",response=%s,%d', $authcid, $challenge['realm'], $challenge['nonce'], $cnonce, $digest_uri, $response_value, $challenge['maxbuf']);
+ } else {
+ return PEAR::raiseError('Invalid digest challenge');
+ }
+ }
+
+ /**
+ * Parses and verifies the digest challenge*
+ *
+ * @param string $challenge The digest challenge
+ * @return array The parsed challenge as an assoc
+ * array in the form "directive => value".
+ * @access private
+ */
+ function _parseChallenge($challenge)
+ {
+ $tokens = array();
+ while (preg_match('/^([a-z-]+)=("[^"]+(?send_data('AUTH CRAM-MD5');
+
+ /* 334: Continue authentication request */
+ if(($error=$this->_parseResponse(334)) !== true)
+ {
+ /* 503: Error: already authenticated */
+ if ($this->_code === 503) {
+ return true;
+ }
+ return $error;
+ }
+
+ $challenge = base64_decode($this->_arguments[0]);
+ $auth_str = base64_encode($uid . ' ' . $this->_HMAC_MD5($pwd, $challenge));
+
+ $this->send_data($auth_str);
+
+ /* 235: Authentication successful */
+ if ( ($error = $this->_parseResponse(235)) ) {
+ return $error;
+ }
+ }
+
+ /**
+ * Authenticates the user using the LOGIN method.
+ *
+ * @param string The userid to authenticate as.
+ * @param string The password to authenticate with.
+ *
+ * @return mixed Returns a PEAR_Error with an error message on any
+ * kind of failure, or true on success.
+ * @access private
+ * @since 1.1.0
+ */
+ function _authLogin($uid, $pwd)
+ {
+ $this->send_data('AUTH LOGIN');
+
+ /* 334: Continue authentication request */
+ if(($error=$this->_parseResponse(334)) !== true)
+ {
+ /* 503: Error: already authenticated */
+ if ($this->_code === 503) {
+ return true;
+ }
+ return $error;
+ }
+
+ $this->send_data( base64_encode($uid) );
+
+ /* 334: Continue authentication request */
+ if(($error=$this->_parseResponse(334)) !== true) return $error;
+
+ $this->send_data( base64_encode($pwd) );
+
+ /* 235: Authentication successful */
+ if (($error=$this->_parseResponse(235)) !== true) return $error;
+
+ return true;
+ }
+
+ /**
+ * Authenticates the user using the PLAIN method.
+ *
+ * @param string The userid to authenticate as.
+ * @param string The password to authenticate with.
+ *
+ * @return mixed Returns a PEAR_Error with an error message on any
+ * kind of failure, or true on success.
+ * @access private
+ * @since 1.1.0
+ */
+ function _authPlain($uid, $pwd)
+ {
+ $this->send_data('AUTH PLAIN');
+
+ /* 334: Continue authentication request */
+ if(($error=$this->_parseResponse(334)) !== true)
+ {
+ /* 503: Error: already authenticated */
+ if ($this->_code === 503) {
+ return true;
+ }
+ return $error;
+ }
+
+ $auth_str = base64_encode(chr(0) . $uid . chr(0) . $pwd);
+ $this->send_data($auth_str);
+
+ /* 235: Authentication successful */
+ if (($error=$this->_parseResponse(235)) !== true) return $error;
+
+ return true;
+ }
+// ============= AUTH METHODS: END ==========================
+
+ /**
+ * Function which implements HMAC MD5 digest
+ *
+ * @param string $key The secret key
+ * @param string $data The data to protect
+ * @return string The HMAC MD5 digest
+ */
+ function _HMAC_MD5($key, $data)
+ {
+ if (strlen($key) > 64) {
+ $key = pack('H32', md5($key));
+ }
+
+ if (strlen($key) < 64) {
+ $key = str_pad($key, 64, chr(0));
+ }
+
+ $k_ipad = substr($key, 0, 64) ^ str_repeat(chr(0x36), 64);
+ $k_opad = substr($key, 0, 64) ^ str_repeat(chr(0x5C), 64);
+
+ $inner = pack('H32', md5($k_ipad . $data));
+ $digest = md5($k_opad . $inner);
+
+ return $digest;
+ }
+
+
+
+ /**
+ * Read a reply from the SMTP server. The reply consists of a response
+ * code and a response message.
+ *
+ * @param mixed $valid The set of valid response codes. These
+ * may be specified as an array of integer
+ * values or as a single integer value.
+ *
+ * @return mixed True if the server returned a valid response code or
+ * a PEAR_Error object is an error condition is reached.
+ *
+ * @access private
+ * @since 1.1.0
+ *
+ * @see getResponse
+ */
+ function _parseResponse($valid)
+ {
+
+ $this->_code = -1;
+ $this->_arguments = array();
+
+ if(!is_resource($this->connection)) return false;
+
+ while ($line = fgets($this->connection, 512)) {
+ if ($this->debug) {
+ $this->debugtext.= "DEBUG: Recv: $line\n";
+ }
+
+ /* If we receive an empty line, the connection has been closed. */
+ if (empty($line)) {
+ $this->disconnect();
+ return 'Connection was unexpectedly closed';
+ }
+
+ /* Read the code and store the rest in the arguments array. */
+ $code = substr($line, 0, 3);
+ $this->_arguments[] = trim(substr($line, 4));
+
+ /* Check the syntax of the response code. */
+ if (is_numeric($code)) {
+ $this->_code = (int)$code;
+ } else {
+ $this->_code = -1;
+ break;
+ }
+
+ /* If this is not a multiline response, we're done. */
+ if (substr($line, 3, 1) != '-') {
+ break;
+ }
+ }
+
+ /* Compare the server's response code with the valid code. */
+ if (is_int($valid) && ($this->_code === $valid)) {
+ return true;
+ }
+
+ /* If we were given an array of valid response codes, check each one. */
+ if (is_array($valid)) {
+ foreach ($valid as $valid_code) {
+ if ($this->_code === $valid_code) {
+ return true;
+ }
+ }
+ }
+
+ return 'Invalid response code received from server';
+ }
+
+
+ /***************************************
+ ** Function that handles the MAIL FROM: cmd
+ ***************************************/
+
+ function mail($from){
+
+ if($this->is_connected()
+ AND $this->send_data('MAIL FROM:'.$from.'')
+ AND substr(trim($this->get_data()), 0, 2) === '250' ){
+
+ return TRUE;
+
+ }else
+ return FALSE;
+ }
+
+ /***************************************
+ ** Function that handles the RCPT TO: cmd
+ ***************************************/
+
+ function rcpt($to){
+
+ if($this->is_connected()
+ AND $this->send_data('RCPT TO:'.$to.'')
+ AND substr(trim($error = $this->get_data()), 0, 2) === '25' ){
+
+ return TRUE;
+
+ }else{
+ $this->errors[] = trim(substr(trim($error), 3));
+ return FALSE;
+ }
+ }
+
+ /***************************************
+ ** Function that sends the DATA cmd
+ ***************************************/
+
+ function data(){
+
+ if($this->is_connected()
+ AND $this->send_data('DATA')
+ AND substr(trim($error = $this->get_data()), 0, 3) === '354' ){
+
+ return TRUE;
+
+ }else{
+ $this->errors[] = trim(substr(trim($error), 3));
+ return FALSE;
+ }
+ }
+
+ /***************************************
+ ** Function to determine if this object
+ ** is connected to the server or not.
+ ***************************************/
+
+ function is_connected(){
+
+ return (is_resource($this->connection) AND ($this->status === SMTP_STATUS_CONNECTED));
+ }
+
+ /***************************************
+ ** Function to send a bit of data
+ ***************************************/
+
+ function send_data($data){
+
+ if($this->debug)
+ {
+ $this->buffer[] = "SEND: $data\n";
+ }
+ if ($this->debug) {
+ $this->debugtext.= "DEBUG: Send: $data\n";
+ }
+ if(is_resource($this->connection)){
+ return fwrite($this->connection, $data.$this->CRLF, strlen($data)+2);
+ }else
+ return FALSE;
+ }
+
+ function bytes_left($fp)
+ {
+ $status = socket_get_status ($fp);
+ //print_r($status);
+ $bytes = $status["unread_bytes"];
+ return $bytes;
+ }
+
+ /***************************************
+ ** Function to get data.
+ ***************************************/
+ function &get_data(){
+
+ $return = '';
+ $line = '';
+
+ if(is_resource($this->connection))
+ {
+ while(strpos($return, $this->CRLF) === FALSE OR substr($line,3,1) !== ' ')
+ {
+ $line = fgets($this->connection, 512);
+ $return .= $line;
+ }
+ if($this->debug)
+ {
+ $this->buffer[] = "GET: ".$return."\n";
+ }
+ return $return;
+
+ }else
+ return FALSE;
+ }
+
+ /***************************************
+ ** Sets a variable
+ ***************************************/
+
+ function set($var, $value){
+
+ $this->$var = $value;
+ return TRUE;
+ }
+
+
+}
+
+?>
\ No newline at end of file
Index: trunk/core/kernel/utility/event.php
===================================================================
diff -u -N
--- trunk/core/kernel/utility/event.php (revision 0)
+++ trunk/core/kernel/utility/event.php (revision 1560)
@@ -0,0 +1,278 @@
+Init($prefix,$special);
+ $this->Name = getArrayValue($params,'name');
+ }
+ elseif ($params && is_string($params)) {
+ if (preg_match('/([^.:]*)[.]{0,1}([^:]*):(.*)/', $params, $regs)) {
+ $prefix = $regs[1];
+ $special = $regs[2];
+ if($prefix) $this->Init($prefix,$special);
+ $this->Name = $regs[3];
+ }
+ else {
+ trigger_error('Invalid event string '.$params.' should be prefix[.special]:OnEvent ', E_USER_ERROR);
+ }
+ }
+ if (isset($specificParams)) $this->specificParams = $specificParams;
+ }
+
+ function setEventParam($name,$value)
+ {
+ $this->specificParams[$name]=$value;
+ }
+
+ function getEventParam($name)
+ {
+ return getArrayValue($this->specificParams, $name);
+ }
+
+ function getPrefixSpecial($from_submit=false)
+ {
+ $separator=!$from_submit?'.':'_';
+ $ret=$this->Prefix.$separator.$this->Special;
+ return rtrim($ret,$separator);
+ }
+
+ /**
+ * Set's pseudo class that differs from
+ * the one specified in $Prefix
+ *
+ * @param string $appendix
+ * @access public
+ */
+ function setPseudoClass($appendix)
+ {
+ $this->pseudoClass=$this->Prefix.$appendix;
+ }
+
+ function Init($prefix,$special='')
+ {
+ $this->Prefix=$prefix;
+ $this->pseudoClass=$prefix; // default value
+ $this->Special=$special;
+ $this->Prefix_Special = rtrim($this->Prefix.'.'.$this->Special,'.');
+ }
+
+ /**
+ * Returns object used in event
+ *
+ * @access public
+ * @return kDBBase
+ */
+ function &getObject($params=Array())
+ {
+ return $this->Application->recallObject($this->Prefix_Special,$this->pseudoClass,$params);
+ }
+
+ /**
+ * Calls passed event by name in current prefix/special environment
+ * Called event gets this event as MasterEvent,
+ * but its results (status and redirect* properties are copied back to current event)
+ *
+ * @param string $name EventName to call
+ */
+ function CallSubEvent($name)
+ {
+ $child_event = new kEvent();
+ $child_event->MasterEvent =& $this;
+ $child_event->Prefix = $this->Prefix;
+ $child_event->Special = $this->Special;
+ $child_event->Prefix_Special = $this->Prefix_Special;
+ $child_event->redirect = $this->redirect;
+ $child_event->redirect_params = $this->redirect_params;
+ $child_event->redirect_script = $this->redirect_script;
+ $child_event->Name = $name;
+
+ $this->Application->HandleEvent( $child_event );
+
+ $this->status = $child_event->status;
+ $this->redirect = $child_event->redirect;
+ $this->redirect_params = $child_event->redirect_params;
+ $this->redirect_script = $child_event->redirect_script;
+ }
+
+ /**
+ * Set's redirect param for event
+ *
+ * @param string $name
+ * @param string $value
+ * @access public
+ */
+ function SetRedirectParam($name, $value)
+ {
+ $this->redirect_params[$name] = $value;
+ }
+
+ /**
+ * Allows to merge passed redirect params hash with existing ones
+ *
+ * @param Array $params
+ * @access public
+ */
+ function setRedirectParams($params)
+ {
+ $this->redirect_params = array_merge_recursive2($this->redirect_params, $params);
+ }
+
+ /**
+ * Returns Master event name if any
+ *
+ * @return mixed
+ * @access public
+ */
+ function hasMasterEvent()
+ {
+ return is_object($this->MasterEvent) ? $this->MasterEvent->Name : false;
+ }
+
+ }
+
+?>
\ No newline at end of file
Index: trunk/core/kernel/utility/params.php
===================================================================
diff -u -N
--- trunk/core/kernel/utility/params.php (revision 0)
+++ trunk/core/kernel/utility/params.php (revision 1560)
@@ -0,0 +1,139 @@
+SplitParamsStr($params_str);
+ }
+
+ /**
+ * Splits tag params into associative array
+ *
+ * @param string $params_str
+ * @access private
+ */
+ function SplitParamsStr($params_str)
+ {
+ preg_match_all('/([\${}a-zA-Z0-9_.]+)=(["\']{1,1})(.*?)(? $val){
+ $values[$val[1]] = str_replace('\\' . $val[2], $val[2], $val[3]);
+ }
+ $this->AddParams($values);
+ }
+
+ /**
+ * Sets new parameter value
+ *
+ * @param string $name
+ * @param string $val
+ * @access public
+ */
+ function Set($name, $val)
+ {
+ //echo "sessing params: [$name] = [$val] (class: ".get_class($this).")
";
+// $this->_Params[strtolower($name)] = $val;
+ $this->_Params[$name] = $val;
+ }
+
+ /**
+ * Removes parameter
+ *
+ * @param string $name
+ * @access public
+ */
+ function Remove($name)
+ {
+ unset($this->_Params[$name]);
+ }
+
+ /**
+ * Gets parameter value by parameter name
+ *
+ * @param string $name
+ * @param int $mode
+ * @return string
+ * @access public
+ */
+ function Get($name, $mode=FALSE_ON_NULL)
+ {
+ // echo " name : '$name' || mode : $mode
";
+ //$name = strtolower($name);
+ if (array_key_exists($name, $this->_Params))
+ return $this->_Params[$name];
+ else
+ return $mode == FALSE_ON_NULL ? false : '';
+ }
+
+ /**
+ * Mass parameter setting from hash
+ *
+ * @param Array $params
+ * @access public
+ */
+ function AddParams($params)
+ {
+ if (!is_array($params)) return;
+ /*if (count($this->_Params) == 0) {
+ $this->_Params = $params;
+ }
+ else {*/
+ foreach ($params as $name => $val)
+// $this->Set(strtolower($name), $val);
+ $this->Set($name, $val);
+ //}
+ }
+
+ /**
+ * Return all paramters as hash
+ *
+ * @return Array
+ * @access public
+ */
+ function GetParams()
+ {
+ return $this->_Params;
+ }
+}
+
+class kArray extends kBase {
+ var $_Array;
+
+ /**
+ * Returns array value with any deep key
+ *
+ * @return mixed
+ * @todo array_unshift doesn't accept parameters by reference, fix it's usage in this method
+ */
+ function GetArrayValue()
+ {
+ $args = func_get_args();
+ array_unshift($args, &$this->_Array);
+ return call_user_func_array('getArrayValue', $args);
+ }
+
+ function SetArrayValue()
+ {
+ $args = func_get_args();
+ $value = array_pop($args);
+
+ $arr =& $this->_Array;
+ for ($i=0; $i
\ No newline at end of file
Index: trunk/core/kernel/utility/email.php
===================================================================
diff -u -N
--- trunk/core/kernel/utility/email.php (revision 0)
+++ trunk/core/kernel/utility/email.php (revision 1560)
@@ -0,0 +1,412 @@
+TextBoundary = uniqid(time());
+ $this->EmailBoundary = uniqid(time());
+ $this->LineFeed = "\r\n";
+ $this->Charset='ISO-8859-1';
+ $this->TransferEncoding='8bit';
+ $this->Body = '';
+ $this->setHeader('Subject', 'Automatically generated message');
+ $this->HeadersArray=array();
+
+ $this->setHeader('Mime-Version', '1.0');
+ }
+
+ function setHeader($header, $value){
+ $this->HeadersArray[$header] = $value;
+ $this->Compiled = false;
+ }
+
+ function setHeaders($headers){
+ $headers=str_replace("\r", "", $headers);
+ $headers_lines = explode("\n", $headers);
+ foreach ($headers_lines as $line_num => $line){
+ list($header_field, $header_value) = explode(':', $line, 2);
+ $header_value = trim($header_value);
+ $this->setHeader($header_field, $header_value);
+ }
+
+ }
+
+ function appendHeader($header, $value){
+ $this->HeadersArray[$header][] = $value;
+ $this->Compiled = false;
+ }
+
+
+ function setFrom($from, $name=''){
+
+ $this->From = $from;
+
+ if ($name!=''){
+ $from = trim($name).' <'.$from.'>';
+ }
+ $this->setHeader('From', trim($from));
+ }
+
+ function setTo($to, $name=''){
+
+ $this->To = $to;
+
+ if ($name!=''){
+ $to = trim($name).' <'.$to.'>';
+ }
+
+ $this->setHeader('To', trim($to));
+ }
+
+ function setSubject($subj){
+ $this->setHeader('Subject', $subj);
+ }
+
+ function SetCC($to_cc){
+ $this->appendHeader('CC', $to_cc);
+ }
+
+ function SetBCC($to_bcc){
+ $this->appendHeader('BCC', $to_bcc);
+ }
+
+ function setReplyTo($reply_to){
+ $this->setHeader('Reply-to', $reply_to);
+ }
+
+ function setTextBody($body_text){
+
+ $this->BodyText = $body_text;
+ $this->Compiled = false;
+ }
+
+ function setHTMLBody($body_html){
+
+ $this->BodyHtml = $body_html;
+ $this->IsMultipart = true;
+ $this->Compiled = false;
+ }
+
+ function compileBody(){
+ if($this->BodyHtml){
+ $search = array (
+ "'(<\/td>.*)[\r\n]+(.*)|(<\/p>)|(<\/div>)|(<\/tr>)'i",
+ "'(.*?)'si",
+ "' |