def grep(self, text, limit=None): results = app.logger.search_log(self.account, self.contact.jid, text) if not results: raise CommandError(_("%s: Nothing found") % text) if limit: try: results = results[len(results) - int(limit):] except ValueError: raise CommandError(_("Limit must be an integer")) for row in results: contact = row.contact_name if not contact: if row.kind == KindConstant.CHAT_MSG_SENT: contact = app.nicks[self.account] else: contact = self.contact.name time_obj = localtime(row.time) date_obj = date.fromtimestamp(row.time) date_ = strftime('%Y-%m-%d', time_obj) time_ = strftime('%H:%M:%S', time_obj) if date_obj == date.today(): formatted = "[%s] %s: %s" % (time_, contact, row.message) else: formatted = "[%s, %s] %s: %s" % (date_, time_, contact, row.message) self.echo(formatted)
def affiliate(self, who, affiliation): if affiliation not in ('owner', 'admin', 'member', 'outcast', 'none'): raise CommandError(_("Invalid affiliation given")) if not who in app.contacts.get_nick_list(self.account, self.room_jid): raise CommandError(_("Nickname not found")) contact = app.contacts.get_gc_contact(self.account, self.room_jid, who) self.connection.gc_set_affiliation(self.room_jid, contact.jid, affiliation)
def ping(self, nick): if self.account == app.ZEROCONF_ACC_NAME: raise CommandError( _('Command is not supported for zeroconf accounts')) gc_c = app.contacts.get_gc_contact(self.account, self.room_jid, nick) if gc_c is None: raise CommandError(_("Unknown nickname")) app.connections[self.account].get_module('Ping').send_ping(gc_c)
def dtmf(self, sequence): if not self.audio_sid: raise CommandError(_("No open audio sessions with the contact")) for tone in sequence: if not (tone in ("*", "#") or tone.isdigit()): raise CommandError(_("%s is not a valid tone") % tone) gjs = self.connection.get_jingle_session session = gjs(self.full_jid, self.audio_sid) content = session.get_content("audio") content.batch_dtmf(sequence)
def video(self): if not self.video_available: raise CommandError(_("Video sessions are not available")) # A video session is toggled by inverting the state of the # appropriate button. state = self._video_button.get_active() self._video_button.set_active(not state)
def audio(self): if not self.audio_available: raise CommandError(_("Voice chats are not available")) # An audio session is toggled by inverting the state of the # appropriate button. state = self._audio_button.get_active() self._audio_button.set_active(not state)
def nick(self, new_nick): try: new_nick = helpers.parse_resource(new_nick) except Exception: raise CommandError(_("Invalid nickname")) # FIXME: Check state of MUC self.connection.get_module('MUC').change_nick(self.room_jid, new_nick) self.new_nick = new_nick
def status(self, status, message): if status not in ('online', 'away', 'chat', 'xa', 'dnd'): raise CommandError("Invalid status given") for connection in app.connections.values(): if not app.settings.get_account_setting(connection.name, 'sync_with_global_status'): continue if not connection.state.is_available: continue connection.change_status(status, message)
def status(self, status, message): if status not in ('online', 'away', 'chat', 'xa', 'dnd'): raise CommandError("Invalid status given") for connection in app.connections.values(): if not app.config.get_per('accounts', connection.name, 'sync_with_global_status'): continue if connection.connected < 2: continue connection.change_status(status, message)
def nick(self, new_nick): try: new_nick = helpers.parse_resource(new_nick) except Exception: raise CommandError(_("Invalid nickname")) self.connection.join_gc(new_nick, self.room_jid, None, change_nick=True) self.new_nick = new_nick
def __call__(self, *args, **kwargs): try: return self.handler(*args, **kwargs) # This allows to use a shortcut way of raising an exception # inside a handler. That is to raise a CommandError without # command or name attributes set. They will be set to a # corresponding values right here in case if they was not set by # the one who raised an exception. except CommandError as error: if not error.command and not error.name: raise CommandError(error.message, self) raise # This one is a little bit too wide, but as Python does not have # anything more constrained - there is no other choice. Take a # look here if command complains about invalid arguments while # they are ok. except TypeError: raise CommandError("Command received invalid arguments", self)
def role(self, who, role): if role not in ('moderator', 'participant', 'visitor', 'none'): raise CommandError(_("Invalid role given")) if not who in app.contacts.get_nick_list(self.account, self.room_jid): raise CommandError(_("Nickname not found")) self.connection.get_module('MUC').set_role(self.room_jid, who, role)
def kick(self, who, reason): if not who in app.contacts.get_nick_list(self.account, self.room_jid): raise CommandError(_("Nickname not found")) self.connection.get_module('MUC').set_role(self.room_jid, who, 'none', reason or str())
def message(self, nick, a_message): nicks = app.contacts.get_nick_list(self.account, self.room_jid) if nick in nicks: self.on_send_pm(nick=nick, msg=a_message) else: raise CommandError(_("Nickname not found"))
def chat(self, nick): nicks = app.contacts.get_nick_list(self.account, self.room_jid) if nick in nicks: self.send_pm(nick) else: raise CommandError(_("Nickname not found"))
def ping(self, nick): if self.account == app.ZEROCONF_ACC_NAME: raise CommandError( _('Command is not supported for zeroconf accounts')) gc_c = app.contacts.get_gc_contact(self.account, self.room_jid, nick) app.connections[self.account].sendPing(gc_c, self)
def ping(self): if self.account == app.ZEROCONF_ACC_NAME: raise CommandError( _('Command is not supported for zeroconf accounts')) app.connections[self.account].get_module('Ping').send_ping( self.contact)
def adapt_arguments(command, arguments, args, opts): """ Adapt args and opts got from the parser to a specific handler by means of arguments specified on command definition. That is transform them to *args and **kwargs suitable for passing to a command handler. Dashes (-) in the option names will be converted to underscores. So you can map --one-more-option to a one_more_option=None. If the initial value of a keyword argument is a boolean (False in most cases) - then this option will be treated as a switch, that is an option which does not take an argument. If a switch is followed by an argument - then this argument will be treated just like a normal positional argument. """ spec_args, spec_kwargs, var_args, _var_kwargs = command.extract_specification( ) norm_kwargs = dict(spec_kwargs) # Quite complex piece of neck-breaking logic to extract raw # arguments if there is more, then one positional argument specified # by the command. In case if it's just one argument which is the # collector - this is fairly easy. But when it's more then one # argument - the neck-breaking logic of how to retrieve residual # arguments as a raw, all in one piece string, kicks in. if command.raw: if arguments: spec_fix = 1 if command.source else 0 spec_len = len(spec_args) - spec_fix arguments_end = len(arguments) - 1 # If there are any optional arguments given they should be # either an unquoted positional argument or part of the raw # argument. So we find all optional arguments that can # possibly be unquoted argument and append them as is to the # args. for key, value, (start, end) in opts[:spec_len]: if value: end -= len(value) + 1 args.append((arguments[start:end], (start, end))) args.append((value, (end, end + len(value) + 1))) else: args.append((arguments[start:end], (start, end))) # We need in-place sort here because after manipulations # with options order of arguments might be wrong and we just # can't have more complex logic to not let that happen. args.sort(key=itemgetter(1)) if spec_len > 1: try: _stopper, (start, end) = args[spec_len - 2] except IndexError: raise CommandError(_("Missing arguments"), command) # The essential point of the whole play. After # boundaries are being determined (supposedly correct) # we separate raw part from the rest of arguments, which # should be normally processed. raw = arguments[end:] raw = raw.strip() or None if not raw and not command.empty: raise CommandError(_("Missing arguments"), command) # Discard residual arguments and all of the options as # raw command does not support options and if an option # is given it is rather a part of a raw argument. args = args[:spec_len - 1] opts = [] args.append((raw, (end, arguments_end))) else: # Substitute all of the arguments with only one, which # contain raw and unprocessed arguments as a string. And # discard all the options, as raw command does not # support them. args = [(arguments, (0, arguments_end))] opts = [] else: if command.empty: args.append((None, (0, 0))) else: raise CommandError(_("Missing arguments"), command) # The first stage of transforming options we have got to a format # that can be used to associate them with declared keyword # arguments. Substituting dashes (-) in their names with # underscores (_). for index, (key, value, position) in enumerate(opts): if '-' in key: opts[index] = (key.replace('-', '_'), value, position) # The second stage of transforming options to an associable state. # Expanding short, one-letter options to a verbose ones, if # corresponding opt-in has been given. if command.expand: expanded = [] for spec_key in norm_kwargs.keys(): letter = spec_key[0] if len(spec_key) > 1 else None if letter and letter not in expanded: for index, (key, value, position) in enumerate(opts): if key == letter: expanded.append(letter) opts[index] = (spec_key, value, position) break # Detect switches and set their values accordingly. If any of them # carries a value - append it to args. for index, (key, value, position) in enumerate(opts): if isinstance(norm_kwargs.get(key), bool): opts[index] = (key, True, position) if value: args.append((value, position)) # Sorting arguments and options (just to be sure) in regarding to # their positions in the string. args.sort(key=itemgetter(1)) opts.sort(key=itemgetter(2)) # Stripping down position information supplied with arguments and # options as it won't be needed again. args = list(map(lambda t: t[0], args)) opts = list(map(lambda t: (t[0], t[1]), opts)) # If command has extra option enabled - collect all extra arguments # and pass them to a last positional argument command defines as a # list. if command.extra: if not var_args: spec_fix = 1 if not command.source else 2 spec_len = len(spec_args) - spec_fix extra = args[spec_len:] args = args[:spec_len] args.append(extra) else: raise DefinitionError("Can not have both, extra and *args") # Detect if positional arguments overlap keyword arguments. If so # and this is allowed by command options - then map them directly to # their options, so they can get proper further processing. spec_fix = 1 if command.source else 0 spec_len = len(spec_args) - spec_fix if len(args) > spec_len: if command.overlap: overlapped = args[spec_len:] args = args[:spec_len] for arg, spec_key, _spec_value in zip(overlapped, spec_kwargs): opts.append((spec_key, arg)) else: raise CommandError(_("Too many arguments"), command) # Detect every switch and ensure it will not receive any arguments. # Normally this does not happen unless overlapping is enabled. for key, value in opts: initial = norm_kwargs.get(key) if isinstance(initial, bool): if not isinstance(value, bool): raise CommandError("%s: Switch can not take an argument" % key, command) # Inject the source arguments as a string as a first argument, if # command has enabled the corresponding option. if command.source: args.insert(0, arguments) # Return *args and **kwargs in the form suitable for passing to a # command handler and being expanded. return tuple(args), dict(opts)