Commit e1808a84 authored by louiz’'s avatar louiz’

Parse command arguments using a decorator and make things more consistent

Avoid surprises with some commands accepting quoted arguments and some other
not.

fix #2555
parent 61b5c6a9
...@@ -28,15 +28,16 @@ import multiuserchat as muc ...@@ -28,15 +28,16 @@ import multiuserchat as muc
from plugin import PluginConfig from plugin import PluginConfig
from roster import roster from roster import roster
from theming import dump_tuple, get_theme from theming import dump_tuple, get_theme
from decorators import command_args_parser
from . structs import Command, possible_show from . structs import Command, possible_show
def command_help(self, arg): @command_args_parser.quoted(0, 1)
def command_help(self, args):
""" """
/help <command_name> /help [command_name]
""" """
args = arg.split()
if not args: if not args:
color = dump_tuple(get_theme().COLOR_HELP_COMMANDS) color = dump_tuple(get_theme().COLOR_HELP_COMMANDS)
acc = [] acc = []
...@@ -67,7 +68,7 @@ def command_help(self, arg): ...@@ -67,7 +68,7 @@ def command_help(self, arg):
msg = '\n'.join(buff) msg = '\n'.join(buff)
msg += _("\nType /help <command_name> to know what each command does") msg += _("\nType /help <command_name> to know what each command does")
if args: else:
command = args[0].lstrip('/').strip() command = args[0].lstrip('/').strip()
if command in self.current_tab().commands: if command in self.current_tab().commands:
...@@ -84,7 +85,8 @@ def command_help(self, arg): ...@@ -84,7 +85,8 @@ def command_help(self, arg):
msg = tup[1] msg = tup[1]
self.information(msg, 'Help') self.information(msg, 'Help')
def command_runkey(self, arg): @command_args_parser.quoted(1)
def command_runkey(self, args):
""" """
/runkey <key> /runkey <key>
""" """
...@@ -93,7 +95,9 @@ def command_runkey(self, arg): ...@@ -93,7 +95,9 @@ def command_runkey(self, arg):
if key == '^J': if key == '^J':
return '\n' return '\n'
return key return key
char = arg.strip() if args is None:
return self.command_help('runkey')
char = args[0]
func = self.key_func.get(char, None) func = self.key_func.get(char, None)
if func: if func:
func() func()
...@@ -102,21 +106,20 @@ def command_runkey(self, arg): ...@@ -102,21 +106,20 @@ def command_runkey(self, arg):
if res: if res:
self.refresh_window() self.refresh_window()
def command_status(self, arg): @command_args_parser.quoted(1, 1, [None])
def command_status(self, args):
""" """
/status <status> [msg] /status <status> [msg]
""" """
args = common.shell_split(arg) if args is None:
if len(args) < 1: return self.command_help('status')
return
if not args[0] in possible_show.keys(): if not args[0] in possible_show.keys():
self.command_help('status') return self.command_help('status')
return
show = possible_show[args[0]] show = possible_show[args[0]]
if len(args) == 2: msg = args[1]
msg = args[1]
else:
msg = None
pres = self.xmpp.make_presence() pres = self.xmpp.make_presence()
if msg: if msg:
pres['status'] = msg pres['status'] = msg
...@@ -136,19 +139,15 @@ def command_status(self, arg): ...@@ -136,19 +139,15 @@ def command_status(self, arg):
if is_muctab and current.joined and show not in ('away', 'xa'): if is_muctab and current.joined and show not in ('away', 'xa'):
current.send_chat_state('active') current.send_chat_state('active')
def command_presence(self, arg): @command_args_parser.quoted(1, 2, [None, None])
def command_presence(self, args):
""" """
/presence <JID> [type] [status] /presence <JID> [type] [status]
""" """
args = common.shell_split(arg) if args is None:
if len(args) == 1: return self.command_help('presence')
jid, type, status = args[0], None, None
elif len(args) == 2: jid, type, status = args[0], args[1], args[2]
jid, type, status = args[0], args[1], None
elif len(args) == 3:
jid, type, status = args[0], args[1], args[2]
else:
return
if jid == '.' and isinstance(self.current_tab(), tabs.ChatTab): if jid == '.' and isinstance(self.current_tab(), tabs.ChatTab):
jid = self.current_tab().name jid = self.current_tab().name
if type == 'available': if type == 'available':
...@@ -177,24 +176,26 @@ def command_presence(self, arg): ...@@ -177,24 +176,26 @@ def command_presence(self, arg):
if self.current_tab() in tab.privates: if self.current_tab() in tab.privates:
self.current_tab().send_chat_state(chatstate, True) self.current_tab().send_chat_state(chatstate, True)
def command_theme(self, arg=''): @command_args_parser.quoted(1)
def command_theme(self, args=None):
"""/theme <theme name>""" """/theme <theme name>"""
args = arg.split() if args is None:
if args: return self.command_help('theme')
self.command_set('theme %s' % (args[0],)) self.command_set('theme %s' % (args[0],))
def command_win(self, arg): @command_args_parser.quoted(1)
def command_win(self, args):
""" """
/win <number> /win <number>
""" """
arg = arg.strip() if args is None:
if not arg: return self.command_help('win')
self.command_help('win')
return nb = args[0]
try: try:
nb = int(arg.split()[0]) nb = int(nb)
except ValueError: except ValueError:
nb = arg pass
if self.current_tab_nb == nb: if self.current_tab_nb == nb:
return return
self.previous_tab_nb = self.current_tab_nb self.previous_tab_nb = self.current_tab_nb
...@@ -219,15 +220,15 @@ def command_win(self, arg): ...@@ -219,15 +220,15 @@ def command_win(self, arg):
self.current_tab().on_gain_focus() self.current_tab().on_gain_focus()
self.refresh_window() self.refresh_window()
def command_move_tab(self, arg): @command_args_parser.quoted(2)
def command_move_tab(self, args):
""" """
/move_tab old_pos new_pos /move_tab old_pos new_pos
""" """
args = common.shell_split(arg) if args is None:
current_tab = self.current_tab()
if len(args) != 2:
return self.command_help('move_tab') return self.command_help('move_tab')
current_tab = self.current_tab()
if args[0] == '.': if args[0] == '.':
args[0] = current_tab.nb args[0] = current_tab.nb
if args[1] == '.': if args[1] == '.':
...@@ -259,16 +260,16 @@ def command_move_tab(self, arg): ...@@ -259,16 +260,16 @@ def command_move_tab(self, arg):
self.current_tab_nb = self.tabs.index(current_tab) self.current_tab_nb = self.tabs.index(current_tab)
self.refresh_window() self.refresh_window()
def command_list(self, arg): @command_args_parser.quoted(0, 1)
def command_list(self, args):
""" """
/list <server> /list [server]
Opens a MucListTab containing the list of the room in the specified server Opens a MucListTab containing the list of the room in the specified server
""" """
arg = arg.split() if args is None:
if len(arg) > 1:
return self.command_help('list') return self.command_help('list')
elif arg: elif args:
server = safeJID(arg[0]).server server = safeJID(args[0]).server
else: else:
if not isinstance(self.current_tab(), tabs.MucTab): if not isinstance(self.current_tab(), tabs.MucTab):
return self.information('Please provide a server', 'Error') return self.information('Please provide a server', 'Error')
...@@ -279,7 +280,8 @@ def command_list(self, arg): ...@@ -279,7 +280,8 @@ def command_list(self, arg):
self.xmpp.plugin['xep_0030'].get_items(jid=server, self.xmpp.plugin['xep_0030'].get_items(jid=server,
callback=cb) callback=cb)
def command_version(self, arg): @command_args_parser.quoted(1)
def command_version(self, args):
""" """
/version <jid> /version <jid>
""" """
...@@ -296,9 +298,9 @@ def command_version(self, arg): ...@@ -296,9 +298,9 @@ def command_version(self, arg):
res.get('os') or _('an unknown platform')) res.get('os') or _('an unknown platform'))
self.information(version, 'Info') self.information(version, 'Info')
args = common.shell_split(arg) if args is None:
if len(args) < 1:
return self.command_help('version') return self.command_help('version')
jid = safeJID(args[0]) jid = safeJID(args[0])
if jid.resource or jid not in roster: if jid.resource or jid not in roster:
fixes.get_version(self.xmpp, jid, callback=callback) fixes.get_version(self.xmpp, jid, callback=callback)
...@@ -308,11 +310,11 @@ def command_version(self, arg): ...@@ -308,11 +310,11 @@ def command_version(self, arg):
else: else:
fixes.get_version(self.xmpp, jid, callback=callback) fixes.get_version(self.xmpp, jid, callback=callback)
def command_join(self, arg, histo_length=None): @command_args_parser.quoted(0, 2)
def command_join(self, args, histo_length=None):
""" """
/join [room][/nick] [password] /join [room][/nick] [password]
""" """
args = common.shell_split(arg)
password = None password = None
if len(args) == 0: if len(args) == 0:
tab = self.current_tab() tab = self.current_tab()
...@@ -409,11 +411,11 @@ def command_join(self, arg, histo_length=None): ...@@ -409,11 +411,11 @@ def command_join(self, arg, histo_length=None):
tab.refresh() tab.refresh()
self.doupdate() self.doupdate()
def command_bookmark_local(self, arg=''): @command_args_parser.quoted(0, 2)
def command_bookmark_local(self, args):
""" """
/bookmark_local [room][/nick] [password] /bookmark_local [room][/nick] [password]
""" """
args = common.shell_split(arg)
nick = None nick = None
password = None password = None
if not args and not isinstance(self.current_tab(), tabs.MucTab): if not args and not isinstance(self.current_tab(), tabs.MucTab):
...@@ -470,15 +472,14 @@ def command_bookmark_local(self, arg=''): ...@@ -470,15 +472,14 @@ def command_bookmark_local(self, arg=''):
self.information(_('Your local bookmarks are now: %s') % self.information(_('Your local bookmarks are now: %s') %
[b for b in bookmark.bookmarks if b.method == 'local'], 'Info') [b for b in bookmark.bookmarks if b.method == 'local'], 'Info')
def command_bookmark(self, arg=''): @command_args_parser.quoted(0, 3)
def command_bookmark(self, args):
""" """
/bookmark [room][/nick] [autojoin] [password] /bookmark [room][/nick] [autojoin] [password]
""" """
if not config.get('use_remote_bookmarks'): if not config.get('use_remote_bookmarks'):
self.command_bookmark_local(arg) return self.command_bookmark_local(" ".join(args))
return
args = common.shell_split(arg)
nick = None nick = None
if not args and not isinstance(self.current_tab(), tabs.MucTab): if not args and not isinstance(self.current_tab(), tabs.MucTab):
return return
...@@ -553,7 +554,8 @@ def command_bookmark(self, arg=''): ...@@ -553,7 +554,8 @@ def command_bookmark(self, arg=''):
if each.method in ('pep', 'privatexml'): if each.method in ('pep', 'privatexml'):
remote.append(each) remote.append(each)
def command_bookmarks(self, arg=''): @command_args_parser.ignored
def command_bookmarks(self):
"""/bookmarks""" """/bookmarks"""
local = [] local = []
remote = [] remote = []
...@@ -568,9 +570,10 @@ def command_bookmarks(self, arg=''): ...@@ -568,9 +570,10 @@ def command_bookmarks(self, arg=''):
self.information(_('Your local bookmarks are: %s') % local, self.information(_('Your local bookmarks are: %s') % local,
_('Info')) _('Info'))
def command_remove_bookmark(self, arg=''): @command_args_parser.quoted(0, 1)
def command_remove_bookmark(self, args):
"""/remove_bookmark [jid]""" """/remove_bookmark [jid]"""
args = common.shell_split(arg)
if not args: if not args:
tab = self.current_tab() tab = self.current_tab()
if isinstance(tab, tabs.MucTab) and bookmark.get_by_jid(tab.name): if isinstance(tab, tabs.MucTab) and bookmark.get_by_jid(tab.name):
...@@ -589,11 +592,11 @@ def command_remove_bookmark(self, arg=''): ...@@ -589,11 +592,11 @@ def command_remove_bookmark(self, arg=''):
else: else:
self.information('No bookmark to remove', 'Info') self.information('No bookmark to remove', 'Info')
def command_set(self, arg): @command_args_parser.quoted(1, 2)
def command_set(self, args):
""" """
/set [module|][section] <option> [value] /set [module|][section] <option> [value]
""" """
args = common.shell_split(arg)
if len(args) == 1: if len(args) == 1:
option = args[0] option = args[0]
value = config.get(option) value = config.get(option)
...@@ -650,33 +653,35 @@ def command_set(self, arg): ...@@ -650,33 +653,35 @@ def command_set(self, arg):
self.call_for_resize() self.call_for_resize()
self.information(*info) self.information(*info)
def command_toggle(self, arg): @command_args_parser.quoted(1)
def command_toggle(self, args):
""" """
/toggle <option> /toggle <option>
shortcut for /set <option> toggle shortcut for /set <option> toggle
""" """
arg = arg.split() if args is None:
if arg and arg[0]: return self.command_help('toggle')
if args[0]:
self.command_set('%s toggle' % arg[0]) self.command_set('%s toggle' % arg[0])
def command_server_cycle(self, arg=''): @command_args_parser.quoted(1, 1)
def command_server_cycle(self, args):
""" """
Do a /cycle on each room of the given server. Do a /cycle on each room of the given server.
If none, do it on the current tab If none, do it on the current tab
""" """
args = common.shell_split(arg)
tab = self.current_tab() tab = self.current_tab()
message = "" message = ""
if len(args): if args:
domain = args[0] domain = args[0]
if len(args) > 1: if len(args) == 2:
message = args[1] message = args[1]
else: else:
if isinstance(tab, tabs.MucTab): if isinstance(tab, tabs.MucTab):
domain = safeJID(tab.name).domain domain = safeJID(tab.name).domain
else: else:
self.information(_("No server specified"), "Error") return self.information(_("No server specified"), "Error")
return
for tab in self.get_tabs(tabs.MucTab): for tab in self.get_tabs(tabs.MucTab):
if tab.name.endswith(domain): if tab.name.endswith(domain):
if tab.joined: if tab.joined:
...@@ -690,7 +695,8 @@ def command_server_cycle(self, arg=''): ...@@ -690,7 +695,8 @@ def command_server_cycle(self, arg=''):
else: else:
self.command_join('"%s/%s"' %(tab.name, tab.own_nick)) self.command_join('"%s/%s"' %(tab.name, tab.own_nick))
def command_last_activity(self, arg): @command_args_parser.quoted(1)
def command_last_activity(self, args):
""" """
/last_activity <jid> /last_activity <jid>
""" """
...@@ -717,41 +723,42 @@ def command_last_activity(self, arg): ...@@ -717,41 +723,42 @@ def command_last_activity(self, arg):
common.parse_secs_to_str(seconds), common.parse_secs_to_str(seconds),
(' and his/her last status was %s' % status) if status else '') (' and his/her last status was %s' % status) if status else '')
self.information(msg, 'Info') self.information(msg, 'Info')
jid = safeJID(arg)
if jid == '': if args is None:
return self.command_help('last_activity') return self.command_help('last_activity')
jid = safeJID(args[0])
self.xmpp.plugin['xep_0012'].get_last_activity(jid, self.xmpp.plugin['xep_0012'].get_last_activity(jid,
callback=callback) callback=callback)
def command_mood(self, arg): @command_args_parser.quoted(0, 2)
def command_mood(self, args):
""" """
/mood [<mood> [text]] /mood [<mood> [text]]
""" """
args = common.shell_split(arg)
if not args: if not args:
self.xmpp.plugin['xep_0107'].stop() return self.xmpp.plugin['xep_0107'].stop()
return
mood = args[0] mood = args[0]
if mood not in pep.MOODS: if mood not in pep.MOODS:
return self.information(_('%s is not a correct value for a mood.') return self.information(_('%s is not a correct value for a mood.')
% mood, % mood,
_('Error')) _('Error'))
if len(args) > 1: if len(args) == 2:
text = args[1] text = args[1]
else: else:
text = None text = None
self.xmpp.plugin['xep_0107'].publish_mood(mood, text, self.xmpp.plugin['xep_0107'].publish_mood(mood, text,
callback=dumb_callback) callback=dumb_callback)
def command_activity(self, arg): @command_args_parser.quoted(0, 3)
def command_activity(self, args):
""" """
/activity [<general> [specific] [text]] /activity [<general> [specific] [text]]
""" """
args = common.shell_split(arg)
length = len(args) length = len(args)
if not length: if not length:
self.xmpp.plugin['xep_0108'].stop() return self.xmpp.plugin['xep_0108'].stop()
return
general = args[0] general = args[0]
if general not in pep.ACTIVITIES: if general not in pep.ACTIVITIES:
return self.information(_('%s is not a correct value for an activity') return self.information(_('%s is not a correct value for an activity')
...@@ -774,14 +781,14 @@ def command_activity(self, arg): ...@@ -774,14 +781,14 @@ def command_activity(self, arg):
self.xmpp.plugin['xep_0108'].publish_activity(general, specific, text, self.xmpp.plugin['xep_0108'].publish_activity(general, specific, text,
callback=dumb_callback) callback=dumb_callback)
def command_gaming(self, arg): @command_args_parser.quoted(0, 2)
def command_gaming(self, args):
""" """
/gaming [<game name> [server address]] /gaming [<game name> [server address]]
""" """
args = common.shell_split(arg)
if not args: if not args:
self.xmpp.plugin['xep_0196'].stop() return self.xmpp.plugin['xep_0196'].stop()
return
name = args[0] name = args[0]
if len(args) > 1: if len(args) > 1:
address = args[1] address = args[1]
...@@ -791,25 +798,27 @@ def command_gaming(self, arg): ...@@ -791,25 +798,27 @@ def command_gaming(self, arg):
server_address=address, server_address=address,
callback=dumb_callback) callback=dumb_callback)
def command_invite(self, arg): @command_args_parser.quoted(2, 1, [None])
def command_invite(self, args):
"""/invite <to> <room> [reason]""" """/invite <to> <room> [reason]"""
args = common.shell_split(arg)
if len(args) < 2: if args is None:
return return self.command_help('invite')
reason = args[2] if len(args) > 2 else None
reason = args[2]
to = safeJID(args[0]) to = safeJID(args[0])
room = safeJID(args[1]).bare room = safeJID(args[1]).bare
self.invite(to.full, room, reason=reason) self.invite(to.full, room, reason=reason)
def command_decline(self, arg): @command_args_parser.quoted(1, 1, [''])
def command_decline(self, args):
"""/decline <room@server.tld> [reason]""" """/decline <room@server.tld> [reason]"""
args = common.shell_split(arg) if args is None:
if not len(args): return self.command_help('decline')
return
jid = safeJID(args[0]) jid = safeJID(args[0])
if jid.bare not in self.pending_invites: if jid.bare not in self.pending_invites:
return return
reason = args[1] if len(args) > 1 else '' reason = args[1]
del self.pending_invites[jid.bare] del self.pending_invites[jid.bare]
self.xmpp.plugin['xep_0045'].decline_invite(jid.bare, self.xmpp.plugin['xep_0045'].decline_invite(jid.bare,
self.pending_invites[jid.bare], self.pending_invites[jid.bare],
...@@ -817,7 +826,8 @@ def command_decline(self, arg): ...@@ -817,7 +826,8 @@ def command_decline(self, arg):
### Commands without a completion in this class ### ### Commands without a completion in this class ###
def command_invitations(self, arg=''): @command_args_parser.ignored
def command_invitations(self):
"""/invitations""" """/invitations"""