Преглед изворни кода

Email sent in asynchronous mode (established the base for an application internal CRON, task queue, etc.) with adjustable configuration (disable by default). Also improved the OQL: IS_NULL() and REGEXP have been added.

git-svn-id: http://svn.code.sf.net/p/itop/code/trunk@1132 a333f486-631f-4898-b8df-5754b55c2be0
romainq пре 14 година
родитељ
комит
6421f721cc

+ 130 - 97
core/action.class.inc.php

@@ -24,6 +24,7 @@
  */
  */
 
 
 
 
+require_once(APPROOT.'/core/asynctask.class.inc.php');
 require_once(APPROOT.'/core/email.class.inc.php');
 require_once(APPROOT.'/core/email.class.inc.php');
 
 
 /**
 /**
@@ -219,120 +220,82 @@ class ActionEmail extends ActionNotification
 
 
 	public function DoExecute($oTrigger, $aContextArgs)
 	public function DoExecute($oTrigger, $aContextArgs)
 	{
 	{
-		$this->m_iRecipients = 0;
-		$this->m_aMailErrors = array();
-		$bRes = false; // until we do succeed in sending the email
-		try
+		if (MetaModel::IsLogEnabledNotification())
 		{
 		{
-			// Determine recicipients
-			//
-			$sTo = $this->FindRecipients('to', $aContextArgs);
-			$sCC = $this->FindRecipients('cc', $aContextArgs);
-			$sBCC = $this->FindRecipients('bcc', $aContextArgs);
-
-			$sFrom = $this->Get('from');
-			$sReplyTo = $this->Get('reply_to');
-	
-			$sSubject = MetaModel::ApplyParams($this->Get('subject'), $aContextArgs);
-			$sBody = MetaModel::ApplyParams($this->Get('body'), $aContextArgs);
-			
-			$oObj = $aContextArgs['this->object()'];
-			$sServerIP = $_SERVER['SERVER_ADDR']; //gethostbyname(gethostname());
-			$sReference = '<iTop/'.get_class($oObj).'/'.$oObj->GetKey().'@'.$sServerIP.'>';
-
-			$oEmail = new EMail();
-
+			$oLog = new EventNotificationEmail();
 			if ($this->IsBeingTested())
 			if ($this->IsBeingTested())
 			{
 			{
-				$oEmail->SetSubject('TEST['.$sSubject.']');
-				$sTestBody = $sBody;
-				$sTestBody .= "<div style=\"border: dashed;\">\n";
-				$sTestBody .= "<h1>Testing email notification ".$this->GetHyperlink()."</h1>\n";
-				$sTestBody .= "<p>The email should be sent with the following properties\n";
-				$sTestBody .= "<ul>\n";
-				$sTestBody .= "<li>TO: $sTo</li>\n";
-				$sTestBody .= "<li>CC: $sCC</li>\n";
-				$sTestBody .= "<li>BCC: $sBCC</li>\n";
-				$sTestBody .= "<li>From: $sFrom</li>\n";
-				$sTestBody .= "<li>Reply-To: $sReplyTo</li>\n";
-				$sTestBody .= "<li>References: $sReference</li>\n";
-				$sTestBody .= "</ul>\n";
-				$sTestBody .= "</p>\n";
-				$sTestBody .= "</div>\n";
-				$oEmail->SetBody($sTestBody);
-				$oEmail->SetRecipientTO($this->Get('test_recipient'));
-				$oEmail->SetRecipientFrom($this->Get('test_recipient'));
-				$oEmail->SetReferences($sReference);
+				$oLog->Set('message', 'TEST - Notification sent ('.$this->Get('test_recipient').')');
 			}
 			}
 			else
 			else
 			{
 			{
-				$oEmail->SetSubject($sSubject);
-				$oEmail->SetBody($sBody);
-				$oEmail->SetRecipientTO($sTo);
-				$oEmail->SetRecipientCC($sCC);
-				$oEmail->SetRecipientBCC($sBCC);
-				$oEmail->SetRecipientFrom($sFrom);
-				$oEmail->SetRecipientReplyTo($sReplyTo);
-				$oEmail->SetReferences($sReference);
-			}
-	
-			if (empty($this->m_aMailErrors))
-			{
-				if ($this->m_iRecipients == 0)
-				{
-					$this->m_aMailErrors[] = 'No recipient';
-				}
-				else
-				{
-					$oKPI = new ExecutionKPI();
-					$this->m_aMailErrors = array_merge($this->m_aMailErrors, $oEmail->Send());
-					$oKPI->ComputeStats('Send mail', $sTo);
-				}
+				$oLog->Set('message', 'Notification pending');
 			}
 			}
+			$oLog->Set('userinfo', UserRights::GetUser());
+			$oLog->Set('trigger_id', $oTrigger->GetKey());
+			$oLog->Set('action_id', $this->GetKey());
+			$oLog->Set('object_id', $aContextArgs['this->object()']->GetKey());
+			// Must be inserted now so that it gets a valid id that will make the link
+			// between an eventual asynchronous task (queued) and the log
+			$oLog->DBInsertNoReload();
 		}
 		}
-		catch (Exception $e)
+		else
 		{
 		{
-			$this->m_aMailErrors[] = $e->getMessage();
+			$oLog = null;
 		}
 		}
 
 
-		if (MetaModel::IsLogEnabledNotification())
+		try
 		{
 		{
-			$oLog = new EventNotificationEmail();
-			if (empty($this->m_aMailErrors))
+			$sRes = $this->_DoExecute($oTrigger, $aContextArgs, $oLog);
+
+			if ($this->IsBeingTested())
 			{
 			{
-				if ($this->IsBeingTested())
-				{
-					$oLog->Set('message', 'TEST - Notification sent ('.$this->Get('test_recipient').')');
-				}
-				else
-				{
-					$oLog->Set('message', 'Notification sent');
-				}
+				$sPrefix = 'TEST ('.$this->Get('test_recipient').') - ';
 			}
 			}
 			else
 			else
 			{
 			{
-				if (is_array($this->m_aMailErrors) && count($this->m_aMailErrors) > 0)
-				{
-					$sError = implode(', ', $this->m_aMailErrors);
-				}
-				else
-				{
-					$sError = 'Unknown reason';
-				}
-				if ($this->IsBeingTested())
-				{
-					$oLog->Set('message', 'TEST - Notification was not sent: '.$sError);
-				}
-				else
-				{
-					$oLog->Set('message', 'Notification was not sent: '.$sError);
-				}
+				$sPrefix = '';
 			}
 			}
-			$oLog->Set('userinfo', UserRights::GetUser());
-			$oLog->Set('trigger_id', $oTrigger->GetKey());
-			$oLog->Set('action_id', $this->GetKey());
-			$oLog->Set('object_id', $aContextArgs['this->object()']->GetKey());
+			$oLog->Set('message', $sPrefix.$sRes);
+
+		}
+		catch (Exception $e)
+		{
+			if ($oLog)
+			{
+				$oLog->Set('message', 'Error: '.$e->getMessage());
+			}
+		}
+		if ($oLog)
+		{
+			$oLog->DBUpdate();
+		}
+	}
+
+	protected function _DoExecute($oTrigger, $aContextArgs, &$oLog)
+	{
+		$this->m_iRecipients = 0;
+		$this->m_aMailErrors = array();
+		$bRes = false; // until we do succeed in sending the email
+
+		// Determine recicipients
+		//
+		$sTo = $this->FindRecipients('to', $aContextArgs);
+		$sCC = $this->FindRecipients('cc', $aContextArgs);
+		$sBCC = $this->FindRecipients('bcc', $aContextArgs);
+
+		$sFrom = $this->Get('from');
+		$sReplyTo = $this->Get('reply_to');
+
+		$sSubject = MetaModel::ApplyParams($this->Get('subject'), $aContextArgs);
+		$sBody = MetaModel::ApplyParams($this->Get('body'), $aContextArgs);
+		
+		$oObj = $aContextArgs['this->object()'];
+		$sServerIP = $_SERVER['SERVER_ADDR']; //gethostbyname(gethostname());
+		$sReference = '<iTop/'.get_class($oObj).'/'.$oObj->GetKey().'@'.$sServerIP.'>';
 
 
+		if (!is_null($oLog))
+		{
 			// Note: we have to secure this because those values are calculated
 			// Note: we have to secure this because those values are calculated
 			// inside the try statement, and we would like to keep track of as
 			// inside the try statement, and we would like to keep track of as
 			// many data as we could while some variables may still be undefined
 			// many data as we could while some variables may still be undefined
@@ -342,7 +305,77 @@ class ActionEmail extends ActionNotification
 			if (isset($sFrom))     $oLog->Set('from', $sFrom);
 			if (isset($sFrom))     $oLog->Set('from', $sFrom);
 			if (isset($sSubject))  $oLog->Set('subject', $sSubject);
 			if (isset($sSubject))  $oLog->Set('subject', $sSubject);
 			if (isset($sBody))     $oLog->Set('body', $sBody);
 			if (isset($sBody))     $oLog->Set('body', $sBody);
-			$oLog->DBInsertNoReload();
+		}
+
+		$oEmail = new EMail();
+
+		if ($this->IsBeingTested())
+		{
+			$oEmail->SetSubject('TEST['.$sSubject.']');
+			$sTestBody = $sBody;
+			$sTestBody .= "<div style=\"border: dashed;\">\n";
+			$sTestBody .= "<h1>Testing email notification ".$this->GetHyperlink()."</h1>\n";
+			$sTestBody .= "<p>The email should be sent with the following properties\n";
+			$sTestBody .= "<ul>\n";
+			$sTestBody .= "<li>TO: $sTo</li>\n";
+			$sTestBody .= "<li>CC: $sCC</li>\n";
+			$sTestBody .= "<li>BCC: $sBCC</li>\n";
+			$sTestBody .= "<li>From: $sFrom</li>\n";
+			$sTestBody .= "<li>Reply-To: $sReplyTo</li>\n";
+			$sTestBody .= "<li>References: $sReference</li>\n";
+			$sTestBody .= "</ul>\n";
+			$sTestBody .= "</p>\n";
+			$sTestBody .= "</div>\n";
+			$oEmail->SetBody($sTestBody);
+			$oEmail->SetRecipientTO($this->Get('test_recipient'));
+			$oEmail->SetRecipientFrom($this->Get('test_recipient'));
+			$oEmail->SetReferences($sReference);
+		}
+		else
+		{
+			$oEmail->SetSubject($sSubject);
+			$oEmail->SetBody($sBody);
+			$oEmail->SetRecipientTO($sTo);
+			$oEmail->SetRecipientCC($sCC);
+			$oEmail->SetRecipientBCC($sBCC);
+			$oEmail->SetRecipientFrom($sFrom);
+			$oEmail->SetRecipientReplyTo($sReplyTo);
+			$oEmail->SetReferences($sReference);
+		}
+
+		if (empty($this->m_aMailErrors))
+		{
+			if ($this->m_iRecipients == 0)
+			{
+				return 'No recipient';
+			}
+			else
+			{
+				$iRes = $oEmail->Send($aErrors, false, $oLog); // allow asynchronous mode
+				switch ($iRes)
+				{
+					case EMAIL_SEND_OK:
+						return "Sent";
+	
+					case EMAIL_SEND_PENDING:
+						return "Pending";
+	
+					case EMAIL_SEND_ERROR:
+						return "Errors: ".implode(', ', $aErrors);
+				}
+			}
+		}
+		else
+		{
+			if (is_array($this->m_aMailErrors) && count($this->m_aMailErrors) > 0)
+			{
+				$sError = implode(', ', $this->m_aMailErrors);
+			}
+			else
+			{
+				$sError = 'Unknown reason';
+			}
+			return 'Notification was not sent: '.$sError;
 		}
 		}
 	}
 	}
 }
 }

+ 1 - 0
core/attributedef.class.inc.php

@@ -63,6 +63,7 @@ define('DEL_MANUAL', 1);
  * @package     iTopORM
  * @package     iTopORM
  */
  */
 define('DEL_AUTO', 2);
 define('DEL_AUTO', 2);
+define('DEL_SILENT', 2);
 
 
 
 
 /**
 /**

+ 2 - 0
core/cmdbobject.class.inc.php

@@ -59,6 +59,8 @@ require_once('dbobject.class.php');
 require_once('dbobjectsearch.class.php');
 require_once('dbobjectsearch.class.php');
 require_once('dbobjectset.class.php');
 require_once('dbobjectset.class.php');
 
 
+require_once('backgroundprocess.inc.php');
+require_once('asynctask.class.inc.php');
 require_once('dbproperty.class.inc.php');
 require_once('dbproperty.class.inc.php');
 
 
 // db change tracking data model
 // db change tracking data model

+ 21 - 1
core/cmdbsource.class.inc.php

@@ -56,7 +56,7 @@ class CMDBSource
 		self::$m_sDBUser = $sUser;
 		self::$m_sDBUser = $sUser;
 		self::$m_sDBPwd = $sPwd;
 		self::$m_sDBPwd = $sPwd;
 		self::$m_sDBName = $sSource;
 		self::$m_sDBName = $sSource;
-		if (!self::$m_resDBLink = @mysql_pconnect($sServer, $sUser, $sPwd))
+		if (!self::$m_resDBLink = @mysql_connect($sServer, $sUser, $sPwd))
 		{
 		{
 			throw new MySQLException('Could not connect to the DB server', array('host'=>$sServer, 'user'=>$sUser));
 			throw new MySQLException('Could not connect to the DB server', array('host'=>$sServer, 'user'=>$sUser));
 		}
 		}
@@ -243,6 +243,26 @@ class CMDBSource
 		return false;
 		return false;
 	}
 	}
 
 
+	public static function QueryToScalar($sSql)
+	{
+		$result = mysql_query($sSql, self::$m_resDBLink);
+		if (!$result)
+		{
+			throw new MySQLException('Failed to issue SQL query', array('query' => $sSql));
+		}
+		if ($aRow = mysql_fetch_array($result, MYSQL_BOTH))
+		{
+			$res = $aRow[0];
+		}
+		else
+		{
+			mysql_free_result($result);
+			throw new MySQLException('Found no result for query', array('query' => $sSql));
+		}
+		mysql_free_result($result);
+		return $res;
+	}
+
 	public static function QueryToArray($sSql)
 	public static function QueryToArray($sSql)
 	{
 	{
 		$aData = array();
 		$aData = array();

+ 24 - 0
core/config.class.inc.php

@@ -253,6 +253,30 @@ class Config
 			'source_of_value' => '',
 			'source_of_value' => '',
 			'show_in_conf_sample' => true,
 			'show_in_conf_sample' => true,
 		),
 		),
+		'cron_max_execution_time' => array(
+			'type' => 'integer',
+			'description' => 'Duration (seconds) of the page cron.php, must be shorter than php setting max_execution_time and shorter than the web server response timeout',
+			'default' => 60,
+			'value' => 60,
+			'source_of_value' => '',
+			'show_in_conf_sample' => true,
+		),
+		'cron_sleep' => array(
+			'type' => 'integer',
+			'description' => 'Duration (seconds) before cron.php checks again if something must be done',
+			'default' => 2,
+			'value' => 2,
+			'source_of_value' => '',
+			'show_in_conf_sample' => false,
+		),
+		'email_asynchronous' => array(
+			'type' => 'bool',
+			'description' => 'If set, the emails are sent off line, which requires cron.php to be activated. Exception: some features like the email test utility will force the serialized mode',
+			'default' => false,
+			'value' => false,
+			'source_of_value' => '',
+			'show_in_conf_sample' => true,
+		),
 	);
 	);
 
 
 	public function IsProperty($sPropCode)
 	public function IsProperty($sPropCode)

+ 55 - 9
core/email.class.inc.php

@@ -24,6 +24,11 @@
  * @license     http://www.opensource.org/licenses/gpl-3.0.html LGPL
  * @license     http://www.opensource.org/licenses/gpl-3.0.html LGPL
  */
  */
 
 
+define ('EMAIL_SEND_OK', 0);
+define ('EMAIL_SEND_PENDING', 1);
+define ('EMAIL_SEND_ERROR', 2);
+
+
 class EMail
 class EMail
 {
 {
 	protected $m_sBody;
 	protected $m_sBody;
@@ -31,15 +36,14 @@ class EMail
 	protected $m_sTo;
 	protected $m_sTo;
 	protected $m_aHeaders; // array of key=>value
 	protected $m_aHeaders; // array of key=>value
 
 
-	public function __construct()
+	public function __construct($sTo = '', $sSubject = '', $sBody = '', $aHeaders = array())
 	{
 	{
-		$this->m_sTo = '';
-		$this->m_sSubject = '';
-		$this->m_sBody = '';
-		$this->m_aHeaders = array();
+		$this->m_sTo = $sTo;
+		$this->m_sSubject = $sSubject;
+		$this->m_sBody = $sBody;
+		$this->m_aHeaders = $aHeaders;
 	}
 	}
 
 
-
 	// Errors management : not that simple because we need that function to be
 	// Errors management : not that simple because we need that function to be
 	// executed in the background, while making sure that any issue would be reported clearly
 	// executed in the background, while making sure that any issue would be reported clearly
 	protected $m_aMailErrors; //array of strings explaining the issues
 	protected $m_aMailErrors; //array of strings explaining the issues
@@ -50,9 +54,22 @@ class EMail
 		$this->m_aMailErrors[] = $sCleanMessage;
 		$this->m_aMailErrors[] = $sCleanMessage;
 	}
 	}
 
 
+  	protected function SendAsynchronous(&$aIssues, $oLog = null)
+	{
+		try
+		{
+			AsyncSendEmail::AddToQueue($this->m_sTo, $this->m_sSubject, $this->m_sBody, $this->m_aHeaders, $oLog);
+		}
+		catch(Exception $e)
+		{
+			$aIssues = array($e->GetMessage());
+			return EMAIL_SEND_ERROR;
+		}
+		$aIssues = array();
+		return EMAIL_SEND_PENDING;
+	}
 
 
-	// returns a list of issues if any
-	public function Send()
+	protected function SendSynchronous(&$aIssues, $oLog = null)
 	{
 	{
 		$sHeaders  = 'MIME-Version: 1.0' . "\r\n";
 		$sHeaders  = 'MIME-Version: 1.0' . "\r\n";
 		// ! the case is important for MS-Outlook
 		// ! the case is important for MS-Outlook
@@ -79,7 +96,36 @@ class EMail
 		{
 		{
 			$this->m_aMailErrors[] = 'Unknown reason';
 			$this->m_aMailErrors[] = 'Unknown reason';
 		}
 		}
-		return $this->m_aMailErrors;
+		if (count($this->m_aMailErrors) > 0)
+		{
+			$aIssues = $this->m_aMailErrors;
+			return EMAIL_SEND_ERROR;
+		}
+		else
+		{
+			$aIssues = array();
+			return EMAIL_SEND_OK;
+		}
+	}
+
+	public function Send(&$aIssues, $bForceSynchronous = false, $oLog = null)
+	{	
+		if ($bForceSynchronous)
+		{
+			return $this->SendSynchronous($aIssues, $oLog);
+		}
+		else
+		{
+			$bConfigASYNC = MetaModel::GetConfig()->Get('email_asynchronous');
+			if ($bConfigASYNC)
+			{
+				return $this->SendAsynchronous($aIssues, $oLog);
+			}
+			else
+			{
+				return $this->SendSynchronous($aIssues, $oLog);
+			}
+		}
 	}
 	}
 
 
 	protected function AddToHeader($sKey, $sValue)
 	protected function AddToHeader($sKey, $sValue)

+ 68 - 5
core/event.class.inc.php

@@ -25,7 +25,7 @@
  * @license     http://www.opensource.org/licenses/gpl-3.0.html LGPL
  * @license     http://www.opensource.org/licenses/gpl-3.0.html LGPL
  */
  */
 
 
-class Event extends cmdbAbstractObject
+class Event extends DBObject implements iDisplay
 {
 {
 	public static function Init()
 	public static function Init()
 	{
 	{
@@ -46,14 +46,77 @@ class Event extends cmdbAbstractObject
 		MetaModel::Init_AddAttribute(new AttributeText("message", array("allowed_values"=>null, "sql"=>"message", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
 		MetaModel::Init_AddAttribute(new AttributeText("message", array("allowed_values"=>null, "sql"=>"message", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
 		MetaModel::Init_AddAttribute(new AttributeDateTime("date", array("allowed_values"=>null, "sql"=>"date", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
 		MetaModel::Init_AddAttribute(new AttributeDateTime("date", array("allowed_values"=>null, "sql"=>"date", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
 		MetaModel::Init_AddAttribute(new AttributeString("userinfo", array("allowed_values"=>null, "sql"=>"userinfo", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
 		MetaModel::Init_AddAttribute(new AttributeString("userinfo", array("allowed_values"=>null, "sql"=>"userinfo", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
+//		MetaModel::Init_AddAttribute(new AttributeString("userinfo", array("allowed_values"=>null, "sql"=>"userinfo", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
 
 
 		// Display lists
 		// Display lists
-		MetaModel::Init_SetZListItems('details', array('message', 'date', 'userinfo')); // Attributes to be displayed for the complete details
+		MetaModel::Init_SetZListItems('details', array('date', 'message', 'userinfo')); // Attributes to be displayed for the complete details
 		MetaModel::Init_SetZListItems('list', array('date', 'finalclass', 'message')); // Attributes to be displayed for a list
 		MetaModel::Init_SetZListItems('list', array('date', 'finalclass', 'message')); // Attributes to be displayed for a list
 		// Search criteria
 		// Search criteria
 //		MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
 //		MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
 //		MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
 //		MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
 	}
 	}
+
+	/**
+	 * Maps the given context parameter name to the appropriate filter/search code for this class
+	 * @param string $sContextParam Name of the context parameter, i.e. 'org_id'
+	 * @return string Filter code, i.e. 'customer_id'
+	 */
+	public static function MapContextParam($sContextParam)
+	{
+		if ($sContextParam == 'menu')
+		{
+			return null;
+		}
+		else
+		{
+			return $sContextParam;
+		}
+	}
+
+	/**
+	 * This function returns a 'hilight' CSS class, used to hilight a given row in a table
+	 * There are currently (i.e defined in the CSS) 4 possible values HILIGHT_CLASS_CRITICAL,
+	 * HILIGHT_CLASS_WARNING, HILIGHT_CLASS_OK, HILIGHT_CLASS_NONE
+	 * To Be overridden by derived classes
+	 * @param void
+	 * @return String The desired higlight class for the object/row
+	 */
+	public function GetHilightClass()
+	{
+		// Possible return values are:
+		// HILIGHT_CLASS_CRITICAL, HILIGHT_CLASS_WARNING, HILIGHT_CLASS_OK, HILIGHT_CLASS_NONE	
+		return HILIGHT_CLASS_NONE; // Not hilighted by default
+	}
+
+	public static function GetUIPage()
+	{
+		return '../pages/UI.php';
+	}
+
+	function DisplayDetails(WebPage $oPage, $bEditMode = false)
+	{
+		// Object's details
+		//$this->DisplayBareHeader($oPage, $bEditMode);
+		$oPage->AddTabContainer(OBJECT_PROPERTIES_TAB);
+		$oPage->SetCurrentTabContainer(OBJECT_PROPERTIES_TAB);
+		$oPage->SetCurrentTab(Dict::S('UI:PropertiesTab'));
+		$this->DisplayBareProperties($oPage, $bEditMode);
+	}
+	
+	function DisplayBareProperties(WebPage $oPage, $bEditMode = false)
+	{
+		if ($bEditMode) return; // Not editable
+		
+		$aDetails = array();
+		$sClass = get_class($this);
+		$aZList = MetaModel::FlattenZlist(MetaModel::GetZListItems($sClass, 'details'));
+		foreach( $aZList as $sAttCode)
+		{
+			$sDisplayValue = $this->GetAsHTML($sAttCode);	
+			$aDetails[] = array('label' => '<span title="'.MetaModel::GetDescription($sClass, $sAttCode).'">'.MetaModel::GetLabel($sClass, $sAttCode).'</span>', 'value' => $sDisplayValue);
+		}
+		$oPage->Details($aDetails);
+	}
 }
 }
 
 
 class EventNotification extends Event
 class EventNotification extends Event
@@ -79,8 +142,8 @@ class EventNotification extends Event
 		MetaModel::Init_AddAttribute(new AttributeInteger("object_id", array("allowed_values"=>null, "sql"=>"object_id", "default_value"=>0, "is_null_allowed"=>false, "depends_on"=>array())));
 		MetaModel::Init_AddAttribute(new AttributeInteger("object_id", array("allowed_values"=>null, "sql"=>"object_id", "default_value"=>0, "is_null_allowed"=>false, "depends_on"=>array())));
 
 
 		// Display lists
 		// Display lists
-		MetaModel::Init_SetZListItems('details', array('date', 'userinfo', 'trigger_id', 'action_id', 'object_id')); // Attributes to be displayed for the complete details
-		MetaModel::Init_SetZListItems('list', array('date', 'userinfo')); // Attributes to be displayed for a list
+		MetaModel::Init_SetZListItems('details', array('date', 'message', 'userinfo', 'trigger_id', 'action_id', 'object_id')); // Attributes to be displayed for the complete details
+		MetaModel::Init_SetZListItems('list', array('date', 'message')); // Attributes to be displayed for a list
 		// Search criteria
 		// Search criteria
 //		MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
 //		MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
 //		MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
 //		MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
@@ -115,7 +178,7 @@ class EventNotificationEmail extends EventNotification
 
 
 		// Display lists
 		// Display lists
 		MetaModel::Init_SetZListItems('details', array('date', 'userinfo', 'message', 'trigger_id', 'action_id', 'object_id', 'to', 'cc', 'bcc', 'from', 'subject', 'body')); // Attributes to be displayed for the complete details
 		MetaModel::Init_SetZListItems('details', array('date', 'userinfo', 'message', 'trigger_id', 'action_id', 'object_id', 'to', 'cc', 'bcc', 'from', 'subject', 'body')); // Attributes to be displayed for the complete details
-		MetaModel::Init_SetZListItems('list', array('date', 'userinfo', 'message', 'to', 'subject')); // Attributes to be displayed for a list
+		MetaModel::Init_SetZListItems('list', array('date', 'message', 'to', 'subject')); // Attributes to be displayed for a list
 
 
 		// Search criteria
 		// Search criteria
 //		MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
 //		MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form

+ 52 - 40
core/oql/oql-lexer.php

@@ -122,6 +122,7 @@ class OQLLexerRaw
     			'/^,/',
     			'/^,/',
     			'/^\\(/',
     			'/^\\(/',
     			'/^\\)/',
     			'/^\\)/',
+    			'/^REGEXP/',
     			'/^=/',
     			'/^=/',
     			'/^!=/',
     			'/^!=/',
     			'/^>/',
     			'/^>/',
@@ -136,6 +137,7 @@ class OQLLexerRaw
     			'/^IF/',
     			'/^IF/',
     			'/^ELT/',
     			'/^ELT/',
     			'/^COALESCE/',
     			'/^COALESCE/',
+    			'/^ISNULL/',
     			'/^CONCAT/',
     			'/^CONCAT/',
     			'/^SUBSTR/',
     			'/^SUBSTR/',
     			'/^TRIM/',
     			'/^TRIM/',
@@ -338,206 +340,216 @@ class OQLLexerRaw
     function yy_r1_16($yy_subpatterns)
     function yy_r1_16($yy_subpatterns)
     {
     {
 
 
-	$this->token = OQLParser::EQ;
+	$this->token = OQLParser::REGEXP;
     }
     }
     function yy_r1_17($yy_subpatterns)
     function yy_r1_17($yy_subpatterns)
     {
     {
 
 
-	$this->token = OQLParser::NOT_EQ;
+	$this->token = OQLParser::EQ;
     }
     }
     function yy_r1_18($yy_subpatterns)
     function yy_r1_18($yy_subpatterns)
     {
     {
 
 
-	$this->token = OQLParser::GT;
+	$this->token = OQLParser::NOT_EQ;
     }
     }
     function yy_r1_19($yy_subpatterns)
     function yy_r1_19($yy_subpatterns)
     {
     {
 
 
-	$this->token = OQLParser::LT;
+	$this->token = OQLParser::GT;
     }
     }
     function yy_r1_20($yy_subpatterns)
     function yy_r1_20($yy_subpatterns)
     {
     {
 
 
-	$this->token = OQLParser::GE;
+	$this->token = OQLParser::LT;
     }
     }
     function yy_r1_21($yy_subpatterns)
     function yy_r1_21($yy_subpatterns)
     {
     {
 
 
-	$this->token = OQLParser::LE;
+	$this->token = OQLParser::GE;
     }
     }
     function yy_r1_22($yy_subpatterns)
     function yy_r1_22($yy_subpatterns)
     {
     {
 
 
-	$this->token = OQLParser::LIKE;
+	$this->token = OQLParser::LE;
     }
     }
     function yy_r1_23($yy_subpatterns)
     function yy_r1_23($yy_subpatterns)
     {
     {
 
 
-	$this->token = OQLParser::NOT_LIKE;
+	$this->token = OQLParser::LIKE;
     }
     }
     function yy_r1_24($yy_subpatterns)
     function yy_r1_24($yy_subpatterns)
     {
     {
 
 
-	$this->token = OQLParser::IN;
+	$this->token = OQLParser::NOT_LIKE;
     }
     }
     function yy_r1_25($yy_subpatterns)
     function yy_r1_25($yy_subpatterns)
     {
     {
 
 
-	$this->token = OQLParser::NOT_IN;
+	$this->token = OQLParser::IN;
     }
     }
     function yy_r1_26($yy_subpatterns)
     function yy_r1_26($yy_subpatterns)
     {
     {
 
 
-	$this->token = OQLParser::INTERVAL;
+	$this->token = OQLParser::NOT_IN;
     }
     }
     function yy_r1_27($yy_subpatterns)
     function yy_r1_27($yy_subpatterns)
     {
     {
 
 
-	$this->token = OQLParser::F_IF;
+	$this->token = OQLParser::INTERVAL;
     }
     }
     function yy_r1_28($yy_subpatterns)
     function yy_r1_28($yy_subpatterns)
     {
     {
 
 
-	$this->token = OQLParser::F_ELT;
+	$this->token = OQLParser::F_IF;
     }
     }
     function yy_r1_29($yy_subpatterns)
     function yy_r1_29($yy_subpatterns)
     {
     {
 
 
-	$this->token = OQLParser::F_COALESCE;
+	$this->token = OQLParser::F_ELT;
     }
     }
     function yy_r1_30($yy_subpatterns)
     function yy_r1_30($yy_subpatterns)
     {
     {
 
 
-	$this->token = OQLParser::F_CONCAT;
+	$this->token = OQLParser::F_COALESCE;
     }
     }
     function yy_r1_31($yy_subpatterns)
     function yy_r1_31($yy_subpatterns)
     {
     {
 
 
-	$this->token = OQLParser::F_SUBSTR;
+	$this->token = OQLParser::F_ISNULL;
     }
     }
     function yy_r1_32($yy_subpatterns)
     function yy_r1_32($yy_subpatterns)
     {
     {
 
 
-	$this->token = OQLParser::F_TRIM;
+	$this->token = OQLParser::F_CONCAT;
     }
     }
     function yy_r1_33($yy_subpatterns)
     function yy_r1_33($yy_subpatterns)
     {
     {
 
 
-	$this->token = OQLParser::F_DATE;
+	$this->token = OQLParser::F_SUBSTR;
     }
     }
     function yy_r1_34($yy_subpatterns)
     function yy_r1_34($yy_subpatterns)
     {
     {
 
 
-	$this->token = OQLParser::F_DATE_FORMAT;
+	$this->token = OQLParser::F_TRIM;
     }
     }
     function yy_r1_35($yy_subpatterns)
     function yy_r1_35($yy_subpatterns)
     {
     {
 
 
-	$this->token = OQLParser::F_CURRENT_DATE;
+	$this->token = OQLParser::F_DATE;
     }
     }
     function yy_r1_36($yy_subpatterns)
     function yy_r1_36($yy_subpatterns)
     {
     {
 
 
-	$this->token = OQLParser::F_NOW;
+	$this->token = OQLParser::F_DATE_FORMAT;
     }
     }
     function yy_r1_37($yy_subpatterns)
     function yy_r1_37($yy_subpatterns)
     {
     {
 
 
-	$this->token = OQLParser::F_TIME;
+	$this->token = OQLParser::F_CURRENT_DATE;
     }
     }
     function yy_r1_38($yy_subpatterns)
     function yy_r1_38($yy_subpatterns)
     {
     {
 
 
-	$this->token = OQLParser::F_TO_DAYS;
+	$this->token = OQLParser::F_NOW;
     }
     }
     function yy_r1_39($yy_subpatterns)
     function yy_r1_39($yy_subpatterns)
     {
     {
 
 
-	$this->token = OQLParser::F_FROM_DAYS;
+	$this->token = OQLParser::F_TIME;
     }
     }
     function yy_r1_40($yy_subpatterns)
     function yy_r1_40($yy_subpatterns)
     {
     {
 
 
-	$this->token = OQLParser::F_YEAR;
+	$this->token = OQLParser::F_TO_DAYS;
     }
     }
     function yy_r1_41($yy_subpatterns)
     function yy_r1_41($yy_subpatterns)
     {
     {
 
 
-	$this->token = OQLParser::F_MONTH;
+	$this->token = OQLParser::F_FROM_DAYS;
     }
     }
     function yy_r1_42($yy_subpatterns)
     function yy_r1_42($yy_subpatterns)
     {
     {
 
 
-	$this->token = OQLParser::F_DAY;
+	$this->token = OQLParser::F_YEAR;
     }
     }
     function yy_r1_43($yy_subpatterns)
     function yy_r1_43($yy_subpatterns)
     {
     {
 
 
-	$this->token = OQLParser::F_HOUR;
+	$this->token = OQLParser::F_MONTH;
     }
     }
     function yy_r1_44($yy_subpatterns)
     function yy_r1_44($yy_subpatterns)
     {
     {
 
 
-	$this->token = OQLParser::F_MINUTE;
+	$this->token = OQLParser::F_DAY;
     }
     }
     function yy_r1_45($yy_subpatterns)
     function yy_r1_45($yy_subpatterns)
     {
     {
 
 
-	$this->token = OQLParser::F_SECOND;
+	$this->token = OQLParser::F_HOUR;
     }
     }
     function yy_r1_46($yy_subpatterns)
     function yy_r1_46($yy_subpatterns)
     {
     {
 
 
-	$this->token = OQLParser::F_DATE_ADD;
+	$this->token = OQLParser::F_MINUTE;
     }
     }
     function yy_r1_47($yy_subpatterns)
     function yy_r1_47($yy_subpatterns)
     {
     {
 
 
-	$this->token = OQLParser::F_DATE_SUB;
+	$this->token = OQLParser::F_SECOND;
     }
     }
     function yy_r1_48($yy_subpatterns)
     function yy_r1_48($yy_subpatterns)
     {
     {
 
 
-	$this->token = OQLParser::F_ROUND;
+	$this->token = OQLParser::F_DATE_ADD;
     }
     }
     function yy_r1_49($yy_subpatterns)
     function yy_r1_49($yy_subpatterns)
     {
     {
 
 
-	$this->token = OQLParser::F_FLOOR;
+	$this->token = OQLParser::F_DATE_SUB;
     }
     }
     function yy_r1_50($yy_subpatterns)
     function yy_r1_50($yy_subpatterns)
     {
     {
 
 
-	$this->token = OQLParser::F_INET_ATON;
+	$this->token = OQLParser::F_ROUND;
     }
     }
     function yy_r1_51($yy_subpatterns)
     function yy_r1_51($yy_subpatterns)
     {
     {
 
 
-	$this->token = OQLParser::F_INET_NTOA;
+	$this->token = OQLParser::F_FLOOR;
     }
     }
     function yy_r1_52($yy_subpatterns)
     function yy_r1_52($yy_subpatterns)
     {
     {
 
 
-	$this->token = OQLParser::NUMVAL;
+	$this->token = OQLParser::F_INET_ATON;
     }
     }
     function yy_r1_53($yy_subpatterns)
     function yy_r1_53($yy_subpatterns)
     {
     {
 
 
-	$this->token = OQLParser::STRVAL;
+	$this->token = OQLParser::F_INET_NTOA;
     }
     }
     function yy_r1_54($yy_subpatterns)
     function yy_r1_54($yy_subpatterns)
     {
     {
 
 
-	$this->token = OQLParser::NAME;
+	$this->token = OQLParser::NUMVAL;
     }
     }
     function yy_r1_55($yy_subpatterns)
     function yy_r1_55($yy_subpatterns)
     {
     {
 
 
-	$this->token = OQLParser::VARNAME;
+	$this->token = OQLParser::STRVAL;
     }
     }
     function yy_r1_56($yy_subpatterns)
     function yy_r1_56($yy_subpatterns)
     {
     {
 
 
+	$this->token = OQLParser::NAME;
+    }
+    function yy_r1_57($yy_subpatterns)
+    {
+
+	$this->token = OQLParser::VARNAME;
+    }
+    function yy_r1_58($yy_subpatterns)
+    {
+
 	$this->token = OQLParser::DOT;
 	$this->token = OQLParser::DOT;
     }
     }
 
 

+ 8 - 0
core/oql/oql-lexer.plex

@@ -94,6 +94,7 @@ math_plus  = "+"
 math_minus = "-"
 math_minus = "-"
 log_and    = "AND"
 log_and    = "AND"
 log_or     = "OR"
 log_or     = "OR"
+regexp     = "REGEXP"
 eq         = "="
 eq         = "="
 not_eq     = "!="
 not_eq     = "!="
 gt         = ">"
 gt         = ">"
@@ -108,6 +109,7 @@ interval   = "INTERVAL"
 f_if       = "IF"
 f_if       = "IF"
 f_elt      = "ELT"
 f_elt      = "ELT"
 f_coalesce = "COALESCE"
 f_coalesce = "COALESCE"
+f_isnull   = "ISNULL"
 f_concat   = "CONCAT"
 f_concat   = "CONCAT"
 f_substr   = "SUBSTR"
 f_substr   = "SUBSTR"
 f_trim     = "TRIM"
 f_trim     = "TRIM"
@@ -186,6 +188,9 @@ par_open {
 par_close {
 par_close {
 	$this->token = OQLParser::PAR_CLOSE;
 	$this->token = OQLParser::PAR_CLOSE;
 }
 }
+regexp {
+	$this->token = OQLParser::REGEXP;
+}
 eq {
 eq {
 	$this->token = OQLParser::EQ;
 	$this->token = OQLParser::EQ;
 }
 }
@@ -228,6 +233,9 @@ f_elt {
 f_coalesce {
 f_coalesce {
 	$this->token = OQLParser::F_COALESCE;
 	$this->token = OQLParser::F_COALESCE;
 }
 }
+f_isnull {
+	$this->token = OQLParser::F_ISNULL;
+}
 f_concat {
 f_concat {
 	$this->token = OQLParser::F_CONCAT;
 	$this->token = OQLParser::F_CONCAT;
 }
 }

+ 382 - 366
core/oql/oql-parser.php

@@ -133,43 +133,45 @@ class OQLParserRaw#line 102 "oql-parser.php"
     const NAME                           = 20;
     const NAME                           = 20;
     const NUMVAL                         = 21;
     const NUMVAL                         = 21;
     const STRVAL                         = 22;
     const STRVAL                         = 22;
-    const NOT_EQ                         = 23;
-    const LOG_AND                        = 24;
-    const LOG_OR                         = 25;
-    const MATH_DIV                       = 26;
-    const MATH_MULT                      = 27;
-    const MATH_PLUS                      = 28;
-    const MATH_MINUS                     = 29;
-    const GT                             = 30;
-    const LT                             = 31;
-    const GE                             = 32;
-    const LE                             = 33;
-    const LIKE                           = 34;
-    const NOT_LIKE                       = 35;
-    const IN                             = 36;
-    const NOT_IN                         = 37;
-    const F_IF                           = 38;
-    const F_ELT                          = 39;
-    const F_COALESCE                     = 40;
-    const F_CONCAT                       = 41;
-    const F_SUBSTR                       = 42;
-    const F_TRIM                         = 43;
-    const F_DATE                         = 44;
-    const F_DATE_FORMAT                  = 45;
-    const F_CURRENT_DATE                 = 46;
-    const F_NOW                          = 47;
-    const F_TIME                         = 48;
-    const F_TO_DAYS                      = 49;
-    const F_FROM_DAYS                    = 50;
-    const F_DATE_ADD                     = 51;
-    const F_DATE_SUB                     = 52;
-    const F_ROUND                        = 53;
-    const F_FLOOR                        = 54;
-    const F_INET_ATON                    = 55;
-    const F_INET_NTOA                    = 56;
-    const YY_NO_ACTION = 234;
-    const YY_ACCEPT_ACTION = 233;
-    const YY_ERROR_ACTION = 232;
+    const REGEXP                         = 23;
+    const NOT_EQ                         = 24;
+    const LOG_AND                        = 25;
+    const LOG_OR                         = 26;
+    const MATH_DIV                       = 27;
+    const MATH_MULT                      = 28;
+    const MATH_PLUS                      = 29;
+    const MATH_MINUS                     = 30;
+    const GT                             = 31;
+    const LT                             = 32;
+    const GE                             = 33;
+    const LE                             = 34;
+    const LIKE                           = 35;
+    const NOT_LIKE                       = 36;
+    const IN                             = 37;
+    const NOT_IN                         = 38;
+    const F_IF                           = 39;
+    const F_ELT                          = 40;
+    const F_COALESCE                     = 41;
+    const F_ISNULL                       = 42;
+    const F_CONCAT                       = 43;
+    const F_SUBSTR                       = 44;
+    const F_TRIM                         = 45;
+    const F_DATE                         = 46;
+    const F_DATE_FORMAT                  = 47;
+    const F_CURRENT_DATE                 = 48;
+    const F_NOW                          = 49;
+    const F_TIME                         = 50;
+    const F_TO_DAYS                      = 51;
+    const F_FROM_DAYS                    = 52;
+    const F_DATE_ADD                     = 53;
+    const F_DATE_SUB                     = 54;
+    const F_ROUND                        = 55;
+    const F_FLOOR                        = 56;
+    const F_INET_ATON                    = 57;
+    const F_INET_NTOA                    = 58;
+    const YY_NO_ACTION = 238;
+    const YY_ACCEPT_ACTION = 237;
+    const YY_ERROR_ACTION = 236;
 
 
 /* Next are that tables used to determine what action to take based on the
 /* Next are that tables used to determine what action to take based on the
 ** current state and lookahead token.  These tables are used to implement
 ** current state and lookahead token.  These tables are used to implement
@@ -221,173 +223,179 @@ class OQLParserRaw#line 102 "oql-parser.php"
 **                          shifting non-terminals after a reduce.
 **                          shifting non-terminals after a reduce.
 **  self::$yy_default       Default action for each state.
 **  self::$yy_default       Default action for each state.
 */
 */
-    const YY_SZ_ACTTAB = 425;
+    const YY_SZ_ACTTAB = 455;
 static public $yy_action = array(
 static public $yy_action = array(
- /*     0 */    16,   55,   29,  141,  141,   69,   27,   96,    7,   33,
- /*    10 */    95,  100,   53,  105,  132,  133,  129,    5,   82,   81,
- /*    20 */    86,   87,   10,   60,   23,   25,   94,   93,   85,   84,
- /*    30 */    51,   19,   49,    8,   50,  114,  115,   92,   91,   90,
- /*    40 */    88,   89,  107,  108,  127,  126,  125,  123,  124,  128,
- /*    50 */   131,  130,  122,  121,  113,  112,    7,  120,    6,    2,
- /*    60 */    63,   63,  132,  133,  129,  101,   82,   81,   86,   87,
- /*    70 */    38,    9,  119,   24,  102,  103,   54,  118,  116,  117,
- /*    80 */   134,   65,   56,   61,   58,   92,   91,   90,   88,   89,
- /*    90 */   107,  108,  127,  126,  125,  123,  124,  128,  131,  130,
- /*   100 */   122,  121,  113,  112,    7,   63,  106,    3,   26,   59,
- /*   110 */   132,  133,  129,   12,   82,   81,   86,   87,   11,   70,
- /*   120 */    42,  105,   24,   24,   80,  110,   30,   68,   31,   28,
- /*   130 */    27,   20,  111,   92,   91,   90,   88,   89,  107,  108,
- /*   140 */   127,  126,  125,  123,  124,  128,  131,  130,  122,  121,
- /*   150 */   113,  112,  233,  109,   99,   55,   63,   63,   63,   46,
- /*   160 */    63,   96,   43,   34,   95,  100,   53,   67,    8,   13,
- /*   170 */    22,   79,   15,   41,   40,   44,   24,   83,   24,   55,
- /*   180 */    94,   93,   85,   84,   51,   96,   35,   34,   95,  100,
- /*   190 */    53,   47,  104,   17,   22,   55,   15,    4,   40,   98,
- /*   200 */    62,   52,   77,   55,   94,   93,   85,   84,   51,   96,
- /*   210 */    35,   34,   95,  100,   53,  186,    1,   27,   22,   81,
- /*   220 */    15,   71,   40,   45,   51,  193,   57,   55,   94,   93,
- /*   230 */    85,   84,   51,   96,   39,   34,   95,  100,   53,  193,
- /*   240 */   193,  193,   22,  193,   15,  193,   40,  193,  193,   48,
- /*   250 */    97,   55,   94,   93,   85,   84,   51,   96,   43,   34,
- /*   260 */    95,  100,   53,  193,  193,  193,   22,   55,   15,  193,
- /*   270 */    40,  193,   66,   52,  193,   55,   94,   93,   85,   84,
- /*   280 */    51,   96,   18,   34,   95,  100,   53,  193,  193,  193,
- /*   290 */    22,   55,   15,  193,   40,  193,   51,   64,  193,   55,
- /*   300 */    94,   93,   85,   84,   51,   96,   36,   34,   95,  100,
- /*   310 */    53,  193,  193,  193,   22,  193,   15,  193,   40,  193,
- /*   320 */    51,  193,  193,   55,   94,   93,   85,   84,   51,   96,
- /*   330 */    32,   34,   95,  100,   53,  193,  193,  193,   22,  193,
- /*   340 */    15,  193,   40,  193,  193,  193,  193,   55,   94,   93,
- /*   350 */    85,   84,   51,   96,  193,   34,   95,  100,   53,  193,
- /*   360 */   193,  193,   22,  193,   15,  193,   37,  193,  193,  193,
- /*   370 */   193,   55,   94,   93,   85,   84,   51,   96,  193,   34,
- /*   380 */    95,  100,   53,  193,  193,  193,   22,  193,   14,   74,
- /*   390 */    73,   72,   75,   76,   78,   55,   94,   93,   85,   84,
- /*   400 */    51,   96,  105,   34,   95,  100,   53,  193,  193,  193,
- /*   410 */    21,  193,  193,  193,  193,  193,  193,  193,  193,  193,
- /*   420 */    94,   93,   85,   84,   51,
+ /*     0 */    17,    6,   29,  143,  143,   28,   23,   56,    5,  120,
+ /*    10 */    12,    2,  107,   10,  133,  134,  135,  102,   83,   82,
+ /*    20 */    87,   88,  103,  104,  121,  119,  115,  116,  106,  105,
+ /*    30 */   117,  118,  136,   66,   58,   59,   60,   57,   93,   92,
+ /*    40 */    91,   89,   90,  108,  109,  128,  127,  126,  124,  125,
+ /*    50 */   129,  130,  131,  132,  123,  122,  114,  113,    5,   35,
+ /*    60 */     7,    3,   24,   70,  133,  134,  135,  106,   83,   82,
+ /*    70 */    87,   88,    4,   75,   74,   73,   76,   77,   79,   62,
+ /*    80 */    52,   69,   30,   20,   26,   63,   55,  106,   93,   92,
+ /*    90 */    91,   89,   90,  108,  109,  128,  127,  126,  124,  125,
+ /*   100 */   129,  130,  131,  132,  123,  122,  114,  113,    5,   54,
+ /*   110 */    64,   64,   64,   64,  133,  134,  135,    8,   83,   82,
+ /*   120 */    87,   88,   71,   43,   16,   24,   24,   31,   25,   81,
+ /*   130 */   111,   27,  188,   19,   53,   23,   49,   50,   93,   92,
+ /*   140 */    91,   89,   90,  108,  109,  128,  127,  126,  124,  125,
+ /*   150 */   129,  130,  131,  132,  123,  122,  114,  113,  237,  110,
+ /*   160 */   100,   52,   64,   64,    9,   68,   64,   97,   46,   32,
+ /*   170 */    96,  101,   51,   44,   45,   84,   21,   24,   15,   38,
+ /*   180 */    40,   13,   24,   82,   11,   52,   95,   94,   86,   85,
+ /*   190 */    54,   97,   39,   32,   96,  101,   51,   47,  112,    1,
+ /*   200 */    21,   23,   15,    8,   40,   99,   80,   72,   78,   52,
+ /*   210 */    95,   94,   86,   85,   54,   97,   39,   32,   96,  101,
+ /*   220 */    51,   42,  197,  197,   21,   52,   15,  197,   40,  197,
+ /*   230 */    67,   55,   61,   52,   95,   94,   86,   85,   54,   97,
+ /*   240 */    36,   32,   96,  101,   51,  197,  197,  197,   21,  197,
+ /*   250 */    15,  197,   40,  197,   54,   48,   98,   52,   95,   94,
+ /*   260 */    86,   85,   54,   97,   46,   32,   96,  101,   51,  197,
+ /*   270 */   197,  197,   21,   52,   15,  197,   40,  197,  197,   65,
+ /*   280 */   197,   52,   95,   94,   86,   85,   54,   97,   41,   32,
+ /*   290 */    96,  101,   51,  197,  197,  197,   21,  197,   15,  197,
+ /*   300 */    40,  197,   54,  197,  197,   52,   95,   94,   86,   85,
+ /*   310 */    54,   97,   33,   32,   96,  101,   51,  197,  197,  197,
+ /*   320 */    21,  197,   15,  197,   40,  197,  197,  197,  197,   52,
+ /*   330 */    95,   94,   86,   85,   54,   97,   18,   32,   96,  101,
+ /*   340 */    51,  197,  197,  197,   21,  197,   15,  197,   40,  197,
+ /*   350 */   197,  197,  197,   52,   95,   94,   86,   85,   54,   97,
+ /*   360 */   197,   32,   96,  101,   51,  197,  197,  197,   21,  197,
+ /*   370 */    15,  197,   37,  197,  197,  197,  197,   52,   95,   94,
+ /*   380 */    86,   85,   54,   97,  197,   32,   96,  101,   51,  197,
+ /*   390 */   197,  197,   21,  197,   14,  197,  197,  197,  197,  197,
+ /*   400 */   197,   52,   95,   94,   86,   85,   54,   97,  197,   32,
+ /*   410 */    96,  101,   51,  197,  197,  197,   22,  197,  197,  197,
+ /*   420 */   197,  197,  197,  197,  197,   52,   95,   94,   86,   85,
+ /*   430 */    54,   97,  197,   34,   96,  101,   51,  197,  197,  197,
+ /*   440 */   197,  197,  197,  197,  197,  197,  197,  197,  197,  197,
+ /*   450 */    95,   94,   86,   85,   54,
     );
     );
     static public $yy_lookahead = array(
     static public $yy_lookahead = array(
- /*     0 */     1,   61,    2,    3,    4,   63,    6,   67,    9,   69,
- /*    10 */    70,   71,   72,   25,   15,   16,   17,    4,   19,   20,
- /*    20 */    21,   22,   79,   10,    3,    4,   86,   87,   88,   89,
- /*    30 */    90,   61,   61,   82,   64,   92,   93,   38,   39,   40,
+ /*     0 */     1,    4,    2,    3,    4,    2,    6,   10,    9,    8,
+ /*    10 */     7,    4,   10,   81,   15,   16,   17,   10,   19,   20,
+ /*    20 */    21,   22,   37,   38,   23,   24,   94,   95,   26,   77,
+ /*    30 */    29,   30,   31,   32,   33,   34,   35,   36,   39,   40,
  /*    40 */    41,   42,   43,   44,   45,   46,   47,   48,   49,   50,
  /*    40 */    41,   42,   43,   44,   45,   46,   47,   48,   49,   50,
- /*    50 */    51,   52,   53,   54,   55,   56,    9,    8,   11,    4,
- /*    60 */    90,   90,   15,   16,   17,   10,   19,   20,   21,   22,
- /*    70 */    62,   81,   23,   65,   36,   37,   61,   28,   29,   30,
- /*    80 */    31,   32,   33,   34,   35,   38,   39,   40,   41,   42,
- /*    90 */    43,   44,   45,   46,   47,   48,   49,   50,   51,   52,
- /*   100 */    53,   54,   55,   56,    9,   90,   10,    5,    2,   24,
- /*   110 */    15,   16,   17,    7,   19,   20,   21,   22,   77,   62,
- /*   120 */    62,   25,   65,   65,   26,   27,    2,   61,   61,   61,
- /*   130 */     6,   61,   91,   38,   39,   40,   41,   42,   43,   44,
- /*   140 */    45,   46,   47,   48,   49,   50,   51,   52,   53,   54,
- /*   150 */    55,   56,   58,   59,   60,   61,   90,   90,   90,   18,
- /*   160 */    90,   67,   68,   69,   70,   71,   72,   63,   82,    7,
- /*   170 */    76,   85,   78,   62,   80,   62,   65,   90,   65,   61,
- /*   180 */    86,   87,   88,   89,   90,   67,   68,   69,   70,   71,
- /*   190 */    72,   73,   75,    8,   76,   61,   78,    9,   80,   63,
- /*   200 */    66,   67,   84,   61,   86,   87,   88,   89,   90,   67,
- /*   210 */    68,   69,   70,   71,   72,   18,    9,    6,   76,   20,
- /*   220 */    78,   63,   80,   74,   90,   94,   84,   61,   86,   87,
- /*   230 */    88,   89,   90,   67,   68,   69,   70,   71,   72,   94,
- /*   240 */    94,   94,   76,   94,   78,   94,   80,   94,   94,   83,
- /*   250 */    60,   61,   86,   87,   88,   89,   90,   67,   68,   69,
- /*   260 */    70,   71,   72,   94,   94,   94,   76,   61,   78,   94,
- /*   270 */    80,   94,   66,   67,   94,   61,   86,   87,   88,   89,
- /*   280 */    90,   67,   68,   69,   70,   71,   72,   94,   94,   94,
- /*   290 */    76,   61,   78,   94,   80,   94,   90,   67,   94,   61,
- /*   300 */    86,   87,   88,   89,   90,   67,   68,   69,   70,   71,
- /*   310 */    72,   94,   94,   94,   76,   94,   78,   94,   80,   94,
- /*   320 */    90,   94,   94,   61,   86,   87,   88,   89,   90,   67,
- /*   330 */    68,   69,   70,   71,   72,   94,   94,   94,   76,   94,
- /*   340 */    78,   94,   80,   94,   94,   94,   94,   61,   86,   87,
- /*   350 */    88,   89,   90,   67,   94,   69,   70,   71,   72,   94,
- /*   360 */    94,   94,   76,   94,   78,   94,   80,   94,   94,   94,
- /*   370 */    94,   61,   86,   87,   88,   89,   90,   67,   94,   69,
- /*   380 */    70,   71,   72,   94,   94,   94,   76,   94,   78,   12,
- /*   390 */    13,   14,   15,   16,   17,   61,   86,   87,   88,   89,
- /*   400 */    90,   67,   25,   69,   70,   71,   72,   94,   94,   94,
- /*   410 */    76,   94,   94,   94,   94,   94,   94,   94,   94,   94,
- /*   420 */    86,   87,   88,   89,   90,
+ /*    50 */    51,   52,   53,   54,   55,   56,   57,   58,    9,   64,
+ /*    60 */    11,    5,   67,   65,   15,   16,   17,   26,   19,   20,
+ /*    70 */    21,   22,    9,   12,   13,   14,   15,   16,   17,   25,
+ /*    80 */    63,   63,   63,   63,   63,   68,   69,   26,   39,   40,
+ /*    90 */    41,   42,   43,   44,   45,   46,   47,   48,   49,   50,
+ /*   100 */    51,   52,   53,   54,   55,   56,   57,   58,    9,   92,
+ /*   110 */    92,   92,   92,   92,   15,   16,   17,   84,   19,   20,
+ /*   120 */    21,   22,   64,   64,    8,   67,   67,    3,    4,   27,
+ /*   130 */    28,    2,   18,   63,   63,    6,   66,   63,   39,   40,
+ /*   140 */    41,   42,   43,   44,   45,   46,   47,   48,   49,   50,
+ /*   150 */    51,   52,   53,   54,   55,   56,   57,   58,   60,   61,
+ /*   160 */    62,   63,   92,   92,   83,   65,   92,   69,   70,   71,
+ /*   170 */    72,   73,   74,   18,   64,   92,   78,   67,   80,   64,
+ /*   180 */    82,    7,   67,   20,   79,   63,   88,   89,   90,   91,
+ /*   190 */    92,   69,   70,   71,   72,   73,   74,   75,   93,    9,
+ /*   200 */    78,    6,   80,   84,   82,   65,   87,   65,   86,   63,
+ /*   210 */    88,   89,   90,   91,   92,   69,   70,   71,   72,   73,
+ /*   220 */    74,   76,   96,   96,   78,   63,   80,   96,   82,   96,
+ /*   230 */    68,   69,   86,   63,   88,   89,   90,   91,   92,   69,
+ /*   240 */    70,   71,   72,   73,   74,   96,   96,   96,   78,   96,
+ /*   250 */    80,   96,   82,   96,   92,   85,   62,   63,   88,   89,
+ /*   260 */    90,   91,   92,   69,   70,   71,   72,   73,   74,   96,
+ /*   270 */    96,   96,   78,   63,   80,   96,   82,   96,   96,   69,
+ /*   280 */    96,   63,   88,   89,   90,   91,   92,   69,   70,   71,
+ /*   290 */    72,   73,   74,   96,   96,   96,   78,   96,   80,   96,
+ /*   300 */    82,   96,   92,   96,   96,   63,   88,   89,   90,   91,
+ /*   310 */    92,   69,   70,   71,   72,   73,   74,   96,   96,   96,
+ /*   320 */    78,   96,   80,   96,   82,   96,   96,   96,   96,   63,
+ /*   330 */    88,   89,   90,   91,   92,   69,   70,   71,   72,   73,
+ /*   340 */    74,   96,   96,   96,   78,   96,   80,   96,   82,   96,
+ /*   350 */    96,   96,   96,   63,   88,   89,   90,   91,   92,   69,
+ /*   360 */    96,   71,   72,   73,   74,   96,   96,   96,   78,   96,
+ /*   370 */    80,   96,   82,   96,   96,   96,   96,   63,   88,   89,
+ /*   380 */    90,   91,   92,   69,   96,   71,   72,   73,   74,   96,
+ /*   390 */    96,   96,   78,   96,   80,   96,   96,   96,   96,   96,
+ /*   400 */    96,   63,   88,   89,   90,   91,   92,   69,   96,   71,
+ /*   410 */    72,   73,   74,   96,   96,   96,   78,   96,   96,   96,
+ /*   420 */    96,   96,   96,   96,   96,   63,   88,   89,   90,   91,
+ /*   430 */    92,   69,   96,   71,   72,   73,   74,   96,   96,   96,
+ /*   440 */    96,   96,   96,   96,   96,   96,   96,   96,   96,   96,
+ /*   450 */    88,   89,   90,   91,   92,
 );
 );
-    const YY_SHIFT_USE_DFLT = -13;
+    const YY_SHIFT_USE_DFLT = -16;
     const YY_SHIFT_MAX = 55;
     const YY_SHIFT_MAX = 55;
     static public $yy_shift_ofst = array(
     static public $yy_shift_ofst = array(
- /*     0 */    -1,   47,   47,   95,   95,   95,   95,   95,   95,   95,
- /*    10 */    95,   95,  199,  199,   49,   49,  199,  199,  377,    0,
- /*    20 */   124,   98,   98,  199,  211,  199,  199,  199,  211,  199,
- /*    30 */   199,  211,   96,   38,   38,  -12,  -12,   85,  102,  -12,
- /*    40 */    85,  102,  102,  -12,  102,  188,  199,   55,   13,  106,
- /*    50 */    21,  197,  185,  207,  162,  141,
+ /*     0 */    -1,   49,   49,   99,   99,   99,   99,   99,   99,   99,
+ /*    10 */    99,   99,  163,  163,    1,    1,  163,  163,   61,    0,
+ /*    20 */   129,  102,  102,  163,  195,  163,  195,  163,  163,  163,
+ /*    30 */   195,  163,  -15,    2,  -15,   56,   41,   54,   56,   41,
+ /*    40 */    54,   41,   63,   56,  163,   56,   41,    7,   -3,  124,
+ /*    50 */     3,  190,  155,  174,  114,  116,
 );
 );
-    const YY_REDUCE_USE_DFLT = -61;
+    const YY_REDUCE_USE_DFLT = -69;
     const YY_REDUCE_MAX = 46;
     const YY_REDUCE_MAX = 46;
     static public $yy_reduce_ofst = array(
     static public $yy_reduce_ofst = array(
- /*     0 */    94,  118,  142,  190,  166,  238,  214,  262,  286,  310,
- /*    10 */   334,  -60,  206,  134,  -57,  -57,  -30,  230,   86,  113,
- /*    20 */   111,   41,   41,   70,   57,   66,   15,  -29,   58,   67,
- /*    30 */    68,    8,  -49,  149,  149,  -49,  -49,  -10,  158,  -49,
- /*    40 */   -10,  104,  -58,  -49,  136,  117,   87,
+ /*     0 */    98,  122,  146,  194,  170,  242,  218,  266,  290,  314,
+ /*    10 */   338,  362,  162,   17,  -68,  -68,  210,   70,  119,  115,
+ /*    20 */   110,  105,  105,   74,   58,   18,   -5,   19,   71,   21,
+ /*    30 */    59,   20,  145,   33,  145,  142,   33,   81,  140,   33,
+ /*    40 */    81,   33,  -48,   -2,   83,  100,   33,
 );
 );
     static public $yyExpectedTokens = array(
     static public $yyExpectedTokens = array(
-        /* 0 */ array(1, 9, 15, 16, 17, 19, 20, 21, 22, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, ),
-        /* 1 */ array(9, 11, 15, 16, 17, 19, 20, 21, 22, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, ),
-        /* 2 */ array(9, 11, 15, 16, 17, 19, 20, 21, 22, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, ),
-        /* 3 */ array(9, 15, 16, 17, 19, 20, 21, 22, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, ),
-        /* 4 */ array(9, 15, 16, 17, 19, 20, 21, 22, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, ),
-        /* 5 */ array(9, 15, 16, 17, 19, 20, 21, 22, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, ),
-        /* 6 */ array(9, 15, 16, 17, 19, 20, 21, 22, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, ),
-        /* 7 */ array(9, 15, 16, 17, 19, 20, 21, 22, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, ),
-        /* 8 */ array(9, 15, 16, 17, 19, 20, 21, 22, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, ),
-        /* 9 */ array(9, 15, 16, 17, 19, 20, 21, 22, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, ),
-        /* 10 */ array(9, 15, 16, 17, 19, 20, 21, 22, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, ),
-        /* 11 */ array(9, 15, 16, 17, 19, 20, 21, 22, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, ),
+        /* 0 */ array(1, 9, 15, 16, 17, 19, 20, 21, 22, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, ),
+        /* 1 */ array(9, 11, 15, 16, 17, 19, 20, 21, 22, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, ),
+        /* 2 */ array(9, 11, 15, 16, 17, 19, 20, 21, 22, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, ),
+        /* 3 */ array(9, 15, 16, 17, 19, 20, 21, 22, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, ),
+        /* 4 */ array(9, 15, 16, 17, 19, 20, 21, 22, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, ),
+        /* 5 */ array(9, 15, 16, 17, 19, 20, 21, 22, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, ),
+        /* 6 */ array(9, 15, 16, 17, 19, 20, 21, 22, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, ),
+        /* 7 */ array(9, 15, 16, 17, 19, 20, 21, 22, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, ),
+        /* 8 */ array(9, 15, 16, 17, 19, 20, 21, 22, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, ),
+        /* 9 */ array(9, 15, 16, 17, 19, 20, 21, 22, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, ),
+        /* 10 */ array(9, 15, 16, 17, 19, 20, 21, 22, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, ),
+        /* 11 */ array(9, 15, 16, 17, 19, 20, 21, 22, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, ),
         /* 12 */ array(20, ),
         /* 12 */ array(20, ),
         /* 13 */ array(20, ),
         /* 13 */ array(20, ),
-        /* 14 */ array(8, 23, 28, 29, 30, 31, 32, 33, 34, 35, ),
-        /* 15 */ array(8, 23, 28, 29, 30, 31, 32, 33, 34, 35, ),
+        /* 14 */ array(8, 23, 24, 29, 30, 31, 32, 33, 34, 35, 36, ),
+        /* 15 */ array(8, 23, 24, 29, 30, 31, 32, 33, 34, 35, 36, ),
         /* 16 */ array(20, ),
         /* 16 */ array(20, ),
         /* 17 */ array(20, ),
         /* 17 */ array(20, ),
-        /* 18 */ array(12, 13, 14, 15, 16, 17, 25, ),
+        /* 18 */ array(12, 13, 14, 15, 16, 17, 26, ),
         /* 19 */ array(2, 3, 4, 6, ),
         /* 19 */ array(2, 3, 4, 6, ),
         /* 20 */ array(2, 6, ),
         /* 20 */ array(2, 6, ),
-        /* 21 */ array(26, 27, ),
-        /* 22 */ array(26, 27, ),
+        /* 21 */ array(27, 28, ),
+        /* 22 */ array(27, 28, ),
         /* 23 */ array(20, ),
         /* 23 */ array(20, ),
         /* 24 */ array(6, ),
         /* 24 */ array(6, ),
         /* 25 */ array(20, ),
         /* 25 */ array(20, ),
-        /* 26 */ array(20, ),
+        /* 26 */ array(6, ),
         /* 27 */ array(20, ),
         /* 27 */ array(20, ),
-        /* 28 */ array(6, ),
+        /* 28 */ array(20, ),
         /* 29 */ array(20, ),
         /* 29 */ array(20, ),
-        /* 30 */ array(20, ),
-        /* 31 */ array(6, ),
-        /* 32 */ array(10, 25, ),
-        /* 33 */ array(36, 37, ),
-        /* 34 */ array(36, 37, ),
-        /* 35 */ array(25, ),
-        /* 36 */ array(25, ),
-        /* 37 */ array(24, ),
+        /* 30 */ array(6, ),
+        /* 31 */ array(20, ),
+        /* 32 */ array(37, 38, ),
+        /* 33 */ array(10, 26, ),
+        /* 34 */ array(37, 38, ),
+        /* 35 */ array(5, ),
+        /* 36 */ array(26, ),
+        /* 37 */ array(25, ),
         /* 38 */ array(5, ),
         /* 38 */ array(5, ),
-        /* 39 */ array(25, ),
-        /* 40 */ array(24, ),
-        /* 41 */ array(5, ),
-        /* 42 */ array(5, ),
-        /* 43 */ array(25, ),
-        /* 44 */ array(5, ),
-        /* 45 */ array(9, ),
-        /* 46 */ array(20, ),
+        /* 39 */ array(26, ),
+        /* 40 */ array(25, ),
+        /* 41 */ array(26, ),
+        /* 42 */ array(9, ),
+        /* 43 */ array(5, ),
+        /* 44 */ array(20, ),
+        /* 45 */ array(5, ),
+        /* 46 */ array(26, ),
         /* 47 */ array(4, 10, ),
         /* 47 */ array(4, 10, ),
         /* 48 */ array(4, 10, ),
         /* 48 */ array(4, 10, ),
-        /* 49 */ array(2, 7, ),
-        /* 50 */ array(3, 4, ),
-        /* 51 */ array(18, ),
-        /* 52 */ array(8, ),
-        /* 53 */ array(9, ),
-        /* 54 */ array(7, ),
-        /* 55 */ array(18, ),
+        /* 49 */ array(3, 4, ),
+        /* 50 */ array(2, 7, ),
+        /* 51 */ array(9, ),
+        /* 52 */ array(18, ),
+        /* 53 */ array(7, ),
+        /* 54 */ array(18, ),
+        /* 55 */ array(8, ),
         /* 56 */ array(),
         /* 56 */ array(),
         /* 57 */ array(),
         /* 57 */ array(),
         /* 58 */ array(),
         /* 58 */ array(),
@@ -467,22 +475,24 @@ static public $yy_action = array(
         /* 132 */ array(),
         /* 132 */ array(),
         /* 133 */ array(),
         /* 133 */ array(),
         /* 134 */ array(),
         /* 134 */ array(),
+        /* 135 */ array(),
+        /* 136 */ array(),
 );
 );
     static public $yy_default = array(
     static public $yy_default = array(
- /*     0 */   232,  169,  232,  232,  232,  232,  232,  232,  232,  232,
- /*    10 */   232,  232,  232,  232,  163,  162,  232,  232,  232,  147,
- /*    20 */   147,  161,  160,  232,  146,  232,  232,  232,  147,  232,
- /*    30 */   232,  147,  232,  159,  158,  172,  168,  165,  144,  167,
- /*    40 */   164,  144,  144,  151,  144,  232,  232,  232,  232,  232,
- /*    50 */   232,  184,  232,  232,  232,  232,  205,  171,  207,  196,
- /*    60 */   166,  206,  148,  186,  150,  204,  149,  139,  142,  140,
- /*    70 */   145,  138,  176,  175,  174,  177,  178,  170,  179,  173,
- /*    80 */   198,  188,  187,  185,  183,  182,  189,  190,  213,  214,
- /*    90 */   212,  211,  210,  181,  180,  152,  153,  143,  137,  136,
- /*   100 */   154,  155,  208,  209,  157,  197,  156,  215,  216,  135,
- /*   110 */   199,  191,  231,  230,  192,  193,  201,  202,  200,  195,
- /*   120 */   194,  229,  228,  220,  221,  219,  218,  217,  222,  223,
- /*   130 */   227,  226,  225,  224,  203,
+ /*     0 */   236,  171,  236,  236,  236,  236,  236,  236,  236,  236,
+ /*    10 */   236,  236,  236,  236,  165,  164,  236,  236,  236,  149,
+ /*    20 */   149,  162,  163,  236,  148,  236,  149,  236,  236,  236,
+ /*    30 */   149,  236,  160,  236,  161,  146,  169,  167,  146,  174,
+ /*    40 */   166,  170,  236,  146,  236,  146,  153,  236,  236,  236,
+ /*    50 */   236,  236,  236,  236,  186,  236,  168,  210,  207,  208,
+ /*    60 */   209,  173,  199,  150,  188,  152,  206,  151,  141,  144,
+ /*    70 */   142,  147,  140,  178,  177,  176,  179,  180,  172,  181,
+ /*    80 */   175,  201,  190,  189,  187,  185,  184,  191,  192,  216,
+ /*    90 */   217,  215,  214,  213,  183,  182,  154,  155,  145,  139,
+ /*   100 */   138,  156,  157,  211,  212,  159,  200,  158,  218,  219,
+ /*   110 */   137,  202,  193,  235,  234,  194,  195,  203,  204,  198,
+ /*   120 */   197,  196,  233,  232,  223,  224,  222,  221,  220,  225,
+ /*   130 */   226,  230,  231,  229,  228,  227,  205,
 );
 );
 /* The next thing included is series of defines which control
 /* The next thing included is series of defines which control
 ** various aspects of the generated parser.
 ** various aspects of the generated parser.
@@ -499,11 +509,11 @@ static public $yy_action = array(
 **    self::YYERRORSYMBOL is the code number of the error symbol.  If not
 **    self::YYERRORSYMBOL is the code number of the error symbol.  If not
 **                        defined, then do no error processing.
 **                        defined, then do no error processing.
 */
 */
-    const YYNOCODE = 95;
+    const YYNOCODE = 97;
     const YYSTACKDEPTH = 100;
     const YYSTACKDEPTH = 100;
-    const YYNSTATE = 135;
-    const YYNRULE = 97;
-    const YYERRORSYMBOL = 57;
+    const YYNSTATE = 137;
+    const YYNRULE = 99;
+    const YYERRORSYMBOL = 59;
     const YYERRSYMDT = 'yy0';
     const YYERRSYMDT = 'yy0';
     const YYFALLBACK = 0;
     const YYFALLBACK = 0;
     /** The next table maps tokens into fallback tokens.  If a construct
     /** The next table maps tokens into fallback tokens.  If a construct
@@ -590,25 +600,25 @@ static public $yy_action = array(
   'EQ',            'PAR_OPEN',      'PAR_CLOSE',     'INTERVAL',    
   'EQ',            'PAR_OPEN',      'PAR_CLOSE',     'INTERVAL',    
   'F_SECOND',      'F_MINUTE',      'F_HOUR',        'F_DAY',       
   'F_SECOND',      'F_MINUTE',      'F_HOUR',        'F_DAY',       
   'F_MONTH',       'F_YEAR',        'DOT',           'VARNAME',     
   'F_MONTH',       'F_YEAR',        'DOT',           'VARNAME',     
-  'NAME',          'NUMVAL',        'STRVAL',        'NOT_EQ',      
-  'LOG_AND',       'LOG_OR',        'MATH_DIV',      'MATH_MULT',   
-  'MATH_PLUS',     'MATH_MINUS',    'GT',            'LT',          
-  'GE',            'LE',            'LIKE',          'NOT_LIKE',    
-  'IN',            'NOT_IN',        'F_IF',          'F_ELT',       
-  'F_COALESCE',    'F_CONCAT',      'F_SUBSTR',      'F_TRIM',      
-  'F_DATE',        'F_DATE_FORMAT',  'F_CURRENT_DATE',  'F_NOW',       
-  'F_TIME',        'F_TO_DAYS',     'F_FROM_DAYS',   'F_DATE_ADD',  
-  'F_DATE_SUB',    'F_ROUND',       'F_FLOOR',       'F_INET_ATON', 
-  'F_INET_NTOA',   'error',         'result',        'query',       
-  'condition',     'class_name',    'join_statement',  'where_statement',
-  'class_list',    'join_item',     'join_condition',  'field_id',    
-  'expression_prio4',  'expression_basic',  'scalar',        'var_name',    
-  'func_name',     'arg_list',      'list_operator',  'list',        
-  'expression_prio1',  'operator1',     'expression_prio2',  'operator2',   
-  'expression_prio3',  'operator3',     'operator4',     'list_items',  
-  'argument',      'interval_unit',  'num_scalar',    'str_scalar',  
-  'num_value',     'str_value',     'name',          'num_operator1',
-  'num_operator2',  'str_operator',
+  'NAME',          'NUMVAL',        'STRVAL',        'REGEXP',      
+  'NOT_EQ',        'LOG_AND',       'LOG_OR',        'MATH_DIV',    
+  'MATH_MULT',     'MATH_PLUS',     'MATH_MINUS',    'GT',          
+  'LT',            'GE',            'LE',            'LIKE',        
+  'NOT_LIKE',      'IN',            'NOT_IN',        'F_IF',        
+  'F_ELT',         'F_COALESCE',    'F_ISNULL',      'F_CONCAT',    
+  'F_SUBSTR',      'F_TRIM',        'F_DATE',        'F_DATE_FORMAT',
+  'F_CURRENT_DATE',  'F_NOW',         'F_TIME',        'F_TO_DAYS',   
+  'F_FROM_DAYS',   'F_DATE_ADD',    'F_DATE_SUB',    'F_ROUND',     
+  'F_FLOOR',       'F_INET_ATON',   'F_INET_NTOA',   'error',       
+  'result',        'query',         'condition',     'class_name',  
+  'join_statement',  'where_statement',  'class_list',    'join_item',   
+  'join_condition',  'field_id',      'expression_prio4',  'expression_basic',
+  'scalar',        'var_name',      'func_name',     'arg_list',    
+  'list_operator',  'list',          'expression_prio1',  'operator1',   
+  'expression_prio2',  'operator2',     'expression_prio3',  'operator3',   
+  'operator4',     'list_items',    'argument',      'interval_unit',
+  'num_scalar',    'str_scalar',    'num_value',     'str_value',   
+  'name',          'num_operator1',  'num_operator2',  'str_operator',
     );
     );
 
 
     /**
     /**
@@ -675,44 +685,46 @@ static public $yy_action = array(
  /*  56 */ "operator1 ::= num_operator1",
  /*  56 */ "operator1 ::= num_operator1",
  /*  57 */ "operator2 ::= num_operator2",
  /*  57 */ "operator2 ::= num_operator2",
  /*  58 */ "operator2 ::= str_operator",
  /*  58 */ "operator2 ::= str_operator",
- /*  59 */ "operator2 ::= EQ",
- /*  60 */ "operator2 ::= NOT_EQ",
- /*  61 */ "operator3 ::= LOG_AND",
- /*  62 */ "operator4 ::= LOG_OR",
- /*  63 */ "num_operator1 ::= MATH_DIV",
- /*  64 */ "num_operator1 ::= MATH_MULT",
- /*  65 */ "num_operator2 ::= MATH_PLUS",
- /*  66 */ "num_operator2 ::= MATH_MINUS",
- /*  67 */ "num_operator2 ::= GT",
- /*  68 */ "num_operator2 ::= LT",
- /*  69 */ "num_operator2 ::= GE",
- /*  70 */ "num_operator2 ::= LE",
- /*  71 */ "str_operator ::= LIKE",
- /*  72 */ "str_operator ::= NOT_LIKE",
- /*  73 */ "list_operator ::= IN",
- /*  74 */ "list_operator ::= NOT_IN",
- /*  75 */ "func_name ::= F_IF",
- /*  76 */ "func_name ::= F_ELT",
- /*  77 */ "func_name ::= F_COALESCE",
- /*  78 */ "func_name ::= F_CONCAT",
- /*  79 */ "func_name ::= F_SUBSTR",
- /*  80 */ "func_name ::= F_TRIM",
- /*  81 */ "func_name ::= F_DATE",
- /*  82 */ "func_name ::= F_DATE_FORMAT",
- /*  83 */ "func_name ::= F_CURRENT_DATE",
- /*  84 */ "func_name ::= F_NOW",
- /*  85 */ "func_name ::= F_TIME",
- /*  86 */ "func_name ::= F_TO_DAYS",
- /*  87 */ "func_name ::= F_FROM_DAYS",
- /*  88 */ "func_name ::= F_YEAR",
- /*  89 */ "func_name ::= F_MONTH",
- /*  90 */ "func_name ::= F_DAY",
- /*  91 */ "func_name ::= F_DATE_ADD",
- /*  92 */ "func_name ::= F_DATE_SUB",
- /*  93 */ "func_name ::= F_ROUND",
- /*  94 */ "func_name ::= F_FLOOR",
- /*  95 */ "func_name ::= F_INET_ATON",
- /*  96 */ "func_name ::= F_INET_NTOA",
+ /*  59 */ "operator2 ::= REGEXP",
+ /*  60 */ "operator2 ::= EQ",
+ /*  61 */ "operator2 ::= NOT_EQ",
+ /*  62 */ "operator3 ::= LOG_AND",
+ /*  63 */ "operator4 ::= LOG_OR",
+ /*  64 */ "num_operator1 ::= MATH_DIV",
+ /*  65 */ "num_operator1 ::= MATH_MULT",
+ /*  66 */ "num_operator2 ::= MATH_PLUS",
+ /*  67 */ "num_operator2 ::= MATH_MINUS",
+ /*  68 */ "num_operator2 ::= GT",
+ /*  69 */ "num_operator2 ::= LT",
+ /*  70 */ "num_operator2 ::= GE",
+ /*  71 */ "num_operator2 ::= LE",
+ /*  72 */ "str_operator ::= LIKE",
+ /*  73 */ "str_operator ::= NOT_LIKE",
+ /*  74 */ "list_operator ::= IN",
+ /*  75 */ "list_operator ::= NOT_IN",
+ /*  76 */ "func_name ::= F_IF",
+ /*  77 */ "func_name ::= F_ELT",
+ /*  78 */ "func_name ::= F_COALESCE",
+ /*  79 */ "func_name ::= F_ISNULL",
+ /*  80 */ "func_name ::= F_CONCAT",
+ /*  81 */ "func_name ::= F_SUBSTR",
+ /*  82 */ "func_name ::= F_TRIM",
+ /*  83 */ "func_name ::= F_DATE",
+ /*  84 */ "func_name ::= F_DATE_FORMAT",
+ /*  85 */ "func_name ::= F_CURRENT_DATE",
+ /*  86 */ "func_name ::= F_NOW",
+ /*  87 */ "func_name ::= F_TIME",
+ /*  88 */ "func_name ::= F_TO_DAYS",
+ /*  89 */ "func_name ::= F_FROM_DAYS",
+ /*  90 */ "func_name ::= F_YEAR",
+ /*  91 */ "func_name ::= F_MONTH",
+ /*  92 */ "func_name ::= F_DAY",
+ /*  93 */ "func_name ::= F_DATE_ADD",
+ /*  94 */ "func_name ::= F_DATE_SUB",
+ /*  95 */ "func_name ::= F_ROUND",
+ /*  96 */ "func_name ::= F_FLOOR",
+ /*  97 */ "func_name ::= F_INET_ATON",
+ /*  98 */ "func_name ::= F_INET_NTOA",
     );
     );
 
 
     /**
     /**
@@ -1077,103 +1089,105 @@ static public $yy_action = array(
      * </pre>
      * </pre>
      */
      */
     static public $yyRuleInfo = array(
     static public $yyRuleInfo = array(
-  array( 'lhs' => 58, 'rhs' => 1 ),
-  array( 'lhs' => 58, 'rhs' => 1 ),
-  array( 'lhs' => 59, 'rhs' => 4 ),
-  array( 'lhs' => 59, 'rhs' => 6 ),
-  array( 'lhs' => 59, 'rhs' => 6 ),
-  array( 'lhs' => 59, 'rhs' => 8 ),
+  array( 'lhs' => 60, 'rhs' => 1 ),
+  array( 'lhs' => 60, 'rhs' => 1 ),
+  array( 'lhs' => 61, 'rhs' => 4 ),
+  array( 'lhs' => 61, 'rhs' => 6 ),
+  array( 'lhs' => 61, 'rhs' => 6 ),
+  array( 'lhs' => 61, 'rhs' => 8 ),
+  array( 'lhs' => 66, 'rhs' => 1 ),
+  array( 'lhs' => 66, 'rhs' => 3 ),
+  array( 'lhs' => 65, 'rhs' => 2 ),
+  array( 'lhs' => 65, 'rhs' => 0 ),
+  array( 'lhs' => 64, 'rhs' => 2 ),
   array( 'lhs' => 64, 'rhs' => 1 ),
   array( 'lhs' => 64, 'rhs' => 1 ),
-  array( 'lhs' => 64, 'rhs' => 3 ),
-  array( 'lhs' => 63, 'rhs' => 2 ),
-  array( 'lhs' => 63, 'rhs' => 0 ),
-  array( 'lhs' => 62, 'rhs' => 2 ),
+  array( 'lhs' => 64, 'rhs' => 0 ),
+  array( 'lhs' => 67, 'rhs' => 6 ),
+  array( 'lhs' => 67, 'rhs' => 4 ),
+  array( 'lhs' => 68, 'rhs' => 3 ),
   array( 'lhs' => 62, 'rhs' => 1 ),
   array( 'lhs' => 62, 'rhs' => 1 ),
-  array( 'lhs' => 62, 'rhs' => 0 ),
-  array( 'lhs' => 65, 'rhs' => 6 ),
-  array( 'lhs' => 65, 'rhs' => 4 ),
-  array( 'lhs' => 66, 'rhs' => 3 ),
-  array( 'lhs' => 60, 'rhs' => 1 ),
-  array( 'lhs' => 69, 'rhs' => 1 ),
-  array( 'lhs' => 69, 'rhs' => 1 ),
-  array( 'lhs' => 69, 'rhs' => 1 ),
-  array( 'lhs' => 69, 'rhs' => 4 ),
-  array( 'lhs' => 69, 'rhs' => 3 ),
-  array( 'lhs' => 69, 'rhs' => 3 ),
-  array( 'lhs' => 76, 'rhs' => 1 ),
-  array( 'lhs' => 76, 'rhs' => 3 ),
+  array( 'lhs' => 71, 'rhs' => 1 ),
+  array( 'lhs' => 71, 'rhs' => 1 ),
+  array( 'lhs' => 71, 'rhs' => 1 ),
+  array( 'lhs' => 71, 'rhs' => 4 ),
+  array( 'lhs' => 71, 'rhs' => 3 ),
+  array( 'lhs' => 71, 'rhs' => 3 ),
   array( 'lhs' => 78, 'rhs' => 1 ),
   array( 'lhs' => 78, 'rhs' => 1 ),
   array( 'lhs' => 78, 'rhs' => 3 ),
   array( 'lhs' => 78, 'rhs' => 3 ),
   array( 'lhs' => 80, 'rhs' => 1 ),
   array( 'lhs' => 80, 'rhs' => 1 ),
   array( 'lhs' => 80, 'rhs' => 3 ),
   array( 'lhs' => 80, 'rhs' => 3 ),
-  array( 'lhs' => 68, 'rhs' => 1 ),
-  array( 'lhs' => 68, 'rhs' => 3 ),
-  array( 'lhs' => 75, 'rhs' => 3 ),
-  array( 'lhs' => 83, 'rhs' => 1 ),
-  array( 'lhs' => 83, 'rhs' => 3 ),
-  array( 'lhs' => 73, 'rhs' => 0 ),
-  array( 'lhs' => 73, 'rhs' => 1 ),
-  array( 'lhs' => 73, 'rhs' => 3 ),
-  array( 'lhs' => 84, 'rhs' => 1 ),
-  array( 'lhs' => 84, 'rhs' => 3 ),
-  array( 'lhs' => 85, 'rhs' => 1 ),
-  array( 'lhs' => 85, 'rhs' => 1 ),
-  array( 'lhs' => 85, 'rhs' => 1 ),
-  array( 'lhs' => 85, 'rhs' => 1 ),
-  array( 'lhs' => 85, 'rhs' => 1 ),
-  array( 'lhs' => 85, 'rhs' => 1 ),
-  array( 'lhs' => 70, 'rhs' => 1 ),
+  array( 'lhs' => 82, 'rhs' => 1 ),
+  array( 'lhs' => 82, 'rhs' => 3 ),
   array( 'lhs' => 70, 'rhs' => 1 ),
   array( 'lhs' => 70, 'rhs' => 1 ),
+  array( 'lhs' => 70, 'rhs' => 3 ),
+  array( 'lhs' => 77, 'rhs' => 3 ),
+  array( 'lhs' => 85, 'rhs' => 1 ),
+  array( 'lhs' => 85, 'rhs' => 3 ),
+  array( 'lhs' => 75, 'rhs' => 0 ),
+  array( 'lhs' => 75, 'rhs' => 1 ),
+  array( 'lhs' => 75, 'rhs' => 3 ),
   array( 'lhs' => 86, 'rhs' => 1 ),
   array( 'lhs' => 86, 'rhs' => 1 ),
+  array( 'lhs' => 86, 'rhs' => 3 ),
   array( 'lhs' => 87, 'rhs' => 1 ),
   array( 'lhs' => 87, 'rhs' => 1 ),
-  array( 'lhs' => 67, 'rhs' => 1 ),
-  array( 'lhs' => 67, 'rhs' => 3 ),
-  array( 'lhs' => 61, 'rhs' => 1 ),
-  array( 'lhs' => 71, 'rhs' => 1 ),
-  array( 'lhs' => 90, 'rhs' => 1 ),
+  array( 'lhs' => 87, 'rhs' => 1 ),
+  array( 'lhs' => 87, 'rhs' => 1 ),
+  array( 'lhs' => 87, 'rhs' => 1 ),
+  array( 'lhs' => 87, 'rhs' => 1 ),
+  array( 'lhs' => 87, 'rhs' => 1 ),
+  array( 'lhs' => 72, 'rhs' => 1 ),
+  array( 'lhs' => 72, 'rhs' => 1 ),
   array( 'lhs' => 88, 'rhs' => 1 ),
   array( 'lhs' => 88, 'rhs' => 1 ),
   array( 'lhs' => 89, 'rhs' => 1 ),
   array( 'lhs' => 89, 'rhs' => 1 ),
-  array( 'lhs' => 77, 'rhs' => 1 ),
-  array( 'lhs' => 79, 'rhs' => 1 ),
-  array( 'lhs' => 79, 'rhs' => 1 ),
-  array( 'lhs' => 79, 'rhs' => 1 ),
+  array( 'lhs' => 69, 'rhs' => 1 ),
+  array( 'lhs' => 69, 'rhs' => 3 ),
+  array( 'lhs' => 63, 'rhs' => 1 ),
+  array( 'lhs' => 73, 'rhs' => 1 ),
+  array( 'lhs' => 92, 'rhs' => 1 ),
+  array( 'lhs' => 90, 'rhs' => 1 ),
+  array( 'lhs' => 91, 'rhs' => 1 ),
   array( 'lhs' => 79, 'rhs' => 1 ),
   array( 'lhs' => 79, 'rhs' => 1 ),
   array( 'lhs' => 81, 'rhs' => 1 ),
   array( 'lhs' => 81, 'rhs' => 1 ),
-  array( 'lhs' => 82, 'rhs' => 1 ),
-  array( 'lhs' => 91, 'rhs' => 1 ),
-  array( 'lhs' => 91, 'rhs' => 1 ),
-  array( 'lhs' => 92, 'rhs' => 1 ),
-  array( 'lhs' => 92, 'rhs' => 1 ),
-  array( 'lhs' => 92, 'rhs' => 1 ),
-  array( 'lhs' => 92, 'rhs' => 1 ),
-  array( 'lhs' => 92, 'rhs' => 1 ),
-  array( 'lhs' => 92, 'rhs' => 1 ),
+  array( 'lhs' => 81, 'rhs' => 1 ),
+  array( 'lhs' => 81, 'rhs' => 1 ),
+  array( 'lhs' => 81, 'rhs' => 1 ),
+  array( 'lhs' => 81, 'rhs' => 1 ),
+  array( 'lhs' => 83, 'rhs' => 1 ),
+  array( 'lhs' => 84, 'rhs' => 1 ),
   array( 'lhs' => 93, 'rhs' => 1 ),
   array( 'lhs' => 93, 'rhs' => 1 ),
   array( 'lhs' => 93, 'rhs' => 1 ),
   array( 'lhs' => 93, 'rhs' => 1 ),
+  array( 'lhs' => 94, 'rhs' => 1 ),
+  array( 'lhs' => 94, 'rhs' => 1 ),
+  array( 'lhs' => 94, 'rhs' => 1 ),
+  array( 'lhs' => 94, 'rhs' => 1 ),
+  array( 'lhs' => 94, 'rhs' => 1 ),
+  array( 'lhs' => 94, 'rhs' => 1 ),
+  array( 'lhs' => 95, 'rhs' => 1 ),
+  array( 'lhs' => 95, 'rhs' => 1 ),
+  array( 'lhs' => 76, 'rhs' => 1 ),
+  array( 'lhs' => 76, 'rhs' => 1 ),
+  array( 'lhs' => 74, 'rhs' => 1 ),
+  array( 'lhs' => 74, 'rhs' => 1 ),
+  array( 'lhs' => 74, 'rhs' => 1 ),
+  array( 'lhs' => 74, 'rhs' => 1 ),
+  array( 'lhs' => 74, 'rhs' => 1 ),
+  array( 'lhs' => 74, 'rhs' => 1 ),
+  array( 'lhs' => 74, 'rhs' => 1 ),
+  array( 'lhs' => 74, 'rhs' => 1 ),
+  array( 'lhs' => 74, 'rhs' => 1 ),
+  array( 'lhs' => 74, 'rhs' => 1 ),
+  array( 'lhs' => 74, 'rhs' => 1 ),
+  array( 'lhs' => 74, 'rhs' => 1 ),
+  array( 'lhs' => 74, 'rhs' => 1 ),
+  array( 'lhs' => 74, 'rhs' => 1 ),
+  array( 'lhs' => 74, 'rhs' => 1 ),
+  array( 'lhs' => 74, 'rhs' => 1 ),
+  array( 'lhs' => 74, 'rhs' => 1 ),
+  array( 'lhs' => 74, 'rhs' => 1 ),
+  array( 'lhs' => 74, 'rhs' => 1 ),
+  array( 'lhs' => 74, 'rhs' => 1 ),
+  array( 'lhs' => 74, 'rhs' => 1 ),
   array( 'lhs' => 74, 'rhs' => 1 ),
   array( 'lhs' => 74, 'rhs' => 1 ),
   array( 'lhs' => 74, 'rhs' => 1 ),
   array( 'lhs' => 74, 'rhs' => 1 ),
-  array( 'lhs' => 72, 'rhs' => 1 ),
-  array( 'lhs' => 72, 'rhs' => 1 ),
-  array( 'lhs' => 72, 'rhs' => 1 ),
-  array( 'lhs' => 72, 'rhs' => 1 ),
-  array( 'lhs' => 72, 'rhs' => 1 ),
-  array( 'lhs' => 72, 'rhs' => 1 ),
-  array( 'lhs' => 72, 'rhs' => 1 ),
-  array( 'lhs' => 72, 'rhs' => 1 ),
-  array( 'lhs' => 72, 'rhs' => 1 ),
-  array( 'lhs' => 72, 'rhs' => 1 ),
-  array( 'lhs' => 72, 'rhs' => 1 ),
-  array( 'lhs' => 72, 'rhs' => 1 ),
-  array( 'lhs' => 72, 'rhs' => 1 ),
-  array( 'lhs' => 72, 'rhs' => 1 ),
-  array( 'lhs' => 72, 'rhs' => 1 ),
-  array( 'lhs' => 72, 'rhs' => 1 ),
-  array( 'lhs' => 72, 'rhs' => 1 ),
-  array( 'lhs' => 72, 'rhs' => 1 ),
-  array( 'lhs' => 72, 'rhs' => 1 ),
-  array( 'lhs' => 72, 'rhs' => 1 ),
-  array( 'lhs' => 72, 'rhs' => 1 ),
-  array( 'lhs' => 72, 'rhs' => 1 ),
     );
     );
 
 
     /**
     /**
@@ -1235,7 +1249,6 @@ static public $yy_action = array(
         49 => 49,
         49 => 49,
         50 => 50,
         50 => 50,
         51 => 51,
         51 => 51,
-        75 => 51,
         76 => 51,
         76 => 51,
         77 => 51,
         77 => 51,
         78 => 51,
         78 => 51,
@@ -1257,6 +1270,8 @@ static public $yy_action = array(
         94 => 51,
         94 => 51,
         95 => 51,
         95 => 51,
         96 => 51,
         96 => 51,
+        97 => 51,
+        98 => 51,
         52 => 52,
         52 => 52,
         53 => 53,
         53 => 53,
         54 => 54,
         54 => 54,
@@ -1279,6 +1294,7 @@ static public $yy_action = array(
         72 => 54,
         72 => 54,
         73 => 54,
         73 => 54,
         74 => 54,
         74 => 54,
+        75 => 54,
         55 => 55,
         55 => 55,
     );
     );
     /* Beginning here are the reduction cases.  A typical example
     /* Beginning here are the reduction cases.  A typical example
@@ -1289,44 +1305,44 @@ static public $yy_action = array(
     */
     */
 #line 29 "oql-parser.y"
 #line 29 "oql-parser.y"
     function yy_r0(){ $this->my_result = $this->yystack[$this->yyidx + 0]->minor;     }
     function yy_r0(){ $this->my_result = $this->yystack[$this->yyidx + 0]->minor;     }
-#line 1296 "oql-parser.php"
+#line 1312 "oql-parser.php"
 #line 32 "oql-parser.y"
 #line 32 "oql-parser.y"
     function yy_r2(){
     function yy_r2(){
 	$this->_retvalue = new OqlObjectQuery($this->yystack[$this->yyidx + -2]->minor, $this->yystack[$this->yyidx + -2]->minor, $this->yystack[$this->yyidx + 0]->minor, $this->yystack[$this->yyidx + -1]->minor, array($this->yystack[$this->yyidx + -2]->minor));
 	$this->_retvalue = new OqlObjectQuery($this->yystack[$this->yyidx + -2]->minor, $this->yystack[$this->yyidx + -2]->minor, $this->yystack[$this->yyidx + 0]->minor, $this->yystack[$this->yyidx + -1]->minor, array($this->yystack[$this->yyidx + -2]->minor));
     }
     }
-#line 1301 "oql-parser.php"
+#line 1317 "oql-parser.php"
 #line 35 "oql-parser.y"
 #line 35 "oql-parser.y"
     function yy_r3(){
     function yy_r3(){
 	$this->_retvalue = new OqlObjectQuery($this->yystack[$this->yyidx + -4]->minor, $this->yystack[$this->yyidx + -2]->minor, $this->yystack[$this->yyidx + 0]->minor, $this->yystack[$this->yyidx + -1]->minor, array($this->yystack[$this->yyidx + -2]->minor));
 	$this->_retvalue = new OqlObjectQuery($this->yystack[$this->yyidx + -4]->minor, $this->yystack[$this->yyidx + -2]->minor, $this->yystack[$this->yyidx + 0]->minor, $this->yystack[$this->yyidx + -1]->minor, array($this->yystack[$this->yyidx + -2]->minor));
     }
     }
-#line 1306 "oql-parser.php"
+#line 1322 "oql-parser.php"
 #line 39 "oql-parser.y"
 #line 39 "oql-parser.y"
     function yy_r4(){
     function yy_r4(){
 	$this->_retvalue = new OqlObjectQuery($this->yystack[$this->yyidx + -2]->minor, $this->yystack[$this->yyidx + -2]->minor, $this->yystack[$this->yyidx + 0]->minor, $this->yystack[$this->yyidx + -1]->minor, $this->yystack[$this->yyidx + -4]->minor);
 	$this->_retvalue = new OqlObjectQuery($this->yystack[$this->yyidx + -2]->minor, $this->yystack[$this->yyidx + -2]->minor, $this->yystack[$this->yyidx + 0]->minor, $this->yystack[$this->yyidx + -1]->minor, $this->yystack[$this->yyidx + -4]->minor);
     }
     }
-#line 1311 "oql-parser.php"
+#line 1327 "oql-parser.php"
 #line 42 "oql-parser.y"
 #line 42 "oql-parser.y"
     function yy_r5(){
     function yy_r5(){
 	$this->_retvalue = new OqlObjectQuery($this->yystack[$this->yyidx + -4]->minor, $this->yystack[$this->yyidx + -2]->minor, $this->yystack[$this->yyidx + 0]->minor, $this->yystack[$this->yyidx + -1]->minor, $this->yystack[$this->yyidx + -6]->minor);
 	$this->_retvalue = new OqlObjectQuery($this->yystack[$this->yyidx + -4]->minor, $this->yystack[$this->yyidx + -2]->minor, $this->yystack[$this->yyidx + 0]->minor, $this->yystack[$this->yyidx + -1]->minor, $this->yystack[$this->yyidx + -6]->minor);
     }
     }
-#line 1316 "oql-parser.php"
+#line 1332 "oql-parser.php"
 #line 47 "oql-parser.y"
 #line 47 "oql-parser.y"
     function yy_r6(){
     function yy_r6(){
 	$this->_retvalue = array($this->yystack[$this->yyidx + 0]->minor);
 	$this->_retvalue = array($this->yystack[$this->yyidx + 0]->minor);
     }
     }
-#line 1321 "oql-parser.php"
+#line 1337 "oql-parser.php"
 #line 50 "oql-parser.y"
 #line 50 "oql-parser.y"
     function yy_r7(){
     function yy_r7(){
 	array_push($this->yystack[$this->yyidx + -2]->minor, $this->yystack[$this->yyidx + 0]->minor);
 	array_push($this->yystack[$this->yyidx + -2]->minor, $this->yystack[$this->yyidx + 0]->minor);
 	$this->_retvalue = $this->yystack[$this->yyidx + -2]->minor;
 	$this->_retvalue = $this->yystack[$this->yyidx + -2]->minor;
     }
     }
-#line 1327 "oql-parser.php"
+#line 1343 "oql-parser.php"
 #line 55 "oql-parser.y"
 #line 55 "oql-parser.y"
     function yy_r8(){ $this->_retvalue = $this->yystack[$this->yyidx + 0]->minor;    }
     function yy_r8(){ $this->_retvalue = $this->yystack[$this->yyidx + 0]->minor;    }
-#line 1330 "oql-parser.php"
+#line 1346 "oql-parser.php"
 #line 56 "oql-parser.y"
 #line 56 "oql-parser.y"
     function yy_r9(){ $this->_retvalue = null;    }
     function yy_r9(){ $this->_retvalue = null;    }
-#line 1333 "oql-parser.php"
+#line 1349 "oql-parser.php"
 #line 58 "oql-parser.y"
 #line 58 "oql-parser.y"
     function yy_r10(){
     function yy_r10(){
 	// insert the join statement on top of the existing list
 	// insert the join statement on top of the existing list
@@ -1334,67 +1350,67 @@ static public $yy_action = array(
 	// and return the updated array
 	// and return the updated array
 	$this->_retvalue = $this->yystack[$this->yyidx + 0]->minor;
 	$this->_retvalue = $this->yystack[$this->yyidx + 0]->minor;
     }
     }
-#line 1341 "oql-parser.php"
+#line 1357 "oql-parser.php"
 #line 64 "oql-parser.y"
 #line 64 "oql-parser.y"
     function yy_r11(){
     function yy_r11(){
 	$this->_retvalue = Array($this->yystack[$this->yyidx + 0]->minor);
 	$this->_retvalue = Array($this->yystack[$this->yyidx + 0]->minor);
     }
     }
-#line 1346 "oql-parser.php"
+#line 1362 "oql-parser.php"
 #line 70 "oql-parser.y"
 #line 70 "oql-parser.y"
     function yy_r13(){
     function yy_r13(){
 	// create an array with one single item
 	// create an array with one single item
 	$this->_retvalue = new OqlJoinSpec($this->yystack[$this->yyidx + -4]->minor, $this->yystack[$this->yyidx + -2]->minor, $this->yystack[$this->yyidx + 0]->minor);
 	$this->_retvalue = new OqlJoinSpec($this->yystack[$this->yyidx + -4]->minor, $this->yystack[$this->yyidx + -2]->minor, $this->yystack[$this->yyidx + 0]->minor);
     }
     }
-#line 1352 "oql-parser.php"
+#line 1368 "oql-parser.php"
 #line 75 "oql-parser.y"
 #line 75 "oql-parser.y"
     function yy_r14(){
     function yy_r14(){
 	// create an array with one single item
 	// create an array with one single item
 	$this->_retvalue = new OqlJoinSpec($this->yystack[$this->yyidx + -2]->minor, $this->yystack[$this->yyidx + -2]->minor, $this->yystack[$this->yyidx + 0]->minor);
 	$this->_retvalue = new OqlJoinSpec($this->yystack[$this->yyidx + -2]->minor, $this->yystack[$this->yyidx + -2]->minor, $this->yystack[$this->yyidx + 0]->minor);
     }
     }
-#line 1358 "oql-parser.php"
+#line 1374 "oql-parser.php"
 #line 80 "oql-parser.y"
 #line 80 "oql-parser.y"
     function yy_r15(){ $this->_retvalue = new BinaryOqlExpression($this->yystack[$this->yyidx + -2]->minor, '=', $this->yystack[$this->yyidx + 0]->minor);     }
     function yy_r15(){ $this->_retvalue = new BinaryOqlExpression($this->yystack[$this->yyidx + -2]->minor, '=', $this->yystack[$this->yyidx + 0]->minor);     }
-#line 1361 "oql-parser.php"
+#line 1377 "oql-parser.php"
 #line 82 "oql-parser.y"
 #line 82 "oql-parser.y"
     function yy_r16(){ $this->_retvalue = $this->yystack[$this->yyidx + 0]->minor;     }
     function yy_r16(){ $this->_retvalue = $this->yystack[$this->yyidx + 0]->minor;     }
-#line 1364 "oql-parser.php"
+#line 1380 "oql-parser.php"
 #line 87 "oql-parser.y"
 #line 87 "oql-parser.y"
     function yy_r20(){ $this->_retvalue = new FunctionOqlExpression($this->yystack[$this->yyidx + -3]->minor, $this->yystack[$this->yyidx + -1]->minor);     }
     function yy_r20(){ $this->_retvalue = new FunctionOqlExpression($this->yystack[$this->yyidx + -3]->minor, $this->yystack[$this->yyidx + -1]->minor);     }
-#line 1367 "oql-parser.php"
+#line 1383 "oql-parser.php"
 #line 88 "oql-parser.y"
 #line 88 "oql-parser.y"
     function yy_r21(){ $this->_retvalue = $this->yystack[$this->yyidx + -1]->minor;     }
     function yy_r21(){ $this->_retvalue = $this->yystack[$this->yyidx + -1]->minor;     }
-#line 1370 "oql-parser.php"
+#line 1386 "oql-parser.php"
 #line 89 "oql-parser.y"
 #line 89 "oql-parser.y"
     function yy_r22(){ $this->_retvalue = new BinaryOqlExpression($this->yystack[$this->yyidx + -2]->minor, $this->yystack[$this->yyidx + -1]->minor, $this->yystack[$this->yyidx + 0]->minor);     }
     function yy_r22(){ $this->_retvalue = new BinaryOqlExpression($this->yystack[$this->yyidx + -2]->minor, $this->yystack[$this->yyidx + -1]->minor, $this->yystack[$this->yyidx + 0]->minor);     }
-#line 1373 "oql-parser.php"
+#line 1389 "oql-parser.php"
 #line 104 "oql-parser.y"
 #line 104 "oql-parser.y"
     function yy_r31(){
     function yy_r31(){
 	$this->_retvalue = new ListOqlExpression($this->yystack[$this->yyidx + -1]->minor);
 	$this->_retvalue = new ListOqlExpression($this->yystack[$this->yyidx + -1]->minor);
     }
     }
-#line 1378 "oql-parser.php"
+#line 1394 "oql-parser.php"
 #line 115 "oql-parser.y"
 #line 115 "oql-parser.y"
     function yy_r34(){
     function yy_r34(){
 	$this->_retvalue = array();
 	$this->_retvalue = array();
     }
     }
-#line 1383 "oql-parser.php"
+#line 1399 "oql-parser.php"
 #line 126 "oql-parser.y"
 #line 126 "oql-parser.y"
     function yy_r38(){ $this->_retvalue = new IntervalOqlExpression($this->yystack[$this->yyidx + -1]->minor, $this->yystack[$this->yyidx + 0]->minor);     }
     function yy_r38(){ $this->_retvalue = new IntervalOqlExpression($this->yystack[$this->yyidx + -1]->minor, $this->yystack[$this->yyidx + 0]->minor);     }
-#line 1386 "oql-parser.php"
+#line 1402 "oql-parser.php"
 #line 138 "oql-parser.y"
 #line 138 "oql-parser.y"
     function yy_r47(){ $this->_retvalue = new ScalarOqlExpression($this->yystack[$this->yyidx + 0]->minor);     }
     function yy_r47(){ $this->_retvalue = new ScalarOqlExpression($this->yystack[$this->yyidx + 0]->minor);     }
-#line 1389 "oql-parser.php"
+#line 1405 "oql-parser.php"
 #line 141 "oql-parser.y"
 #line 141 "oql-parser.y"
     function yy_r49(){ $this->_retvalue = new FieldOqlExpression($this->yystack[$this->yyidx + 0]->minor);     }
     function yy_r49(){ $this->_retvalue = new FieldOqlExpression($this->yystack[$this->yyidx + 0]->minor);     }
-#line 1392 "oql-parser.php"
+#line 1408 "oql-parser.php"
 #line 142 "oql-parser.y"
 #line 142 "oql-parser.y"
     function yy_r50(){ $this->_retvalue = new FieldOqlExpression($this->yystack[$this->yyidx + 0]->minor, $this->yystack[$this->yyidx + -2]->minor);     }
     function yy_r50(){ $this->_retvalue = new FieldOqlExpression($this->yystack[$this->yyidx + 0]->minor, $this->yystack[$this->yyidx + -2]->minor);     }
-#line 1395 "oql-parser.php"
+#line 1411 "oql-parser.php"
 #line 143 "oql-parser.y"
 #line 143 "oql-parser.y"
     function yy_r51(){ $this->_retvalue=$this->yystack[$this->yyidx + 0]->minor;     }
     function yy_r51(){ $this->_retvalue=$this->yystack[$this->yyidx + 0]->minor;     }
-#line 1398 "oql-parser.php"
+#line 1414 "oql-parser.php"
 #line 146 "oql-parser.y"
 #line 146 "oql-parser.y"
     function yy_r52(){ $this->_retvalue = new VariableOqlExpression(substr($this->yystack[$this->yyidx + 0]->minor, 1));     }
     function yy_r52(){ $this->_retvalue = new VariableOqlExpression(substr($this->yystack[$this->yyidx + 0]->minor, 1));     }
-#line 1401 "oql-parser.php"
+#line 1417 "oql-parser.php"
 #line 148 "oql-parser.y"
 #line 148 "oql-parser.y"
     function yy_r53(){
     function yy_r53(){
 	if ($this->yystack[$this->yyidx + 0]->minor[0] == '`')
 	if ($this->yystack[$this->yyidx + 0]->minor[0] == '`')
@@ -1407,13 +1423,13 @@ static public $yy_action = array(
 	}
 	}
 	$this->_retvalue = new OqlName($name, $this->m_iColPrev);
 	$this->_retvalue = new OqlName($name, $this->m_iColPrev);
     }
     }
-#line 1414 "oql-parser.php"
+#line 1430 "oql-parser.php"
 #line 160 "oql-parser.y"
 #line 160 "oql-parser.y"
     function yy_r54(){$this->_retvalue=$this->yystack[$this->yyidx + 0]->minor;    }
     function yy_r54(){$this->_retvalue=$this->yystack[$this->yyidx + 0]->minor;    }
-#line 1417 "oql-parser.php"
+#line 1433 "oql-parser.php"
 #line 161 "oql-parser.y"
 #line 161 "oql-parser.y"
     function yy_r55(){$this->_retvalue=stripslashes(substr($this->yystack[$this->yyidx + 0]->minor, 1, strlen($this->yystack[$this->yyidx + 0]->minor) - 2));    }
     function yy_r55(){$this->_retvalue=stripslashes(substr($this->yystack[$this->yyidx + 0]->minor, 1, strlen($this->yystack[$this->yyidx + 0]->minor) - 2));    }
-#line 1420 "oql-parser.php"
+#line 1436 "oql-parser.php"
 
 
     /**
     /**
      * placeholder for the left hand side in a reduce operation.
      * placeholder for the left hand side in a reduce operation.
@@ -1528,7 +1544,7 @@ static public $yy_action = array(
 #line 25 "oql-parser.y"
 #line 25 "oql-parser.y"
  
  
 throw new OQLParserException($this->m_sSourceQuery, $this->m_iLine, $this->m_iCol, $this->tokenName($yymajor), $TOKEN);
 throw new OQLParserException($this->m_sSourceQuery, $this->m_iLine, $this->m_iCol, $this->tokenName($yymajor), $TOKEN);
-#line 1536 "oql-parser.php"
+#line 1552 "oql-parser.php"
     }
     }
 
 
     /**
     /**
@@ -1680,7 +1696,7 @@ throw new OQLParserException($this->m_sSourceQuery, $this->m_iLine, $this->m_iCo
             }            
             }            
         } while ($yymajor != self::YYNOCODE && $this->yyidx >= 0);
         } while ($yymajor != self::YYNOCODE && $this->yyidx >= 0);
     }
     }
-}#line 211 "oql-parser.y"
+}#line 213 "oql-parser.y"
 
 
 
 
 class OQLParserException extends OQLException
 class OQLParserException extends OQLException
@@ -1745,4 +1761,4 @@ class OQLParser extends OQLParserRaw
 	}
 	}
 }
 }
 
 
-#line 1755 "oql-parser.php"
+#line 1771 "oql-parser.php"

+ 2 - 0
core/oql/oql-parser.y

@@ -164,6 +164,7 @@ str_value(A) ::= STRVAL(X). {A=stripslashes(substr(X, 1, strlen(X) - 2));}
 operator1(A) ::= num_operator1(X). {A=X;}
 operator1(A) ::= num_operator1(X). {A=X;}
 operator2(A) ::= num_operator2(X). {A=X;}
 operator2(A) ::= num_operator2(X). {A=X;}
 operator2(A) ::= str_operator(X). {A=X;}
 operator2(A) ::= str_operator(X). {A=X;}
+operator2(A) ::= REGEXP(X). {A=X;}
 operator2(A) ::= EQ(X). {A=X;}
 operator2(A) ::= EQ(X). {A=X;}
 operator2(A) ::= NOT_EQ(X). {A=X;}
 operator2(A) ::= NOT_EQ(X). {A=X;}
 operator3(A) ::= LOG_AND(X). {A=X;}
 operator3(A) ::= LOG_AND(X). {A=X;}
@@ -187,6 +188,7 @@ list_operator(A) ::= NOT_IN(X). {A=X;}
 func_name(A) ::= F_IF(X). { A=X; }
 func_name(A) ::= F_IF(X). { A=X; }
 func_name(A) ::= F_ELT(X). { A=X; }
 func_name(A) ::= F_ELT(X). { A=X; }
 func_name(A) ::= F_COALESCE(X). { A=X; }
 func_name(A) ::= F_COALESCE(X). { A=X; }
+func_name(A) ::= F_ISNULL(X). { A=X; }
 func_name(A) ::= F_CONCAT(X). { A=X; }
 func_name(A) ::= F_CONCAT(X). { A=X; }
 func_name(A) ::= F_SUBSTR(X). { A=X; }
 func_name(A) ::= F_SUBSTR(X). { A=X; }
 func_name(A) ::= F_TRIM(X). { A=X; }
 func_name(A) ::= F_TRIM(X). { A=X; }

+ 18 - 11
setup/email.test.php

@@ -158,18 +158,25 @@ function DisplayStep2(SetupWebPage $oP, $sFrom, $sTo)
 	$oEmail->SetRecipientFrom($sFrom);
 	$oEmail->SetRecipientFrom($sFrom);
 	$oEmail->SetSubject("Test iTop");
 	$oEmail->SetSubject("Test iTop");
 	$oEmail->SetBody("<p>Hello,</p><p>The email function is now working fine.</p><p>You may now be able to use the notification function.</p><p>iTop</p>");
 	$oEmail->SetBody("<p>Hello,</p><p>The email function is now working fine.</p><p>You may now be able to use the notification function.</p><p>iTop</p>");
-	$aIssues = $oEmail->send();
-	if (count($aIssues) > 0)
+	$iRes = $oEmail->Send($aIssues, true /* force synchronous exec */);
+	switch ($iRes)
 	{
 	{
-		foreach ($aIssues as $sError)
-		{
-			$oP->error($sError);
-		}
-		$oP->add("<button onClick=\"window.history.back();\"><< Back</button>\n");
-	}
-	else
-	{
-		$oP->ok("The email has been sent, you may now check that the email will arrive...");
+		case EMAIL_SEND_OK:
+			$oP->ok("The email has been sent, you may now check that the email will arrive...");
+			break;
+
+		case EMAIL_SEND_PENDING:
+			$oP->ok("Email queued");
+			$oP->add("<button onClick=\"window.history.back();\"><< Back</button>\n");
+			break;
+
+		case EMAIL_SEND_ERROR:
+			foreach ($aIssues as $sError)
+			{
+				$oP->error($sError);
+			}
+			$oP->add("<button onClick=\"window.history.back();\"><< Back</button>\n");
+			break;
 	}
 	}
 }
 }
 
 

+ 71 - 22
test/testlist.inc.php

@@ -2997,35 +2997,36 @@ class TestTriggerAndEmail extends TestBizModel
 
 
 	protected function DoExecute()
 	protected function DoExecute()
 	{
 	{
-		$oMyPerson = MetaModel::NewObject("bizPerson");
+		$oMyPerson = MetaModel::NewObject("Person");
 		$oMyPerson->Set("name", "testemail1");
 		$oMyPerson->Set("name", "testemail1");
+		$oMyPerson->Set("first_name", "theodore");
 		$oMyPerson->Set("org_id", "1");
 		$oMyPerson->Set("org_id", "1");
-		$oMyPerson->Set("email", "romain.quetiez@hp.com");
+		$oMyPerson->Set("email", "romain.quetiez@combodo.com");
 		$iPersonId = $this->ObjectToDB($oMyPerson, true);
 		$iPersonId = $this->ObjectToDB($oMyPerson, true);
 
 
-		$oMyPerson = MetaModel::NewObject("bizPerson");
+		$oMyPerson = MetaModel::NewObject("Person");
 		$oMyPerson->Set("name", "testemail2");
 		$oMyPerson->Set("name", "testemail2");
+		$oMyPerson->Set("first_name", "theodore");
 		$oMyPerson->Set("org_id", "1");
 		$oMyPerson->Set("org_id", "1");
-		$oMyPerson->Set("email", "denis.flaven@hp.com");
+		$oMyPerson->Set("email", "denis.flaven@combodo.com");
 		$iPersonId = $this->ObjectToDB($oMyPerson, true);
 		$iPersonId = $this->ObjectToDB($oMyPerson, true);
 
 
-		$oMyPerson = MetaModel::NewObject("bizPerson");
+		$oMyPerson = MetaModel::NewObject("Person");
 		$oMyPerson->Set("name", "testemail3");
 		$oMyPerson->Set("name", "testemail3");
+		$oMyPerson->Set("first_name", "theodore");
 		$oMyPerson->Set("org_id", "1");
 		$oMyPerson->Set("org_id", "1");
-		$oMyPerson->Set("email", "erwan.taloc@hp.com");
+		$oMyPerson->Set("email", "erwan.taloc@combodo.com");
 		$iPersonId = $this->ObjectToDB($oMyPerson, true);
 		$iPersonId = $this->ObjectToDB($oMyPerson, true);
 
 
-		$oMyServer = MetaModel::NewObject("bizServer");
+		$oMyServer = MetaModel::NewObject("Server");
 		$oMyServer->Set("name", "wfr.terminator.com");
 		$oMyServer->Set("name", "wfr.terminator.com");
-		$oMyServer->Set("severity", "low");
 		$oMyServer->Set("status", "production");
 		$oMyServer->Set("status", "production");
 		$oMyServer->Set("org_id", 2);
 		$oMyServer->Set("org_id", 2);
-		$oMyServer->Set("location_id", 2);
 		$iServerId = $this->ObjectToDB($oMyServer, true);
 		$iServerId = $this->ObjectToDB($oMyServer, true);
 
 
 		$oMyTrigger = MetaModel::NewObject("TriggerOnStateEnter");
 		$oMyTrigger = MetaModel::NewObject("TriggerOnStateEnter");
 		$oMyTrigger->Set("description", "Testor");
 		$oMyTrigger->Set("description", "Testor");
-		$oMyTrigger->Set("target_class", "bizServer");
+		$oMyTrigger->Set("target_class", "Server");
 		$oMyTrigger->Set("state", "Shipped");
 		$oMyTrigger->Set("state", "Shipped");
 		$iTriggerId = $this->ObjectToDB($oMyTrigger, true);
 		$iTriggerId = $this->ObjectToDB($oMyTrigger, true);
 
 
@@ -3035,9 +3036,9 @@ class TestTriggerAndEmail extends TestBizModel
 		(
 		(
 			$oMyTrigger,
 			$oMyTrigger,
 			'test',
 			'test',
-			"SELECT bizPerson WHERE naime = 'Dali'",
-			"SELECT bizServer",
-			'romain.quetiez@hp.com'
+			"SELECT Person WHERE naime = 'Dali'",
+			"SELECT Server",
+			'romain.quetiez@combodo.com'
 		);
 		);
 
 
 		// Error: no recipient
 		// Error: no recipient
@@ -3048,7 +3049,7 @@ class TestTriggerAndEmail extends TestBizModel
 			'test',
 			'test',
 			"",
 			"",
 			"",
 			"",
-			'romain.quetiez@hp.com'
+			'romain.quetiez@combodo.com'
 		);
 		);
 
 
 		// Test
 		// Test
@@ -3057,9 +3058,9 @@ class TestTriggerAndEmail extends TestBizModel
 		(
 		(
 			$oMyTrigger,
 			$oMyTrigger,
 			'test',
 			'test',
-			"SELECT bizPerson WHERE name LIKE 'testemail%'",
-			"SELECT bizPerson",
-			'romain.quetiez@hp.com'
+			"SELECT Person WHERE name LIKE 'testemail%'",
+			"SELECT Person",
+			'romain.quetiez@combodo.com'
 		);
 		);
 
 
 		// Test failing because of a wrong test recipient address
 		// Test failing because of a wrong test recipient address
@@ -3068,7 +3069,7 @@ class TestTriggerAndEmail extends TestBizModel
 		(
 		(
 			$oMyTrigger,
 			$oMyTrigger,
 			'test',
 			'test',
-			"SELECT bizPerson WHERE name LIKE 'testemail%'",
+			"SELECT Person WHERE name LIKE 'testemail%'",
 			"",
 			"",
 			'toto@walibi.bg'
 			'toto@walibi.bg'
 		);
 		);
@@ -3079,9 +3080,9 @@ class TestTriggerAndEmail extends TestBizModel
 		(
 		(
 			$oMyTrigger,
 			$oMyTrigger,
 			'enabled',
 			'enabled',
-			"SELECT bizPerson WHERE name LIKE 'testemail%'",
+			"SELECT Person WHERE name LIKE 'testemail%'",
 			"",
 			"",
-			'romain.quetiez@hp.com'
+			'romain.quetiez@combodo.com'
 		);
 		);
 
 
 		// Does nothing, because it is disabled
 		// Does nothing, because it is disabled
@@ -3090,9 +3091,9 @@ class TestTriggerAndEmail extends TestBizModel
 		(
 		(
 			$oMyTrigger,
 			$oMyTrigger,
 			'disabled',
 			'disabled',
-			"SELECT bizPerson WHERE name = 'testemail%'",
+			"SELECT Person WHERE name = 'testemail%'",
 			"",
 			"",
-			'romain.quetiez@hp.com'
+			'romain.quetiez@combodo.com'
 		);
 		);
 
 
 		$oMyTrigger->DoActivate($oMyServer->ToArgs('this'));
 		$oMyTrigger->DoActivate($oMyServer->ToArgs('this'));
@@ -3219,4 +3220,52 @@ class TestSetLinkset extends TestBizModel
 	}
 	}
 }
 }
 
 
+class TestEmailAsynchronous extends TestBizModel
+{
+	static public function GetName()
+	{
+		return 'Itop - Asynchronous email';
+	}
+
+	static public function GetDescription()
+	{
+		return 'Queues a request to send an email';
+	}
+
+	static public function GetConfigFile() {return '/config-itop.php';}
+
+	protected function DoExecute()
+	{
+		for ($i = 0 ; $i < 2 ; $i++)
+		{
+			$oMail = new Email();
+			$oMail->SetRecipientTO('romain.quetiez@combodo.com');
+			//$oMail->SetRecipientFrom('romain.quetiez@combodo.com');
+			$oMail->SetRecipientCC('romainquetiez@yahoo.fr');
+			$oMail->SetSubject('automated test - '.$i);
+			$oMail->SetBody('this is one is entirely working fine '.time());
+			$iRes = $oMail->Send($aIssues, false);
+			switch ($iRes)
+			{
+				case EMAIL_SEND_OK:
+					echo "EMAIL_SEND_OK<br/>\n";
+					break;
+
+				case EMAIL_SEND_PENDING:
+					echo "EMAIL_SEND_PENDING<br/>\n";
+					break;
+
+				case EMAIL_SEND_ERROR:
+					echo "EMAIL_SEND_ERROR: <br/>\n";
+					foreach($aIssues as $sIssue)
+					{
+						echo "Issue: $sIssue<br/>\n";
+					}
+					break;
+			}
+		}
+		
+	}
+}
+
 ?>
 ?>