1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
|
#############################################################################
# Copyright (c) 2015-2016 Balabit
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 as published
# by the Free Software Foundation, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# As an additional exemption you are allowed to compile & link against the
# OpenSSL libraries as published by the OpenSSL project. See the file
# COPYING for details.
#
#############################################################################
from __future__ import absolute_import, print_function
from .completer import Completer
from .syslognginternals import get_nv_registry
class MacroCompleter(Completer):
_date_wildcards = {
'R_': 'received time',
'S_': 'stamp in message',
'C_': 'current time'
}
def __init__(self, macros=None):
super().__init__()
self._macros = macros
self._completions = []
def complete(self, entire_text, word_to_be_completed):
if not self._looks_like_a_macro_prefix(entire_text):
return []
self._collect_completions(word_to_be_completed)
return sorted([completion
for completion in self._completions
if len(word_to_be_completed) == 0 or completion.startswith(word_to_be_completed)])
def _looks_like_a_macro_prefix(self, entire_input):
if entire_input == '':
return True
if entire_input == '$':
return True
if entire_input[0] == '$' and self._is_valid_macro(entire_input[1:]):
return True
if entire_input == '${':
return True
if entire_input[:2] == '${':
return True
return False
def _is_valid_macro(self, macro):
return all(self._is_valid_macro_char(c) for c in macro)
@staticmethod
def _is_valid_macro_char(macro_char):
if 'A' <= macro_char <= 'Z':
return True
if 'a' <= macro_char <= 'z':
return True
if '0' <= macro_char <= '9':
return True
if macro_char == '_':
return True
return False
def _collect_completions(self, word):
self._reset_completions()
if word == '':
self._add_completion('$')
self._add_completion('${')
elif word == '$':
self._extend_completions(self._collect_unqualified_macros())
self._extend_completions(self._collect_qualified_macros_with_brace())
self._extend_completions(self._collect_small_numbered_matches())
self._extend_completions(self._collect_date_wildcards())
self._add_completion('${')
elif self._is_word_a_numbered_match_prefix(word):
self._extend_completions(self._collect_all_numbered_matches())
elif self._is_word_a_nonbraced_prefix(word):
if self._is_word_a_date_prefix(word):
self._extend_completions(self._collect_date_macros())
else:
self._extend_completions(self._collect_unqualified_macros())
self._extend_completions(self._collect_date_wildcards())
elif word == '${':
self._extend_completions(self._collect_small_numbered_matches_with_brace())
self._extend_completions(self._collect_all_macros_with_brace())
self._extend_completions(self._collect_date_wildcard_with_brace())
elif self._is_word_a_numbered_match_prefix_with_brace(word):
self._extend_completions(self._collect_all_numbered_matches_with_brace())
elif self._is_word_a_braced_prefix(word):
if self._is_word_a_date_prefix_with_brace(word):
self._extend_completions(self._collect_date_macros_with_brace())
else:
self._extend_completions(self._collect_all_macros_with_brace())
self._extend_completions(self._collect_date_wildcard_with_brace())
return self._completions
def _is_word_a_date_prefix(self, word):
return word[:3] in ['$' + x for x in self._date_wildcards]
@staticmethod
def _is_word_a_numbered_match_prefix(word):
return word[0] == '$' and word[1:2].isdigit()
@staticmethod
def _is_word_a_nonbraced_prefix(word):
return word[0] == '$' and word[1] != '{'
@staticmethod
def _is_word_a_numbered_match_prefix_with_brace(word):
return word[0:2] == '${' and word[2:3].isdigit()
def _is_word_a_date_prefix_with_brace(self, word):
return word[:4] in ['${' + x for x in self._date_wildcards]
@staticmethod
def _is_word_a_braced_prefix(word):
return word[0:2] == '${'
@staticmethod
def _is_macro_qualified(macro):
return '.' in macro
@classmethod
def _is_macro_unqualified(cls, macro):
return (not cls._is_macro_qualified(macro) and
not cls._is_macro_a_numbered_match(macro) and
not cls._is_macro_a_date_macro(macro))
@staticmethod
def _is_macro_a_numbered_match(macro):
return macro.isdigit()
@classmethod
def _is_macro_a_date_macro(cls, macro):
return macro[0:2] in cls._date_wildcards
@classmethod
def _is_macro_a_small_numbered_match(cls, macro):
return cls._is_macro_a_numbered_match(macro) and int(macro) < 10
def _collect_macros_generic(self, predicate, template):
for macro in self._macros or get_nv_registry():
if predicate(macro):
yield template.format(macro)
def _collect_macros(self, predicate):
return self._collect_macros_generic(predicate, '${}')
def _collect_macros_with_brace(self, predicate):
return self._collect_macros_generic(predicate, '${{{}}}')
def _collect_unqualified_macros(self):
return self._collect_macros(self._is_macro_unqualified)
def _collect_qualified_macros_with_brace(self):
return self._collect_macros_with_brace(self._is_macro_qualified)
def _collect_date_macros(self):
return self._collect_macros(self._is_macro_a_date_macro)
def _collect_date_macros_with_brace(self):
return self._collect_macros_with_brace(self._is_macro_a_date_macro)
def _collect_small_numbered_matches(self):
return self._collect_macros(self._is_macro_a_small_numbered_match)
def _collect_small_numbered_matches_with_brace(self):
return self._collect_macros_with_brace(self._is_macro_a_small_numbered_match)
def _collect_all_numbered_matches(self):
return self._collect_macros(self._is_macro_a_numbered_match)
def _collect_all_numbered_matches_with_brace(self):
return self._collect_macros_with_brace(self._is_macro_a_numbered_match)
def _collect_all_macros_with_brace(self):
return self._collect_macros_with_brace(
lambda macro: (not self._is_macro_a_numbered_match(macro) and
not self._is_macro_a_date_macro(macro)))
def _collect_date_wildcards(self):
for (wildcard, description) in self._date_wildcards.items():
yield f"${wildcard}* ({description})"
def _collect_date_wildcard_with_brace(self):
for (wildcard, description) in self._date_wildcards.items():
yield f"${{{wildcard}*}} ({description})"
def _reset_completions(self):
self._completions = []
def _extend_completions(self, iterable):
self._completions.extend(iterable)
def _add_completion(self, value):
self._completions.append(value)
|