diff --git a/src/command_system/__init__.py b/src/command_system/__init__.py index 8084d759e..2fb336264 100644 --- a/src/command_system/__init__.py +++ b/src/command_system/__init__.py @@ -1,4 +1,4 @@ -# Copyright (C) 2009 Alexander Cherniuk +# Copyright (C) 2009-2010 Alexander Cherniuk # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/command_system/dispatching.py b/src/command_system/dispatching.py index dfbc73d40..0c613ec15 100644 --- a/src/command_system/dispatching.py +++ b/src/command_system/dispatching.py @@ -1,4 +1,4 @@ -# Copyright (C) 2009 Alexander Cherniuk +# Copyright (C) 2009-2010 Alexander Cherniuk # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/command_system/errors.py b/src/command_system/errors.py index c4e71b616..d3b29e85e 100644 --- a/src/command_system/errors.py +++ b/src/command_system/errors.py @@ -1,4 +1,4 @@ -# Copyright (C) 2009 Alexander Cherniuk +# Copyright (C) 2009-2010 Alexander Cherniuk # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -45,3 +45,9 @@ class CommandError(BaseError): Used to indicate errors occured during command execution. """ pass + +class NoCommandError(BaseError): + """ + Used to indicate an inability to find the specified command. + """ + pass diff --git a/src/command_system/framework.py b/src/command_system/framework.py index f67f68da5..c8c822494 100644 --- a/src/command_system/framework.py +++ b/src/command_system/framework.py @@ -1,4 +1,4 @@ -# Copyright (C) 2009 Alexander Cherniuk +# Copyright (C) 2009-2010 Alexander Cherniuk # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -25,7 +25,7 @@ from inspect import getargspec from dispatching import Dispatcher, HostDispatcher, ContainerDispatcher from mapping import parse_arguments, adapt_arguments -from errors import DefinitionError, CommandError +from errors import DefinitionError, CommandError, NoCommandError class CommandHost(object): """ @@ -128,7 +128,7 @@ class CommandProcessor(object): def get_command(self, name): command = Dispatcher.get_command(self.COMMAND_HOST, name) if not command: - raise CommandError("Command does not exist", name=name) + raise NoCommandError("Command does not exist", name=name) return command def list_commands(self): @@ -330,7 +330,7 @@ def command(*names, **properties): return decorator -def documentation(text): +def doc(text): """ This decorator is used to bind a documentation (a help) to a command. diff --git a/src/command_system/implementation/__init__.py b/src/command_system/implementation/__init__.py index a5f4e4a23..4e179f5ea 100644 --- a/src/command_system/implementation/__init__.py +++ b/src/command_system/implementation/__init__.py @@ -1,4 +1,4 @@ -# Copyright (C) 2009 Alexander Cherniuk +# Copyright (C) 2009-2010 Alexander Cherniuk # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/command_system/implementation/custom.py b/src/command_system/implementation/custom.py index 5e1b94ec0..64b872e54 100644 --- a/src/command_system/implementation/custom.py +++ b/src/command_system/implementation/custom.py @@ -1,4 +1,4 @@ -# Copyright (C) 2009 Alexander Cherniuk +# Copyright (C) 2009-2010 Alexander Cherniuk # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -21,7 +21,7 @@ Keep in mind that this module is not being loaded, so the code will not be executed and commands defined here will not be detected. """ -from ..framework import CommandContainer, command, documentation +from ..framework import CommandContainer, command, doc from hosts import ChatCommands, PrivateChatCommands, GroupChatCommands class CustomCommonCommands(CommandContainer): @@ -58,7 +58,7 @@ class CustomChatCommands(CommandContainer): HOSTS = (ChatCommands,) - @documentation(_("The same as using a doc-string, except it supports translation")) + @doc(_("The same as using a doc-string, except it supports translation")) @command def sing(self): return "Are you phreaking kidding me? Buy yourself a damn stereo..." diff --git a/src/command_system/implementation/hosts.py b/src/command_system/implementation/hosts.py index 933015609..3624da2dc 100644 --- a/src/command_system/implementation/hosts.py +++ b/src/command_system/implementation/hosts.py @@ -1,4 +1,4 @@ -# Copyright (C) 2009 Alexander Cherniuk +# Copyright (C) 2009-2010 Alexander Cherniuk # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/command_system/implementation/middleware.py b/src/command_system/implementation/middleware.py index d575b7725..7525fba20 100644 --- a/src/command_system/implementation/middleware.py +++ b/src/command_system/implementation/middleware.py @@ -1,4 +1,4 @@ -# Copyright (C) 2009 Alexander Cherniuk +# Copyright (C) 2009-2010 Alexander Cherniuk # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -26,7 +26,7 @@ from traceback import print_exc from common import gajim from ..framework import CommandProcessor -from ..errors import CommandError +from ..errors import CommandError, NoCommandError class ChatCommandProcessor(CommandProcessor): """ @@ -44,33 +44,40 @@ class ChatCommandProcessor(CommandProcessor): def execute_command(self, name, arguments): try: super(ChatCommandProcessor, self).execute_command(name, arguments) + except NoCommandError, error: + details = dict(name=error.name, message=error.message) + message = "%(name)s: %(message)s\n" % details + message += "Try using the //%(name)s or /say /%(name)s " % details + message += "construct if you intended to send it as a text." + self.echo(message, 'error') except CommandError, error: - self.echo("%s: %s" %(error.name, error.message), 'error') + self.echo("%s: %s" % (error.name, error.message), 'error') except Exception: self.echo("An error occured while trying to execute the command", 'error') print_exc() def looks_like_command(self, text, body, name, arguments): - # Command escape stuff ggoes here. If text was prepended by the command - # prefix twice, like //not_a_command (if prefix is set to /) then it - # will be escaped, that is sent just as a regular message with one (only - # one) prefix removed, so message will be /not_a_command. + # Command escape stuff ggoes here. If text was prepended by the + # command prefix twice, like //not_a_command (if prefix is set + # to /) then it will be escaped, that is sent just as a regular + # message with one (only one) prefix removed, so message will be + # /not_a_command. if body.startswith(self.COMMAND_PREFIX): self.send(body) return True def command_preprocessor(self, command, name, arguments, args, kwargs): - # If command argument contain h or help option - forward it to the /help - # command. Dont forget to pass self, as all commands are unbound. And - # also don't forget to print output. + # If command argument contain h or help option - forward it to + # the /help command. Dont forget to pass self, as all commands + # are unbound. And also don't forget to print output. if 'h' in kwargs or 'help' in kwargs: help = self.get_command('help') self.echo(help(self, name)) return True def command_postprocessor(self, command, name, arguments, args, kwargs, value): - # If command returns a string - print it to a user. A convenient and - # sufficient in most simple cases shortcut to a using echo. + # If command returns a string - print it to a user. A convenient + # and sufficient in most simple cases shortcut to a using echo. if value and isinstance(value, StringTypes): self.echo(value) diff --git a/src/command_system/implementation/standard.py b/src/command_system/implementation/standard.py index 18ee00223..68e41a00f 100644 --- a/src/command_system/implementation/standard.py +++ b/src/command_system/implementation/standard.py @@ -1,4 +1,4 @@ -# Copyright (C) 2009 Alexander Cherniuk +# Copyright (C) 2009-2010 Alexander Cherniuk # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -27,7 +27,7 @@ from common.exceptions import GajimGeneralException from common.logger import Constants from ..errors import CommandError -from ..framework import CommandContainer, command, documentation +from ..framework import CommandContainer, command, doc from ..mapping import generate_usage from hosts import ChatCommands, PrivateChatCommands, GroupChatCommands @@ -45,18 +45,18 @@ class StandardCommonCommands(CommandContainer): HOSTS = (ChatCommands, PrivateChatCommands, GroupChatCommands) @command - @documentation(_("Clear the text window")) + @doc(_("Clear the text window")) def clear(self): self.conv_textview.clear() @command - @documentation(_("Hide the chat buttons")) + @doc(_("Hide the chat buttons")) def compact(self): new_status = not self.hide_chat_buttons self.chat_buttons_set_visible(new_status) @command(overlap=True) - @documentation(_("Show help on a given command or a list of available commands if -(-a)ll is given")) + @doc(_("Show help on a given command or a list of available commands if -(-a)ll is given")) def help(self, command=None, all=False): if command: command = self.get_command(command) @@ -83,17 +83,17 @@ class StandardCommonCommands(CommandContainer): self.echo(help(self, 'help')) @command(raw=True) - @documentation(_("Send a message to the contact")) + @doc(_("Send a message to the contact")) def say(self, message): self.send(message) @command(raw=True) - @documentation(_("Send action (in the third person) to the current chat")) + @doc(_("Send action (in the third person) to the current chat")) def me(self, action): self.send("/me %s" % action) @command('lastlog', overlap=True) - @documentation(_("Show logged messages which mention given text")) + @doc(_("Show logged messages which mention given text")) def grep(self, text, limit=None): results = gajim.logger.get_search_results_for_query(self.contact.jid, text, self.account) @@ -129,7 +129,7 @@ class StandardCommonCommands(CommandContainer): self.echo(formatted) @command(raw=True, empty=True) - @documentation(_(""" + @doc(_(""" Set current the status Status can be given as one of the following values: online, away, @@ -142,7 +142,7 @@ class StandardCommonCommands(CommandContainer): connection.change_status(status, message) @command(raw=True, empty=True) - @documentation(_("Set the current status to away")) + @doc(_("Set the current status to away")) def away(self, message): if not message: message = _("Away") @@ -150,36 +150,40 @@ class StandardCommonCommands(CommandContainer): connection.change_status('away', message) @command('back', raw=True, empty=True) - @documentation(_("Set the current status to online")) + @doc(_("Set the current status to online")) def online(self, message): if not message: message = _("Available") for connection in gajim.connections.itervalues(): connection.change_status('online', message) -class StandardChatCommands(CommandContainer): +class StandardCommonChatCommands(CommandContainer): """ - This command container contains standard command which are unique to - a chat. + This command container contans standard commands, which are common + to a chat and a private chat only. """ - HOSTS = (ChatCommands,) + HOSTS = (ChatCommands, PrivateChatCommands) @command - @documentation(_("Send a ping to the contact")) + @doc(_("Toggle the GPG encryption")) + def gpg(self): + self._toggle_gpg() + + @command + @doc(_("Send a ping to the contact")) def ping(self): if self.account == gajim.ZEROCONF_ACC_NAME: raise CommandError(_('Command is not supported for zeroconf accounts')) gajim.connections[self.account].sendPing(self.contact) @command - @documentation(_("Sends DTMF events through an open audio session")) + @doc(_("Send DTMF events through an open audio session")) def dtmf(self, events): if not self.audio_sid: raise CommandError(_("There is no open audio session with this contact")) # Valid values for DTMF tones are *, # or a number - events = [event for event in events - if event in ('*', '#') or event.isdigit()] + events = filter(lambda e: e in ('*', '#') or e.isdigit (), events) if events: session = gajim.connections[self.account].get_jingle_session( self.contact.get_full_jid(), self.audio_sid) @@ -189,7 +193,7 @@ class StandardChatCommands(CommandContainer): raise CommandError(_("No valid DTMF event specified")) @command - @documentation(_("Toggle audio session")) + @doc(_("Toggle audio session")) def audio(self): if self.audio_state == self.JINGLE_STATE_NOT_AVAILABLE: raise CommandError(_("Video sessions are not available")) @@ -200,7 +204,7 @@ class StandardChatCommands(CommandContainer): self._audio_button.set_active(not state) @command - @documentation(_("Toggle video session")) + @doc(_("Toggle video session")) def video(self): if self.video_state == self.JINGLE_STATE_NOT_AVAILABLE: raise CommandError(_("Video sessions are not available")) @@ -210,24 +214,32 @@ class StandardChatCommands(CommandContainer): state = self._video_button.get_active() self._video_button.set_active(not state) +class StandardChatCommands(CommandContainer): + """ + This command container contains standard commands which are unique + to a chat. + """ + + HOSTS = (ChatCommands,) + class StandardPrivateChatCommands(CommandContainer): """ - This command container contains standard command which are unique to - a private chat. + This command container contains standard commands which are unique + to a private chat. """ HOSTS = (PrivateChatCommands,) -class StandardGroupchatCommands(CommandContainer): +class StandardGroupChatCommands(CommandContainer): """ - This command container contains standard command which are unique to - a group chat. + This command container contains standard commands which are unique + to a group chat. """ HOSTS = (GroupChatCommands,) @command(raw=True) - @documentation(_("Change your nickname in a group chat")) + @doc(_("Change your nickname in a group chat")) def nick(self, new_nick): try: new_nick = helpers.parse_resource(new_nick) @@ -237,7 +249,7 @@ class StandardGroupchatCommands(CommandContainer): self.new_nick = new_nick @command('query', raw=True) - @documentation(_("Open a private chat window with a specified occupant")) + @doc(_("Open a private chat window with a specified occupant")) def chat(self, nick): nicks = gajim.contacts.get_nick_list(self.account, self.room_jid) if nick in nicks: @@ -246,7 +258,7 @@ class StandardGroupchatCommands(CommandContainer): raise CommandError(_("Nickname not found")) @command('msg', raw=True) - @documentation(_("Open a private chat window with a specified occupant and send him a message")) + @doc(_("Open a private chat window with a specified occupant and send him a message")) def message(self, nick, a_message): nicks = gajim.contacts.get_nick_list(self.account, self.room_jid) if nick in nicks: @@ -255,7 +267,7 @@ class StandardGroupchatCommands(CommandContainer): raise CommandError(_("Nickname not found")) @command(raw=True, empty=True) - @documentation(_("Display or change a group chat topic")) + @doc(_("Display or change a group chat topic")) def topic(self, new_topic): if new_topic: self.connection.send_gc_subject(self.room_jid, new_topic) @@ -263,13 +275,13 @@ class StandardGroupchatCommands(CommandContainer): return self.subject @command(raw=True, empty=True) - @documentation(_("Invite a user to a room for a reason")) + @doc(_("Invite a user to a room for a reason")) def invite(self, jid, reason): self.connection.send_invite(self.room_jid, jid, reason) return _("Invited %s to %s") % (jid, self.room_jid) @command(raw=True, empty=True) - @documentation(_("Join a group chat given by a jid, optionally using given nickname")) + @doc(_("Join a group chat given by a jid, optionally using given nickname")) def join(self, jid, nick): if not nick: nick = self.nick @@ -286,12 +298,12 @@ class StandardGroupchatCommands(CommandContainer): pass @command('part', 'close', raw=True, empty=True) - @documentation(_("Leave the groupchat, optionally giving a reason, and close tab or window")) + @doc(_("Leave the groupchat, optionally giving a reason, and close tab or window")) def leave(self, reason): self.parent_win.remove_tab(self, self.parent_win.CLOSE_COMMAND, reason) @command(raw=True, empty=True) - @documentation(_(""" + @doc(_(""" Ban user by a nick or a jid from a groupchat If given nickname is not found it will be treated as a jid. @@ -303,14 +315,14 @@ class StandardGroupchatCommands(CommandContainer): self.connection.gc_set_affiliation(self.room_jid, who, 'outcast', reason or str()) @command(raw=True, empty=True) - @documentation(_("Kick user by a nick from a groupchat")) + @doc(_("Kick user by a nick from a groupchat")) def kick(self, who, reason): if not who in gajim.contacts.get_nick_list(self.account, self.room_jid): raise CommandError(_("Nickname not found")) self.connection.gc_set_role(self.room_jid, who, 'none', reason or str()) @command - @documentation(_("Display names of all group chat occupants")) + @doc(_("Display names of all group chat occupants")) def names(self, verbose=False): get_contact = lambda nick: gajim.contacts.get_gc_contact(self.account, self.room_jid, nick) nicks = gajim.contacts.get_nick_list(self.account, self.room_jid) @@ -331,11 +343,11 @@ class StandardGroupchatCommands(CommandContainer): return ', '.join(nicks) @command('ignore', raw=True) - @documentation(_("Forbid an occupant to send you public or private messages")) + @doc(_("Forbid an occupant to send you public or private messages")) def block(self, who): self.on_block(None, who) @command('unignore', raw=True) - @documentation(_("Allow an occupant to send you public or private messages")) + @doc(_("Allow an occupant to send you public or private messages")) def unblock(self, who): self.on_unblock(None, who) diff --git a/src/command_system/mapping.py b/src/command_system/mapping.py index aa178dc70..8f7a31470 100644 --- a/src/command_system/mapping.py +++ b/src/command_system/mapping.py @@ -1,4 +1,4 @@ -# Copyright (C) 2009 Alexander Cherniuk +# Copyright (C) 2009-2010 Alexander Cherniuk # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/common/multimedia_helpers.py b/src/common/multimedia_helpers.py index b4e574eeb..06ec7b5ca 100644 --- a/src/common/multimedia_helpers.py +++ b/src/common/multimedia_helpers.py @@ -31,6 +31,7 @@ class DeviceManager(object): element = gst.element_factory_make(name, '%spresencetest' % name) if isinstance(element, gst.interfaces.PropertyProbe): element.set_state(gst.STATE_READY) + element.probe_property_name('device') devices = element.probe_get_values_name('device') if devices: self.devices[text % _(' Default device')] = pipe % name @@ -79,7 +80,7 @@ class VideoInputManager(DeviceManager): '%s is-live=true') # Auto src self.detect_element('autovideosrc', _('Autodetect')) - # V4L2 src ; TODO: Figure out why it doesn't work + # V4L2 src self.detect_element('v4l2src', _('V4L2: %s')) # Funny things, just to test... # self.devices['GOOM'] = 'audiotestsrc ! goom' @@ -96,3 +97,4 @@ class VideoOutputManager(DeviceManager): # ximagesink self.detect_element('ximagesink', _('X Window System (without Xv)')) self.detect_element('autovideosink', _('Autodetect')) + diff --git a/src/common/xmpp/auth_nb.py b/src/common/xmpp/auth_nb.py index ff54b80e7..e952abbd6 100644 --- a/src/common/xmpp/auth_nb.py +++ b/src/common/xmpp/auth_nb.py @@ -422,13 +422,18 @@ class SASL(PlugIn): self.on_sasl() raise NodeProcessed + @staticmethod + def _convert_to_iso88591(string): + try: + string = string.decode('utf-8').encode('iso-8859-1') + except UnicodeEncodeError: + pass + return string + def set_password(self, password): - if password is None: - self.password = '' - else: - self.password = password + self.password = '' if password is None else password if self.mechanism == 'SCRAM-SHA-1': - nonce = ''.join('%x' % randint(0, 2**28) for randint in \ + nonce = ''.join('%x' % randint(0, 2 ** 28) for randint in \ itertools.repeat(random.randint, 7)) self.scram_soup = 'n=' + self.username + ',r=' + nonce self.scram_gs2 = 'n,,' # No CB yet. @@ -437,15 +442,9 @@ class SASL(PlugIn): node = Node('auth', attrs={'xmlns': NS_SASL, 'mechanism': self.mechanism}, payload=[sasl_data]) elif self.mechanism == 'DIGEST-MD5': - def convert_to_iso88591(string): - try: - string = string.decode('utf-8').encode('iso-8859-1') - except UnicodeEncodeError: - pass - return string - hash_username = convert_to_iso88591(self.resp['username']) - hash_realm = convert_to_iso88591(self.resp['realm']) - hash_password = convert_to_iso88591(self.password) + hash_username = self._convert_to_iso88591(self.resp['username']) + hash_realm = self._convert_to_iso88591(self.resp['realm']) + hash_password = self._convert_to_iso88591(self.password) A1 = C([H(C([hash_username, hash_realm, hash_password])), self.resp['nonce'], self.resp['cnonce']]) A2 = C(['AUTHENTICATE', self.resp['digest-uri']]) diff --git a/src/dataforms_widget.py b/src/dataforms_widget.py index 28a170827..14dc90626 100644 --- a/src/dataforms_widget.py +++ b/src/dataforms_widget.py @@ -400,7 +400,7 @@ class SingleForm(gtk.Table, object): check.set_active(value in field.values) check.connect('toggled', self.on_list_multi_checkbutton_toggled, field, value) - widget.pack_start(check, expand=False) + widget.pack_start(check, expand=False) else: # more than 5 options: show combobox def on_list_multi_treeview_changed(selection, f): diff --git a/src/gajim-remote.py b/src/gajim-remote.py index f7a82419a..0a0468f44 100644 --- a/src/gajim-remote.py +++ b/src/gajim-remote.py @@ -534,6 +534,8 @@ class GajimRemote: self.arguments += ['']*(len(args)-i) def handle_uri(self): + if len(sys.argv) < 3: + send_error(_('No uri given')) if not sys.argv[2].startswith('xmpp:'): send_error(_('Wrong uri')) sys.argv[2] = sys.argv[2][5:]