Subversion Repositories oidplus

Compare Revisions

Regard whitespace Rev 1266 → Rev 1267

/trunk/includes/classes/OIDplus.class.php
1796,7 → 1796,7
$pubKey = OIDplus::getSystemPublicKey();
if (!verify_private_public_key($privKey, $pubKey)) {
if ($pubKey) {
OIDplus::logger()->log("[WARN]A!", "The private/public key-pair is broken. A new key-pair will now be generated for your system. Your System-ID will change.");
OIDplus::logger()->log("V2:[WARN]A", "The private/public key-pair is broken. A new key-pair will now be generated for your system. Your System-ID will change.");
}
 
$pkey_config = array(
1833,7 → 1833,7
OIDplus::config()->setValue('oidplus_public_key', $pubKey);
 
// Log the new system ID
OIDplus::logger()->log("[INFO]A!", "A new private/public key-pair for your system had been generated. Your SystemID is now %1", $system_id);
OIDplus::logger()->log("V2:[INFO]A", "A new private/public key-pair for your system had been generated. Your SystemID is now %1", $system_id);
}
} else {
$passphrase = self::getPrivKeyPassphrase();
1844,7 → 1844,7
$passphrase = self::getPrivKeyPassphrase();
if ($passphrase !== false) {
$privKey = encrypt_private_key($privKey, $passphrase);
OIDplus::logger()->log("[INFO]A!", "The private/public key-pair has been upgraded to an encrypted key-pair. The key is saved in %1", self::getPrivKeyPassphraseFilename());
OIDplus::logger()->log("V2:[INFO]A", "The private/public key-pair has been upgraded to an encrypted key-pair. The key is saved in %1", self::getPrivKeyPassphraseFilename());
OIDplus::config()->setValue('oidplus_private_key', $privKey);
}
}
1904,7 → 1904,7
if (($ver_prev) && ($ver_now != $ver_prev)) {
// TODO: Problem: When the system was updated using SVN or GIT in the console, then the IP address of the next random visitor of the website is logged!
// Idea: Maybe we should extend the mask code with some kind of magic constant "[NO_IP]", so that no IP is logged for that event?
OIDplus::logger()->log("[INFO]A!", "Detected system version change from '%1' to '%2'", $ver_prev, $ver_now);
OIDplus::logger()->log("V2:[INFO]A", "Detected system version change from '%1' to '%2'", $ver_prev, $ver_now);
 
// Just to be sure, recanonize objects (we don't do it at every page visit due to performance reasons)
self::recanonizeObjects();
2468,7 → 2468,7
OIDplus::db()->query("update ###asn1id set oid = ? where oid = ?", array($idb, $ida));
OIDplus::db()->query("update ###iri set oid = ? where oid = ?", array($idb, $ida));
OIDplus::db()->query("update ###log_object set object = ? where object = ?", array($idb, $ida));
OIDplus::logger()->log("[INFO]A!", "Object name '%1' has been changed to '%2' during re-canonization", $ida, $idb);
OIDplus::logger()->log("V2:[INFO]A", "Object name '%1' has been changed to '%2' during re-canonization", $ida, $idb);
if (OIDplus::db()->transaction_supported()) OIDplus::db()->transaction_commit();
} catch (\Exception $e) {
if (OIDplus::db()->transaction_supported()) OIDplus::db()->transaction_rollback();
/trunk/includes/classes/OIDplusAuthUtils.class.php
179,11 → 179,12
}
 
/**
* @param string $email
* @param string|OIDplusRA $ra
* @return bool
* @throws OIDplusException
*/
public function isRaLoggedIn(string $email): bool {
public function isRaLoggedIn($ra): bool {
$email = $ra instanceof OIDplusRA ? $ra->raEmail() : $ra;
$acs = $this->getAuthContentStore();
if (is_null($acs)) return false;
return $acs->isRaLoggedIn($email);
224,7 → 225,7
$logmsg = "RA '$email' logged in";
if ($origin != '') $logmsg .= " via $origin";
if ($loginfo != '') $logmsg .= " ($loginfo)";
OIDplus::logger()->log("[OK]RA(%1)!", "%2", $email, $logmsg);
OIDplus::logger()->log("V2:[OK]RA(%1)", "%2", $email, $logmsg);
}
 
/**
239,7 → 240,7
if (is_null($acs)) return;
$acs->raLogoutEx($email, $loginfo);
 
OIDplus::logger()->log("[OK]RA(%1)!", "RA '%1' logged out (%2)", $email, $loginfo);
OIDplus::logger()->log("V2:[OK]RA(%1)", "RA '%1' logged out (%2)", $email, $loginfo);
 
if (($this->raNumLoggedIn() == 0) && (!$this->isAdminLoggedIn())) {
// Nobody logged in anymore. Destroy session cookie to make GDPR people happy
354,7 → 355,7
$logmsg = "Admin logged in";
if ($origin != '') $logmsg .= " via $origin";
if ($loginfo != '') $logmsg .= " ($loginfo)";
OIDplus::logger()->log("[OK]A!", "%1", $logmsg);
OIDplus::logger()->log("V2:[OK]A", "%1", $logmsg);
}
 
/**
376,7 → 377,7
$acs->activate();
}
 
OIDplus::logger()->log("[OK]A!", "Admin logged out (%1)", $loginfo);
OIDplus::logger()->log("V2:[OK]A", "Admin logged out (%1)", $loginfo);
}
 
// Authentication keys for validating arguments (e.g. sent by mail)
/trunk/includes/classes/OIDplusLogger.class.php
26,15 → 26,30
class OIDplusLogger extends OIDplusBaseClass {
 
/**
* This function splits a mask code containing multiple components
* (delimited by '+' or '/') in single components
* It takes care that '+' and '/' inside brackets won't be used to split the codes
* This method splits a mask code containing multiple components (delimited by '+') into single components
* It takes care that '+' inside brackets isn't be used to split the codes
* Also, brackets can be escaped.
* The severity block (optional, must be standing in front of a component)
* is handled too. Inside the severity block, you may only use '/' to split components.
* The severity block will be implicitly repeated from the previous components if a component
* does not feature one.
*
* @param string $maskcode A maskcode, e.g. [INFO]OID(2.999)
* @return array|false An array of [$severity,$target],
* where $severity is 'INFO' or [$online,$offline] like ['INFO','INFO']
* and $target is like ['A'], ['OID', '2.999'], etc.
*/
public static function parse_maskcode(string $maskcode) {
$out = array();
$sevs = array(); // Note: The severity block will repeat for the next components if not changed explicitly
 
if (!str_starts_with($maskcode,'V2:')) {
return false;
} else {
$maskcode = substr($maskcode, 3);
}
 
// Step 1: Split severities from the rest of the maskcodes
/*
* "[ERR]AAA(BBB)+CCC(DDD)" ==> array(
* array(array("ERR"),"AAA(BBB)"),
* array(array("ERR"),"CCC(DDD)")
43,28 → 58,22
* array(array("INFO"),"AAA(B+BB)"),
* array(array("WARN"),"CCC(DDD)")
* )
* "[?WARN/!OK] AAA(B\)BB)+CCC(DDD)" ==> array(
* array(array("?WARN", "!OK"),"AAA(B\)BB)"),
* array(array("?WARN", "!OK"),"CCC(DDD)")
* "[OK/WARN] AAA(B\)BB)+CCC(DDD)" ==> array(
* array(array("OK", "WARN"),"AAA(B\)BB)"),
* array(array("OK", "WARN"),"CCC(DDD)")
* )
* @param string $maskcodes
* @return array|false
*/
private function split_maskcodes(string $maskcodes) {
$out = array();
$sevs = array(); // Note: The severity block will repeat for the next components if not changed explicitly
 
$code = '';
$sev = '';
$bracket_level = 0;
$is_escaping = false;
$inside_severity_block = false;
for ($i=0; $i<strlen($maskcodes); $i++) {
$char = $maskcodes[$i];
for ($i=0; $i<strlen($maskcode); $i++) {
$char = $maskcode[$i];
 
if ($inside_severity_block) {
// Severity block (optional)
// e.g. [?WARN/!OK] ==> $sevs = array("?WARN", "!OK")
// e.g. [OK/WARN] ==> $sevs = array("OK", "WARN")
if ($char == '\\') {
if ($is_escaping) {
$is_escaping = false;
146,7 → 155,7
}
$code .= $char;
}
else if ((($char == '+') || ($char == '/')) && ($bracket_level == 0)) {
else if (($char == '+') && ($bracket_level == 0)) {
if ($is_escaping) {
$is_escaping = false;
$code .= $char;
167,7 → 176,59
}
if ($code != '') $out[] = array($sevs,$code);
if ($inside_severity_block) return false;
unset($sevs);
 
// Step 2: Process severities (split to online/offline)
// Allowed: ['INFO'] or ['INFO', 'INFO']
// Disallow: ['NONE'] and ['NONE', 'NONE']
foreach ($out as &$component) {
$sev_fixed = null;
$sevs = $component[0];
if (count($sevs) == 1) {
if ($sevs[0] == 'NONE') return false; // meaningless component
try { self::convertSeverity($sevs[0]); } catch (\Exception $e) { return false; } // just checking for valid value
$sev_fixed = $sevs[0];
} else if (count($sevs) == 2) {
$sev_online = $sevs[0];
$sev_offline = $sevs[1];
if (($sev_online == 'NONE') && ($sev_offline == 'NONE')) return false; // meaningless component
try { self::convertSeverity($sev_online); } catch (\Exception $e) { return false; } // just checking for valid value
try { self::convertSeverity($sev_offline); } catch (\Exception $e) { return false; } // just checking for valid value
$sev_fixed = [$sev_online, $sev_offline];
} else {
return false;
}
$component[0] = $sev_fixed;
}
 
// Step 3: Process target (split to type and value)
// 'OID(2.999)' becomes ['OID', '2.999']
// 'A' becomes ['A']
foreach ($out as &$component) {
$m = array();
if (preg_match('@^([^()]+)\((.+)\)$@ismU', $component[1], $m)) {
$type = $m[1];
$value = $m[2];
$component[1] = [$type, $value];
} else {
$component[1] = [$component[1]];
}
}
 
// Some other checks (it makes it easier to validate the maskcodes with dev tools)
foreach ($out as list($severity,$target)) {
if (($target[0] == 'OID') || ($target[0] == 'SUPOID')) {
if (is_array($severity)) return false; // OID and SUPOID logger mask cannot have online/offline severity
if (empty($target[1])) return false; /** @phpstan-ignore-line */
} else if (($target[0] == 'OIDRA') || ($target[0] == 'SUPOIDRA') || ($target[0] == 'RA')) {
if (empty($target[1])) return false;
} else if ($target[0] == 'A') {
if (!empty($target[1])) return false;
} else {
return false;
}
}
 
return $out;
}
 
187,238 → 248,232
}
 
/**
* @param string $maskcodes A description of the mask-codes can be found in doc/developer_notes/logger_maskcodes.md
* @param string $maskcode A description of the mask-codes can be found in doc/developer_notes/logger_maskcodes.md
* @param string $message The message of the event
* @param mixed ...$sprintfArgs If used, %1..%n in $maskcodes and $message will be replaced, like _L() does.
* @param mixed ...$sprintfArgs If used, %1..%n in $maskcode and $message will be replaced, like _L() does.
* @return bool
* @throws OIDplusException
*/
public function log(string $maskcodes, string $message, ...$sprintfArgs): bool {
public function log(string $maskcode, string $message, ...$sprintfArgs): bool {
$this->reLogMissing(); // try to re-log failed requests
 
$maskcodes = my_vsprintf($maskcodes, $sprintfArgs);
$sprintfArgs_Escaped = array();
foreach ($sprintfArgs as $arg) {
// Inside an severity block, e.g. INFO of [INFO], we would need to escape []/\
// In the value, e.g. 2.999 of OID(2.999), we would need to escape ()+\
// Since there seems to be no meaningful use-case for parametrized severities, we only escape the value
$sprintfArgs_Escaped[] = str_replace(array('(',')','+','\\'), array('\\(', '\\)', '\\+', '\\\\'), $arg);
}
 
$maskcode = my_vsprintf($maskcode, $sprintfArgs_Escaped);
$message = my_vsprintf($message, $sprintfArgs);
 
if (strpos(str_replace('%%','',$maskcodes),'%') !== false) {
if (strpos(str_replace('%%','',$maskcode),'%') !== false) {
throw new OIDplusException(_L('Unresolved wildcards in logging maskcode'));
}
 
return $this->log_internal($maskcodes, $message, true);
return $this->log_internal($maskcode, $message, true);
}
 
/**
* @param string $maskcodes
* @param string $message
* @param bool $allow_delayed_log
* @return bool
* @param string $sev_name
* @return int
* @throws OIDplusConfigInitializationException
* @throws OIDplusException
*/
private function log_internal(string $maskcodes, string $message, bool $allow_delayed_log): bool {
$loggerPlugins = OIDplus::getLoggerPlugins();
if (count($loggerPlugins) == 0) {
// The plugin might not be initialized in OIDplus::init()
// yet. Remember the log entries for later submission during
// OIDplus::init();
if ($allow_delayed_log) $this->missing_plugin_queue[] = array($maskcodes, $message);
return false;
}
private static function convertSeverity(string $sev_name): int {
//$sev_name = strtoupper($sev_name);
 
// What is a mask code?
// A mask code gives information about the log event:
// 1. The severity (info, warning, error)
// 2. In which logbook(s) the event shall be placed
// Example:
// The event would be:
// "Person 'X' moves from house 'A' to house 'B'"
// This event would affect the person X and the two houses,
// so, instead of logging into 3 logbooks separately,
// you would create a mask code that tells the system
// to put the message into the logbooks of person X,
// house A, and house B.
switch ($sev_name) {
case 'NONE':
// Do not log anything. Used for online/offline severity pairs
return -1;
 
$logEvent = new OIDplusLogEvent($message);
 
// A mask code with multiple components is split into single codes
// using '+' or '/', e.g. "OID(x)+RA(x)" would be split to "OID(x)" and "RA(x)"
// which would result in the message being placed in the logbook of OID x,
// and the logbook of the RA owning OID x.
$maskcodes_ary = $this->split_maskcodes($maskcodes);
if ($maskcodes_ary === false) {
throw new OIDplusException(_L('Invalid maskcode "%1" (failed to split)',$maskcodes));
}
foreach ($maskcodes_ary as list($sevs,$maskcode)) {
// At the beginning of each mask code, you must define a severity.
// If you have a mask code with multiple components, you don't have to place the
// severity for each component. You can just leave it at the beginning.
// e.g. "[WARN]OID(x)+RA(x)" is equal to "[WARN]OID(x)+[WARN]RA(x)"
// You can also put different severities for the components:
// e.g. "[INFO]OID(x)+[WARN]RA(x)" would be a info for the OID, but a warning for the RA.
// If you want to make the severity dependent on wheather the user is logged in or not,
// prepend "?" or "!" and use '/' as delimiter
// Example: "[?WARN/!OK]RA(x)" means: If RA is not logged in, it is a warning; if it is logged in, it is an success
$severity = 0; // default severity = none
$severity_online = 0;
foreach ($sevs as $sev) {
switch (strtoupper($sev)) {
// [OK] = Success
// Numeric value: 1
// Rule of thumb: YOU have done something and it was successful
case '?OK':
$severity_online = 1;
break;
case '!OK':
case 'OK':
$severity = 1;
break;
return 1;
 
// [INFO] = Informational
// Numeric value: 2
// Rule of thumb: Someone else has done something (that affects you) and it was successful
case '?INFO':
$severity_online = 2;
break;
case '!INFO':
case 'INFO':
$severity = 2;
break;
return 2;
 
// [WARN] = Warning
// Numeric value: 3
// Rule of thumb: Something happened (probably someone did something) and it affects you
case '?WARN':
$severity_online = 3;
break;
case '!WARN':
case 'WARN':
$severity = 3;
break;
return 3;
 
// [ERR] = Error
// Numeric value: 4
// Rule of thumb: Something failed (probably someone did something) and it affects you
case '?ERR':
$severity_online = 4;
break;
case '!ERR':
case 'ERR':
$severity = 4;
break;
return 4;
 
// [CRIT] = Critical
// Numeric value: 5
// Rule of thumb: Something happened (probably someone did something) which is not an error,
// but some critical situation (e.g. hardware failure), and it affects you
case '?CRIT':
$severity_online = 5;
break;
case '!CRIT':
case 'CRIT':
$severity = 5;
break;
return 5;
 
default:
throw new OIDplusException(_L('Invalid maskcode "%1" (Unknown severity "%2")',$maskcodes,$sev));
throw new OIDplusException(_L('Unknown severity "%1" in logger maskcode',$sev_name));
}
}
 
/**
* @param string $maskcode
* @param string $message
* @param bool $allow_delayed_log
* @return bool
* @throws OIDplusException
*/
private function log_internal(string $maskcode, string $message, bool $allow_delayed_log): bool {
$loggerPlugins = OIDplus::getLoggerPlugins();
if (count($loggerPlugins) == 0) {
// The plugin might not be initialized in OIDplus::init()
// yet. Remember the log entries for later submission during
// OIDplus::init();
if ($allow_delayed_log) $this->missing_plugin_queue[] = array($maskcode, $message);
return false;
}
 
$logEvent = new OIDplusLogEvent($message);
 
$maskcode_ary = self::parse_maskcode($maskcode);
if ($maskcode_ary === false) {
throw new OIDplusException(_L('Invalid maskcode "%1" (failed to parse or has invalid data)',$maskcode));
}
foreach ($maskcode_ary as list($severity,$target)) {
if ($target[0] == 'OID') {
// OID(x) Save log entry into the logbook of: Object "x"
$m = array();
if (preg_match('@^OID\((.+)\)$@ismU', $maskcode, $m)) {
$object_id = $m[1];
$logEvent->addTarget(new OIDplusLogTargetObject($severity, $object_id));
if ($object_id == '') throw new OIDplusException(_L('OID logger mask requires OID'));
$object_id = $target[1];
assert(!is_array($severity));
$obj = OIDplusObject::parse($object_id);
if (!$obj) throw new OIDplusException(_L('OID logger mask: Invalid object %1',$object_id));
if (($severity_int = self::convertSeverity($severity)) >= 0) {
$logEvent->addTarget(new OIDplusLogTargetObject($severity_int, $object_id));
}
}
 
else if ($target[0] == 'SUPOID') {
// SUPOID(x) Save log entry into the logbook of: Parent of object "x"
else if (preg_match('@^SUPOID\((.+)\)$@ismU', $maskcode, $m)) {
$object_id = $m[1];
if ($object_id == '') throw new OIDplusException(_L('SUPOID logger mask requires OID'));
$object_id = $target[1];
assert(!is_array($severity));
$obj = OIDplusObject::parse($object_id);
if ($obj) {
if (!$obj) throw new OIDplusException(_L('SUPOID logger mask: Invalid object %1',$object_id));
if ($objParent = $obj->getParent()) {
$parent = $objParent->nodeId();
$logEvent->addTarget(new OIDplusLogTargetObject($severity, $parent));
if (($severity_int = self::convertSeverity($severity)) >= 0) {
$logEvent->addTarget(new OIDplusLogTargetObject($severity_int, $parent));
}
} else {
//throw new OIDplusException(_L('%1 has no parent',$object_id));
}
} else {
throw new OIDplusException(_L('SUPOID logger mask: Invalid object %1',$object_id));
}
}
 
// OIDRA(x)? Save log entry into the logbook of: Logged in RA of object "x"
// Remove or replace "?" by "!" if the entity does not need to be logged in
else if (preg_match('@^OIDRA\((.+)\)([\?\!])$@ismU', $maskcode, $m)) {
$object_id = $m[1];
$ra_need_login = $m[2] == '?';
if ($object_id == '') throw new OIDplusException(_L('OIDRA logger mask requires OID'));
else if ($target[0] == 'OIDRA') {
// OIDRA(x) Save log entry into the logbook of: Logged in RA of object "x"
$object_id = $target[1];
$obj = OIDplusObject::parse($object_id);
if ($obj) {
if ($ra_need_login) {
foreach (OIDplus::authUtils()->loggedInRaList() as $ra) {
if ($obj->userHasWriteRights($ra)) $logEvent->addTarget(new OIDplusLogTargetUser($severity_online, $ra->raEmail()));
if (!$obj) throw new OIDplusException(_L('OIDRA logger mask: Invalid object "%1"', $object_id));
if (!is_array($severity)) {
$severity_online = $severity;
$severity_offline = $severity;
} else {
$severity_online = $severity[0];
$severity_offline = $severity[1];
}
} else {
// $logEvent->addTarget(new OIDplusLogTargetUser($severity, $obj->getRa()->raEmail()));
foreach (OIDplusRA::getAllRAs() as $ra) {
if ($obj->userHasWriteRights($ra)) $logEvent->addTarget(new OIDplusLogTargetUser($severity, $ra->raEmail()));
if ($obj->userHasWriteRights($ra)) {
if (OIDplus::authUtils()->isRaLoggedIn($ra)) {
if (($severity_online_int = self::convertSeverity($severity_online)) >= 0) {
$logEvent->addTarget(new OIDplusLogTargetUser($severity_online_int, $ra->raEmail()));
}
}
} else {
throw new OIDplusException(_L('OIDRA logger mask: Invalid object "%1"',$object_id));
if (($severity_offline_int = self::convertSeverity($severity_offline)) >= 0) {
$logEvent->addTarget(new OIDplusLogTargetUser($severity_offline_int, $ra->raEmail()));
}
}
}
}
}
 
// SUPOIDRA(x)? Save log entry into the logbook of: Logged in RA that owns the superior object of "x"
// Remove or replace "?" by "!" if the entity does not need to be logged in
else if (preg_match('@^SUPOIDRA\((.+)\)([\?\!])$@ismU', $maskcode, $m)) {
$object_id = $m[1];
$ra_need_login = $m[2] == '?';
if ($object_id == '') throw new OIDplusException(_L('SUPOIDRA logger mask requires OID'));
else if ($target[0] == 'SUPOIDRA') {
// SUPOIDRA(x) Save log entry into the logbook of: Logged in RA that owns the superior object of "x"
$object_id = $target[1];
$obj = OIDplusObject::parse($object_id);
if ($obj) {
if ($ra_need_login) {
foreach (OIDplus::authUtils()->loggedInRaList() as $ra) {
if ($obj->userHasParentalWriteRights($ra)) $logEvent->addTarget(new OIDplusLogTargetUser($severity_online, $ra->raEmail()));
if (!$obj) throw new OIDplusException(_L('SUPOIDRA logger mask: Invalid object "%1"',$object_id));
if (!is_array($severity)) {
$severity_online = $severity;
$severity_offline = $severity;
} else {
$severity_online = $severity[0];
$severity_offline = $severity[1];
}
} else {
if ($objParent = $obj->getParent()) {
// $logEvent->addTarget(new OIDplusLogTargetUser($severity, $objParent->getRa()->raEmail()));
foreach (OIDplusRA::getAllRAs() as $ra) {
if ($obj->userHasParentalWriteRights($ra)) $logEvent->addTarget(new OIDplusLogTargetUser($severity, $ra->raEmail()));
if ($obj->userHasParentalWriteRights($ra)) {
if (OIDplus::authUtils()->isRaLoggedIn($ra)) {
if (($severity_online_int = self::convertSeverity($severity_online)) >= 0) {
$logEvent->addTarget(new OIDplusLogTargetUser($severity_online_int, $ra->raEmail()));
}
} else {
//throw new OIDplusException(_L('%1 has no parent, therefore also no parent RA',$object_id));
if (($severity_offline_int = self::convertSeverity($severity_offline)) >= 0) {
$logEvent->addTarget(new OIDplusLogTargetUser($severity_offline_int, $ra->raEmail()));
}
}
} else {
throw new OIDplusException(_L('SUPOIDRA logger mask: Invalid object "%1"',$object_id));
}
}
}
 
// RA(x)? Save log entry into the logbook of: Logged in RA "x"
// Remove or replace "?" by "!" if the entity does not need to be logged in
else if (preg_match('@^RA\((.*)\)([\?\!])$@ismU', $maskcode, $m)) {
$ra_email = $m[1];
$ra_need_login = $m[2] == '?';
if (!empty($ra_email)) {
if ($ra_need_login && OIDplus::authUtils()->isRaLoggedIn($ra_email)) {
$logEvent->addTarget(new OIDplusLogTargetUser($severity_online, $ra_email));
} else if (!$ra_need_login) {
$logEvent->addTarget(new OIDplusLogTargetUser($severity, $ra_email));
else if ($target[0] == 'RA') {
// RA(x) Save log entry into the logbook of: Logged in RA "x"
$ra_email = $target[1];
if (!is_array($severity)) {
$severity_online = $severity;
$severity_offline = $severity;
} else {
$severity_online = $severity[0];
$severity_offline = $severity[1];
}
if (OIDplus::authUtils()->isRaLoggedIn($ra_email)) {
if (($severity_online_int = self::convertSeverity($severity_online)) >= 0) {
$logEvent->addTarget(new OIDplusLogTargetUser($severity_online_int, $ra_email));
}
} else {
if (($severity_offline_int = self::convertSeverity($severity_offline)) >= 0) {
$logEvent->addTarget(new OIDplusLogTargetUser($severity_offline_int, $ra_email));
}
}
}
 
// A? Save log entry into the logbook of: A logged in admin
// Remove or replace "?" by "!" if the entity does not need to be logged in
else if (preg_match('@^A([\?\!])$@imU', $maskcode, $m)) {
$admin_need_login = $m[1] == '?';
if ($admin_need_login && OIDplus::authUtils()->isAdminLoggedIn()) {
$logEvent->addTarget(new OIDplusLogTargetUser($severity_online, 'admin'));
} else if (!$admin_need_login) {
$logEvent->addTarget(new OIDplusLogTargetUser($severity, 'admin'));
else if ($target[0] == 'A') {
// A Save log entry into the logbook of: A logged in admin
if (!is_array($severity)) {
$severity_online = $severity;
$severity_offline = $severity;
} else {
$severity_online = $severity[0];
$severity_offline = $severity[1];
}
if (OIDplus::authUtils()->isAdminLoggedIn()) {
if (($severity_online_int = self::convertSeverity($severity_online)) >= 0) {
$logEvent->addTarget(new OIDplusLogTargetUser($severity_online_int, 'admin'));
}
} else {
if (($severity_offline_int = self::convertSeverity($severity_offline)) >= 0) {
$logEvent->addTarget(new OIDplusLogTargetUser($severity_offline_int, 'admin'));
}
}
}
 
// Unexpected
else {
throw new OIDplusException(_L('Unexpected logger component "%1" in mask code "%2"',$maskcode,$maskcodes));
throw new OIDplusException(_L('Unexpected logger component type "%1" in mask code "%2"',$target[0],$maskcode));
}
}