mirror of
https://gitlab.easter-eggs.com/ee/ldapsaisie.git
synced 2024-11-22 18:09:06 +01:00
LScli autocompleter: fix handling quoted arguments
This commit is contained in:
parent
f277528400
commit
a21b40d706
3 changed files with 102 additions and 40 deletions
4
debian/ldapsaisie.bash-completion
vendored
4
debian/ldapsaisie.bash-completion
vendored
|
@ -18,5 +18,9 @@ _ldapsaisie()
|
||||||
COMPREPLY[i]=${COMPREPLY[i]#"$equal_word"}
|
COMPREPLY[i]=${COMPREPLY[i]#"$equal_word"}
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
|
# If only one answer and it ending by "=", do not add space
|
||||||
|
if [[ ${#COMPREPLY[@]} -eq 1 ]] && [[ ${COMPREPLY[0]} == *= || ${COMPREPLY[0]} == *=\' || ${COMPREPLY[0]} == *=\" ]]; then
|
||||||
|
compopt -o nospace
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
complete -o default -F _ldapsaisie ldapsaisie
|
complete -o default -F _ldapsaisie ldapsaisie
|
||||||
|
|
|
@ -387,16 +387,19 @@ class LScli extends LSlog_staticLoggerClass {
|
||||||
$command_arg_num = null;
|
$command_arg_num = null;
|
||||||
$command_args = array();
|
$command_args = array();
|
||||||
for ($i=1; $i < count($comp_words); $i++) {
|
for ($i=1; $i < count($comp_words); $i++) {
|
||||||
if (array_key_exists($comp_words[$i], self :: $commands)) {
|
$unescaped_comp_word = $comp_words[$i];
|
||||||
|
self :: unquote_word($unescaped_comp_word);
|
||||||
|
if (array_key_exists($unescaped_comp_word, self :: $commands)) {
|
||||||
if (!$command) {
|
if (!$command) {
|
||||||
$command = $comp_words[$i];
|
$command = $comp_words[$i];
|
||||||
|
self :: unquote_word($command);
|
||||||
$command_arg_num = $i;
|
$command_arg_num = $i;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
$command_args[] = $comp_words[$i];
|
$command_args[] = $comp_words[$i];
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
switch($comp_words[$i]) {
|
switch($unescaped_comp_word) {
|
||||||
case '-S':
|
case '-S':
|
||||||
case '--ldap-server':
|
case '--ldap-server':
|
||||||
$i++;
|
$i++;
|
||||||
|
@ -409,6 +412,7 @@ class LScli extends LSlog_staticLoggerClass {
|
||||||
break;
|
break;
|
||||||
if (isset($comp_words[$i])) {
|
if (isset($comp_words[$i])) {
|
||||||
$ldap_server_id = intval($comp_words[$i]);
|
$ldap_server_id = intval($comp_words[$i]);
|
||||||
|
self :: unquote_word($ldap_server_id);
|
||||||
if(!LSsession :: setLdapServer($ldap_server_id))
|
if(!LSsession :: setLdapServer($ldap_server_id))
|
||||||
self :: usage("Fail to select LDAP server #$ldap_server_id.");
|
self :: usage("Fail to select LDAP server #$ldap_server_id.");
|
||||||
}
|
}
|
||||||
|
@ -424,6 +428,7 @@ class LScli extends LSlog_staticLoggerClass {
|
||||||
if (!isset($comp_words[$i]))
|
if (!isset($comp_words[$i]))
|
||||||
break;
|
break;
|
||||||
$class = $comp_words[$i];
|
$class = $comp_words[$i];
|
||||||
|
self :: unquote_word($class);
|
||||||
if(!LSsession :: loadLSclass($class))
|
if(!LSsession :: loadLSclass($class))
|
||||||
self :: usage("Fail to load class '$class'.");
|
self :: usage("Fail to load class '$class'.");
|
||||||
break;
|
break;
|
||||||
|
@ -438,6 +443,7 @@ class LScli extends LSlog_staticLoggerClass {
|
||||||
if (!isset($comp_words[$i]))
|
if (!isset($comp_words[$i]))
|
||||||
break;
|
break;
|
||||||
$addon = $comp_words[$i];
|
$addon = $comp_words[$i];
|
||||||
|
self :: unquote_word($addon);
|
||||||
if(!LSsession :: loadLSaddon($addon))
|
if(!LSsession :: loadLSaddon($addon))
|
||||||
self :: usage("Fail to load addon '$addon'.");
|
self :: usage("Fail to load addon '$addon'.");
|
||||||
break;
|
break;
|
||||||
|
@ -497,12 +503,13 @@ class LScli extends LSlog_staticLoggerClass {
|
||||||
**/
|
**/
|
||||||
public static function autocomplete_class_name($prefix='') {
|
public static function autocomplete_class_name($prefix='') {
|
||||||
$classes = array();
|
$classes = array();
|
||||||
|
$quote_char = self :: unquote_word($prefix);
|
||||||
$regex = "/^class\.($prefix.*)\.php$/";
|
$regex = "/^class\.($prefix.*)\.php$/";
|
||||||
foreach(array(LS_ROOT_DIR."/".LS_CLASS_DIR, LS_ROOT_DIR."/".LS_LOCAL_DIR."/".LS_CLASS_DIR) as $dir_path) {
|
foreach(array(LS_ROOT_DIR."/".LS_CLASS_DIR, LS_ROOT_DIR."/".LS_LOCAL_DIR."/".LS_CLASS_DIR) as $dir_path) {
|
||||||
foreach (listFiles($dir_path, $regex) as $file) {
|
foreach (listFiles($dir_path, $regex) as $file) {
|
||||||
$class = $file[1];
|
$class = $file[1];
|
||||||
if (!in_array($class, $classes))
|
if (!in_array($class, $classes))
|
||||||
$classes[] = $class;
|
$classes[] = self :: quote_word($class, $quote_char);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return $classes;
|
return $classes;
|
||||||
|
@ -517,12 +524,13 @@ class LScli extends LSlog_staticLoggerClass {
|
||||||
**/
|
**/
|
||||||
public static function autocomplete_addon_name($prefix='') {
|
public static function autocomplete_addon_name($prefix='') {
|
||||||
$addons = array();
|
$addons = array();
|
||||||
|
$quote_char = self :: unquote_word($prefix);
|
||||||
$regex = "/^LSaddons\.($prefix.*)\.php$/";
|
$regex = "/^LSaddons\.($prefix.*)\.php$/";
|
||||||
foreach(array(LS_ROOT_DIR."/".LS_ADDONS_DIR, LS_ROOT_DIR."/".LS_LOCAL_DIR."/".LS_ADDONS_DIR) as $dir_path) {
|
foreach(array(LS_ROOT_DIR."/".LS_ADDONS_DIR, LS_ROOT_DIR."/".LS_LOCAL_DIR."/".LS_ADDONS_DIR) as $dir_path) {
|
||||||
foreach (listFiles($dir_path, $regex) as $file) {
|
foreach (listFiles($dir_path, $regex) as $file) {
|
||||||
$addon = $file[1];
|
$addon = $file[1];
|
||||||
if (!in_array($addon, $addons))
|
if (!in_array($addon, $addons))
|
||||||
$addons[] = $addon;
|
$addons[] = self :: quote_word($addon, $quote_char);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return $addons;
|
return $addons;
|
||||||
|
@ -534,12 +542,16 @@ class LScli extends LSlog_staticLoggerClass {
|
||||||
* @param[in] $opts array Available options
|
* @param[in] $opts array Available options
|
||||||
* @param[in] $prefix string Option name prefix (optional, default=empty string)
|
* @param[in] $prefix string Option name prefix (optional, default=empty string)
|
||||||
* @param[in] $case_sensitive boolean Set to false if options are case insensitive (optional, default=true)
|
* @param[in] $case_sensitive boolean Set to false if options are case insensitive (optional, default=true)
|
||||||
|
* @param[in] $quote_char boolean Quote character (optional, if not set, $prefix will be unquoted and its
|
||||||
|
* quote char (if detected) will be used to quote options)
|
||||||
*
|
*
|
||||||
* @retval array List of matched options
|
* @retval array List of matched options
|
||||||
**/
|
**/
|
||||||
public static function autocomplete_opts($opts, $prefix='', $case_sensitive=true) {
|
public static function autocomplete_opts($opts, $prefix='', $case_sensitive=true, $quote_char='') {
|
||||||
if (!is_string($prefix) || strlen($prefix)==0)
|
if (!is_string($prefix) || strlen($prefix)==0)
|
||||||
return $opts;
|
return $opts;
|
||||||
|
if (!$quote_char)
|
||||||
|
$quote_char = self :: unquote_word($prefix);
|
||||||
|
|
||||||
if (!$case_sensitive)
|
if (!$case_sensitive)
|
||||||
$prefix = strtolower($prefix);
|
$prefix = strtolower($prefix);
|
||||||
|
@ -547,8 +559,9 @@ class LScli extends LSlog_staticLoggerClass {
|
||||||
foreach($opts as $key => $opt) {
|
foreach($opts as $key => $opt) {
|
||||||
if (!$case_sensitive)
|
if (!$case_sensitive)
|
||||||
$opt = strtolower($opt);
|
$opt = strtolower($opt);
|
||||||
|
self :: unquote_word($opt);
|
||||||
if (substr($opt, 0, strlen($prefix)) == $prefix)
|
if (substr($opt, 0, strlen($prefix)) == $prefix)
|
||||||
$matched_opts[] = $opts[$key];
|
$matched_opts[] = LScli :: quote_word($opt, $quote_char);
|
||||||
}
|
}
|
||||||
self :: log_debug("autocomplete_opts(".implode('|', $opts).", $prefix, case ".($case_sensitive?"sensitive":"insensitive").") : matched opts: ".print_r($matched_opts, true));
|
self :: log_debug("autocomplete_opts(".implode('|', $opts).", $prefix, case ".($case_sensitive?"sensitive":"insensitive").") : matched opts: ".print_r($matched_opts, true));
|
||||||
return $matched_opts;
|
return $matched_opts;
|
||||||
|
@ -573,10 +586,13 @@ class LScli extends LSlog_staticLoggerClass {
|
||||||
* Autocomplete LSobject type option
|
* Autocomplete LSobject type option
|
||||||
*
|
*
|
||||||
* @param[in] $prefix string Option prefix (optional, default=empty string)
|
* @param[in] $prefix string Option prefix (optional, default=empty string)
|
||||||
|
* @param[in] $case_sensitive boolean Set to false if options are case insensitive (optional, default=true)
|
||||||
|
* @param[in] $quote_char boolean Quote character (optional, if not set, $prefix will be unquoted and its
|
||||||
|
* quote char (if detected) will be used to quote options)
|
||||||
*
|
*
|
||||||
* @retval array List of available options
|
* @retval array List of available options
|
||||||
**/
|
**/
|
||||||
public static function autocomplete_LSobject_types($prefix='') {
|
public static function autocomplete_LSobject_types($prefix='', $case_sensitive=true, $quote_char='') {
|
||||||
$types = LSconfig :: get('LSaccess', array(), null, LSsession :: $ldapServer);
|
$types = LSconfig :: get('LSaccess', array(), null, LSsession :: $ldapServer);
|
||||||
$subdn_config = LSconfig :: get('subDn', null, null, LSsession :: $ldapServer);
|
$subdn_config = LSconfig :: get('subDn', null, null, LSsession :: $ldapServer);
|
||||||
if (is_array($subdn_config)) {
|
if (is_array($subdn_config)) {
|
||||||
|
@ -597,7 +613,7 @@ class LScli extends LSlog_staticLoggerClass {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return self :: autocomplete_opts($types, $prefix, false);
|
return self :: autocomplete_opts($types, $prefix, $case_sensitive, $quote_char);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -605,16 +621,23 @@ class LScli extends LSlog_staticLoggerClass {
|
||||||
*
|
*
|
||||||
* @param[in] $objType string LSobject type
|
* @param[in] $objType string LSobject type
|
||||||
* @param[in] $prefix string Option prefix (optional, default=empty string)
|
* @param[in] $prefix string Option prefix (optional, default=empty string)
|
||||||
|
* @param[in] $case_sensitive boolean Set to false if options are case insensitive (optional, default=true)
|
||||||
|
* @param[in] $quote_char boolean Quote character (optional, if not set, $prefix will be unquoted and its
|
||||||
|
* quote char (if detected) will be used to quote options)
|
||||||
*
|
*
|
||||||
* @retval array List of available options
|
* @retval array List of available options
|
||||||
**/
|
**/
|
||||||
public static function autocomplete_LSobject_dn($objType, $prefix='') {
|
public static function autocomplete_LSobject_dn($objType, $prefix='', $case_sensitive=true, $quote_char='') {
|
||||||
if (!LSsession ::loadLSobject($objType, false))
|
if (!LSsession ::loadLSobject($objType, false))
|
||||||
return array();
|
return array();
|
||||||
|
|
||||||
|
// Make sure to unquote prefix
|
||||||
|
if (!$quote_char && $prefix)
|
||||||
|
$quote_char = self :: unquote_word($prefix);
|
||||||
|
|
||||||
$rdn_attr = LSconfig :: get("LSobjects.$objType.rdn");
|
$rdn_attr = LSconfig :: get("LSobjects.$objType.rdn");
|
||||||
if (!$rdn_attr || strlen($prefix) < (strlen($rdn_attr)+2) || substr($prefix, 0, (strlen($rdn_attr)+1)) != "$rdn_attr=")
|
if (!$rdn_attr || strlen($prefix) < (strlen($rdn_attr)+2) || substr($prefix, 0, (strlen($rdn_attr)+1)) != "$rdn_attr=")
|
||||||
return array("$rdn_attr=a", "$rdn_attr=*");
|
return array(LScli :: quote_word("$rdn_attr=", $quote_char));
|
||||||
|
|
||||||
// Split prefix by comma to keep only RDN
|
// Split prefix by comma to keep only RDN
|
||||||
$prefix_parts = explode(',', $prefix);
|
$prefix_parts = explode(',', $prefix);
|
||||||
|
@ -627,13 +650,41 @@ class LScli extends LSlog_staticLoggerClass {
|
||||||
if (is_array($objs)) {
|
if (is_array($objs)) {
|
||||||
$dns = array_keys($objs);
|
$dns = array_keys($objs);
|
||||||
self :: log_debug("Matching $objType DNs with prefix '$prefix_rdn': ".implode(', ', $dns));
|
self :: log_debug("Matching $objType DNs with prefix '$prefix_rdn': ".implode(', ', $dns));
|
||||||
// If prefix have been reduced for the search, use self :: autocomplete_opts() to keep only
|
return self :: autocomplete_opts($dns, $prefix, $case_sensitive, $quote_char);
|
||||||
// full match
|
|
||||||
if ($prefix_rdn != $prefix)
|
|
||||||
return self :: autocomplete_opts($dns, $prefix);
|
|
||||||
return $dns;
|
|
||||||
}
|
}
|
||||||
return array("$rdn_attr=a", "$rdn_attr=*");
|
return array(LScli :: quote_word("$rdn_attr=", $quote_char));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unquote a word
|
||||||
|
*
|
||||||
|
* @param[in] &$word string Reference of the word to unquote
|
||||||
|
*
|
||||||
|
* @retval string The quote character or an empty string if word if not quoted
|
||||||
|
*/
|
||||||
|
public static function unquote_word(&$word) {
|
||||||
|
if (in_array($word[0], array('"', "'"))) {
|
||||||
|
$quote_char = $word[0];
|
||||||
|
$word = substr($word, 1);
|
||||||
|
if ($word[strlen($word)-1] == $quote_char)
|
||||||
|
$word = substr($word, 0, -1);
|
||||||
|
return $quote_char;
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Quote a word
|
||||||
|
*
|
||||||
|
* @param[in] $word string The word to quote
|
||||||
|
* @param[in] $quote_char string The quote character. If not defined or empty, the input word
|
||||||
|
* will be returned unmodified.
|
||||||
|
*
|
||||||
|
* @retval string The quoted word
|
||||||
|
*/
|
||||||
|
public static function quote_word($word, $quote_char) {
|
||||||
|
if (!$quote_char) return $word;
|
||||||
|
return $quote_char . str_replace($quote_char, "\\$quote_char", $word) . $quote_char;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1967,20 +1967,22 @@ class LSldapObject extends LSlog_staticLoggerClass {
|
||||||
if (!in_array($command_args[$i], $opts)) {
|
if (!in_array($command_args[$i], $opts)) {
|
||||||
// If object type not defined
|
// If object type not defined
|
||||||
if (is_null($objType)) {
|
if (is_null($objType)) {
|
||||||
// Check object type exists
|
|
||||||
$objTypes = LScli :: autocomplete_LSobject_types($command_args[$i]);
|
|
||||||
|
|
||||||
// Load it if exist and not trying to complete it
|
|
||||||
if (in_array($command_args[$i], $objTypes) && $i != $comp_word_num) {
|
|
||||||
LSsession :: loadLSobject($command_args[$i], false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Defined it
|
// Defined it
|
||||||
$objType = $command_args[$i];
|
$objType = $command_args[$i];
|
||||||
|
LScli :: unquote_word($objType);
|
||||||
$objType_arg_num = $i;
|
$objType_arg_num = $i;
|
||||||
|
|
||||||
|
// Check object type exists
|
||||||
|
$objTypes = LScli :: autocomplete_LSobject_types($objType);
|
||||||
|
|
||||||
|
// Load it if exist and not trying to complete it
|
||||||
|
if (in_array($objType, $objTypes) && $i != $comp_word_num) {
|
||||||
|
LSsession :: loadLSobject($objType, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
elseif (is_null($dn)) {
|
elseif (is_null($dn)) {
|
||||||
$dn = $command_args[$i];
|
$dn = $command_args[$i];
|
||||||
|
LScli :: unquote_word($dn);
|
||||||
$dn_arg_num = $i;
|
$dn_arg_num = $i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2183,20 +2185,22 @@ class LSldapObject extends LSlog_staticLoggerClass {
|
||||||
if (!in_array($command_args[$i], $opts)) {
|
if (!in_array($command_args[$i], $opts)) {
|
||||||
// If object type not defined
|
// If object type not defined
|
||||||
if (is_null($objType)) {
|
if (is_null($objType)) {
|
||||||
// Check object type exists
|
|
||||||
$objTypes = LScli :: autocomplete_LSobject_types($command_args[$i]);
|
|
||||||
|
|
||||||
// Load it if exist and not trying to complete it
|
|
||||||
if (in_array($command_args[$i], $objTypes) && $i != $comp_word_num) {
|
|
||||||
LSsession :: loadLSobject($command_args[$i], false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Defined it
|
// Defined it
|
||||||
$objType = $command_args[$i];
|
$objType = $command_args[$i];
|
||||||
|
LScli :: unquote_word($objType);
|
||||||
$objType_arg_num = $i;
|
$objType_arg_num = $i;
|
||||||
|
|
||||||
|
// Check object type exists
|
||||||
|
$objTypes = LScli :: autocomplete_LSobject_types($objType);
|
||||||
|
|
||||||
|
// Load it if exist and not trying to complete it
|
||||||
|
if (in_array($objType, $objTypes) && $i != $comp_word_num) {
|
||||||
|
LSsession :: loadLSobject($objType, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
elseif (is_null($dn)) {
|
elseif (is_null($dn)) {
|
||||||
$dn = $command_args[$i];
|
$dn = $command_args[$i];
|
||||||
|
LScli :: unquote_word($dn);
|
||||||
$dn_arg_num = $i;
|
$dn_arg_num = $i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2605,24 +2609,27 @@ class LSldapObject extends LSlog_staticLoggerClass {
|
||||||
if (!in_array($command_args[$i], $opts)) {
|
if (!in_array($command_args[$i], $opts)) {
|
||||||
// If object type not defined
|
// If object type not defined
|
||||||
if (is_null($objType)) {
|
if (is_null($objType)) {
|
||||||
// Check object type exists
|
|
||||||
$objTypes = LScli :: autocomplete_LSobject_types($command_args[$i]);
|
|
||||||
|
|
||||||
// Load it if exist and not trying to complete it
|
|
||||||
if (in_array($command_args[$i], $objTypes) && $i != $comp_word_num) {
|
|
||||||
LSsession :: loadLSobject($command_args[$i], false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Defined it
|
// Defined it
|
||||||
$objType = $command_args[$i];
|
$objType = $command_args[$i];
|
||||||
|
LScli :: unquote_word($objType);
|
||||||
$objType_arg_num = $i;
|
$objType_arg_num = $i;
|
||||||
|
|
||||||
|
// Check object type exists
|
||||||
|
$objTypes = LScli :: autocomplete_LSobject_types($objType);
|
||||||
|
|
||||||
|
// Load it if exist and not trying to complete it
|
||||||
|
if (in_array($objType, $objTypes) && $i != $comp_word_num) {
|
||||||
|
LSsession :: loadLSobject($objType, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
elseif (is_null($dn)) {
|
elseif (is_null($dn)) {
|
||||||
$dn = $command_args[$i];
|
$dn = $command_args[$i];
|
||||||
|
LScli :: unquote_word($dn);
|
||||||
$dn_arg_num = $i;
|
$dn_arg_num = $i;
|
||||||
}
|
}
|
||||||
elseif (is_null($relation_id)) {
|
elseif (is_null($relation_id)) {
|
||||||
$relation_id = $command_args[$i];
|
$relation_id = $command_args[$i];
|
||||||
|
LScli :: unquote_word($relation_id);
|
||||||
$relation_id_arg_num = $i;
|
$relation_id_arg_num = $i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue