Merge branch 'master' of git.poez.io:poezio into slix
Conflicts: src/core/handlers.py src/tabs/xmltab.py
This commit is contained in:
commit
545ad1bd71
15 changed files with 268 additions and 89 deletions
|
@ -116,9 +116,12 @@ use_bookmarks_method =
|
|||
|
||||
# use this option to force the use of local bookmarks
|
||||
# possible values are: anything/false
|
||||
|
||||
use_remote_bookmarks = true
|
||||
|
||||
# Whether you want all bookmarks, even those without
|
||||
# autojoin, to be open on startup
|
||||
open_all_bookmarks = false
|
||||
|
||||
# What will be put after the name, when using autocompletion at the
|
||||
# beginning of the input. A space will always be added after that
|
||||
after_completion = ,
|
||||
|
@ -461,8 +464,9 @@ show_useless_separator = false
|
|||
exec_remote = false
|
||||
|
||||
# Path of the FIFO in which the remote commands will be sent.
|
||||
# The "poezio.fifo" file will be created in this directory
|
||||
# Used with exec_remote set to true, see the documentation of /link for details
|
||||
# Defaults to ./poezio.fifo
|
||||
# Defaults to ./
|
||||
remote_fifo_path =
|
||||
|
||||
# Defines if all tabs are resized at the same time (if set to false)
|
||||
|
|
|
@ -541,10 +541,16 @@ XML tab commands
|
|||
~~~~~~~~~~~~~~~~
|
||||
|
||||
.. glossary::
|
||||
:sorted:
|
||||
|
||||
/clear [XML tab version]
|
||||
Clear the current buffer.
|
||||
|
||||
/dump
|
||||
**Usage:** ``/dump <filename>``
|
||||
|
||||
Write the content of the XML buffer into a file.
|
||||
|
||||
/reset
|
||||
Reset the stanza filter.
|
||||
|
||||
|
|
|
@ -62,8 +62,11 @@ and certificate validation.
|
|||
|
||||
**Default value:** ``[empty]``
|
||||
|
||||
The fingerprint of the SSL certificate as a hexadecimal string, you should
|
||||
not touch it, except if know what you are doing.
|
||||
The SHA-2 fingerprint of the SSL certificate as a hexadecimal string,
|
||||
you should not touch it, except if know what you are doing.
|
||||
|
||||
.. note:: the fingerprint was previously stored in SHA-1, and has been
|
||||
silently upgraded to SHA-2 if the SHA-1 still matched.
|
||||
|
||||
ciphers
|
||||
|
||||
|
@ -194,6 +197,13 @@ Options related to account configuration, nickname…
|
|||
|
||||
The status message poezio will send when connecting.
|
||||
|
||||
open_all_bookmarks
|
||||
|
||||
**Default value:** ``false``
|
||||
|
||||
If this option is set to ``true``, all remote bookmarks, even
|
||||
those that do not have autojoin, will be opened on startup.
|
||||
(the tabs without autojoin will not be joined)
|
||||
|
||||
|
||||
|
||||
|
@ -860,9 +870,11 @@ Other
|
|||
|
||||
remote_fifo_path
|
||||
|
||||
**Default value:** ``./poezio.fifo``
|
||||
**Default value:** ``./``
|
||||
|
||||
The path of the FIFO used to send the commands (see the :term:`exec_remote` option).
|
||||
Poezio will try to create a :file:`poezio.fifo` file in this directory.
|
||||
|
||||
|
||||
save_status
|
||||
|
||||
|
|
|
@ -53,10 +53,11 @@ The following events are poezio-only events, for SleekXMPP events, check out
|
|||
- **message:** :py:class:`~sleekxmpp.Message` that will be sent
|
||||
- **tab:** :py:class:`~tabs.ConversationTab` source
|
||||
|
||||
Same thing than :term:`conversation_say`, but after XHTML generation of the body, if needed.
|
||||
This means you must not insert any colors in the body in the handler, since
|
||||
it may lead to send invalid XML. This hook is less safe than :term:`conversation_say` and
|
||||
you should probably not need it.
|
||||
Same thing than :term:`conversation_say`, but after XHTML generation
|
||||
of the body, if needed. This means you must not insert any colors
|
||||
in the body in the handler, since it may lead to send
|
||||
invalid XML. This hook is less safe than :term:`conversation_say`
|
||||
and you should probably not need it.
|
||||
|
||||
muc_msg
|
||||
- **message:** :py:class:`~sleekxmpp.Message` received
|
||||
|
@ -96,7 +97,7 @@ The following events are poezio-only events, for SleekXMPP events, check out
|
|||
|
||||
normal_presence
|
||||
- **presence:** :py:class:`~sleekxmpp.Presence` received
|
||||
- **resource:** :py:class:`Resource <str>` that emitted the :py:class:`~sleekxmpp.Presence`
|
||||
- **resource:** :py:class:`Resource <str>` that emitted the :py:class:`~sleekxmpp.Presence`
|
||||
|
||||
Triggered when a presence is received from a contact.
|
||||
|
||||
|
@ -104,18 +105,26 @@ The following events are poezio-only events, for SleekXMPP events, check out
|
|||
- **presence:** :py:class:`~sleekxmpp.Presence` received
|
||||
- **tab:** :py:class:`~tabs.MucTab` source
|
||||
|
||||
Triggered when a presence is received from someone in a :py:class:`~tabs.MucTab`.
|
||||
Triggered when a presence is received from someone in a
|
||||
:py:class:`~tabs.MucTab`.
|
||||
|
||||
joining_muc
|
||||
- **presence:** :py:class:`~~sleekxmpp.Presence` to be sent
|
||||
|
||||
Triggered when joining a MUC. The presence can thus be modified
|
||||
before being sent.
|
||||
|
||||
Triggered when joining a MUC. The presence can thus be modified before being sent.
|
||||
changing_nick
|
||||
- **presence:** :py:class:`~~sleekxmpp.Presence` to be sent
|
||||
|
||||
Triggered when the user changes his/her nickname on a MUC. The
|
||||
presence can thus be modified before being sent.
|
||||
|
||||
send_normal_presence
|
||||
- **presence:** :py:class:`~sleekxmpp.Presence` sent
|
||||
|
||||
Triggered when poezio sends a new :py:class:`~sleekxmpp.Presence` stanza. The presence can thus be modified before being sent.
|
||||
Triggered when poezio sends a new :py:class:`~sleekxmpp.Presence`
|
||||
stanza. The presence can thus be modified before being sent.
|
||||
|
||||
muc_join
|
||||
- **presence:** :py:class:`~sleekxmpp.Presence` received
|
||||
|
@ -148,7 +157,8 @@ The following events are poezio-only events, for SleekXMPP events, check out
|
|||
- **message**:py:class:`~sleekxmpp.Message` received
|
||||
- **tab:** :py:class:`~tabs.PrivateTab` source
|
||||
|
||||
Triggered when a private message (that goes in a :py:class:`~tabs.PrivateTab`)
|
||||
is ignored automatically by poezio.
|
||||
Triggered when a private message (that goes in a
|
||||
:py:class:`~tabs.PrivateTab`) is ignored automatically by poezio.
|
||||
|
||||
**tab** is always ``None``, except when a tab has already been opened.
|
||||
**tab** is always ``None``, except when a tab has already been
|
||||
opened.
|
||||
|
|
|
@ -15,6 +15,8 @@ Key bindings listing
|
|||
--------------------
|
||||
Some key bindings are available only in some tabs, others are global.
|
||||
|
||||
.. _global-keys:
|
||||
|
||||
Global keys
|
||||
~~~~~~~~~~~
|
||||
These keys work in **any** tab.
|
||||
|
@ -46,6 +48,8 @@ highlight > message > non-empty input).
|
|||
|
||||
**Alt-C**: Scroll the information buffer down.
|
||||
|
||||
.. _input-keys:
|
||||
|
||||
Input keys
|
||||
~~~~~~~~~~
|
||||
These keys concern only the inputs.
|
||||
|
@ -75,9 +79,11 @@ for example in conjunction with the bind command, to help you know how to
|
|||
bind something to a key combination without having to remember how to write
|
||||
them by hand.
|
||||
|
||||
.. _chattab-keys:
|
||||
|
||||
Chat tab input keys
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
These keys work in any conversation tab (MultiUserChat, Private or
|
||||
Conversation tabs).
|
||||
|
||||
|
@ -118,6 +124,8 @@ current conversation, if any.
|
|||
- u: Underlined
|
||||
- o: Stop formatting
|
||||
|
||||
.. _muctab-keys:
|
||||
|
||||
MultiUserChat tab input keys
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
@ -133,8 +141,11 @@ These keys work only in the MultiUserChat tab.
|
|||
|
||||
**tabulation**: Complete a nick.
|
||||
|
||||
.. _muclisttab-keys:
|
||||
|
||||
MultiUserChat List tab input keys
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
These keys work only in the MultiUserChat List tab (obtained with :term:`/list`).
|
||||
|
||||
**Up**: Go up one row.
|
||||
|
@ -152,6 +163,8 @@ These keys work only in the MultiUserChat List tab (obtained with :term:`/list`)
|
|||
**PageDown**: Scroll a page of chats down.
|
||||
|
||||
|
||||
.. _rostertab-keys:
|
||||
|
||||
Roster tab input keys
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
@ -184,8 +197,11 @@ These keys work only in the Roster tab (the tab number 0).
|
|||
|
||||
**PageDown**: Scroll a page of contacts down.
|
||||
|
||||
.. _forms-keys:
|
||||
|
||||
Data Forms tab keys
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
**Ctrl+y**: Validate the form, send it and close the tab.
|
||||
|
||||
**Ctrl+g**: Cancel that form (do not send your changes) and close the
|
||||
|
|
|
@ -8,13 +8,13 @@ Poezio is composed of tabs which can be of various types. Each tab type has
|
|||
a distinct interface, list of commands and list of key shortcuts, in addition
|
||||
to the global commands and key shortcuts.
|
||||
|
||||
The Tab list
|
||||
~~~~~~~~~~~~
|
||||
Tab list
|
||||
~~~~~~~~
|
||||
|
||||
Since Poezio 0.7.5, there are now two ways to show the available tabs:
|
||||
There are two ways of showing the open tabs:
|
||||
|
||||
The old way: horizontal list
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Horizontal list
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
This is the default method.
|
||||
|
||||
|
@ -24,8 +24,8 @@ has a number, each time you open a new tab, it gets the next available number.
|
|||
.. figure:: ./images/tab_bar.png
|
||||
:alt: Example of 5 opened tabs
|
||||
|
||||
The new way: vertical list
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Vertical list
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
On all tabs, you get a pane on the left side of the screen that shows a list
|
||||
of the opened tabs. As stated above, each tab has a number, and each time you
|
||||
|
@ -57,6 +57,8 @@ Generalities
|
|||
|
||||
:ref:`global-commands`
|
||||
|
||||
:ref:`Global shortcuts <global-keys>`
|
||||
|
||||
The tab numbered **0** is always the **roster** tab, the other tabs can be of any
|
||||
type.
|
||||
|
||||
|
@ -65,11 +67,11 @@ type.
|
|||
|
||||
The status of a tab is represented by its color:
|
||||
|
||||
* **blue** (tab **0**): an inactive tab of any type, nothing new to see
|
||||
* **Blue** (tab **0**): an inactive tab of any type, nothing new to see
|
||||
there.
|
||||
* **purple** (tab **1**): a :ref:`muctab` with at least one new
|
||||
* **Purple** (tab **1**): a :ref:`muctab` with at least one new
|
||||
unread message.
|
||||
* **green** (tab **2**): a tab of a private conversation (:ref:`privatetab` or :ref:`conversationtab`)
|
||||
* **Green** (tab **2**): a tab of a private conversation (:ref:`privatetab` or :ref:`conversationtab`)
|
||||
with a new message to read.
|
||||
* **Cyan** (tab **3**): the current tab.
|
||||
* **Red** (tab **4**): a :ref:`muctab` with at least one new highlight
|
||||
|
@ -92,19 +94,22 @@ Roster tab
|
|||
|
||||
:ref:`Specific commands <rostertab-commands>`
|
||||
|
||||
This is a unique tab, always numbered **0**. It contains the list of your
|
||||
contacts. You can add/remove/edit/search contacts from there, and you can open
|
||||
a conversation with them.
|
||||
:ref:`Specific shortcuts <rostertab-keys>`
|
||||
|
||||
Use the **direction arrows** to browse the list, the ``Space`` key to fold or unfold a group
|
||||
or a contact.
|
||||
This is a unique tab, always numbered **0**. It contains the list of your
|
||||
contacts. You can add (:term:`/add`, :term:`/accept`), remove
|
||||
(:term:`/remove`) and search contacts from there, and you can open
|
||||
a conversation with them (``Enter`` key).
|
||||
|
||||
Use the **direction arrows** (↑↓) to browse the list, the ``Space`` key to
|
||||
fold or unfold a group or a contact.
|
||||
|
||||
.. figure:: ./images/roster.png
|
||||
:alt: The roster tab
|
||||
|
||||
#. The area where information messages are displayed.
|
||||
#. The actual list of contacts. The first level is group, the second is the
|
||||
contacts and the third is the resources of you online contacts.
|
||||
#. Area where information messages are displayed.
|
||||
#. Actual list of contacts. The first level is group, the second is the
|
||||
contacts and the third is the resources of your online contacts.
|
||||
#. More informations about the selected contact.
|
||||
|
||||
.. _muctab:
|
||||
|
@ -114,6 +119,10 @@ MultiUserChat tab
|
|||
|
||||
:ref:`Specific commands <muctab-commands>`
|
||||
|
||||
:ref:`Specific shortcuts <muctab-keys>`
|
||||
|
||||
:ref:`Chat shortcuts <chattab-keys>`
|
||||
|
||||
This tab contains a multi-user conversation.
|
||||
|
||||
.. figure:: ./images/muc.png
|
||||
|
@ -164,6 +173,8 @@ Private tab
|
|||
~~~~~~~~~~~
|
||||
:ref:`Specific commands <privatetab-commands>`
|
||||
|
||||
:ref:`Chat shortcuts <chattab-keys>`
|
||||
|
||||
This is the tab opened with the :term:`/query` command in a :ref:`muctab`, letting you talk in private
|
||||
with a participant of a multi-user chat.
|
||||
|
||||
|
@ -180,6 +191,8 @@ Conversation tab
|
|||
|
||||
:ref:`Specific commands <conversationtab-commands>`
|
||||
|
||||
:ref:`Chat shortcuts <chattab-keys>`
|
||||
|
||||
A tab opened from the roster or :term:`/message`, to talk in private with one of your contacts.
|
||||
|
||||
.. figure:: ./images/conversation.png
|
||||
|
@ -194,6 +207,8 @@ status message of the contact. Plugins may add some elements to the status line.
|
|||
Dataforms tab
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
:ref:`Specific shortcuts <formtab-keys>`
|
||||
|
||||
This tab lets you view a form received from a remote entity, edit the values and
|
||||
send everything back. It is mostly used to configure MUCs with the
|
||||
:term:`/configure` command but can actually be used for almost anything.
|
||||
|
@ -211,6 +226,8 @@ You can then send the completed form using ``Ctrl+y`` or cancel using ``Ctrl+g``
|
|||
List tab
|
||||
~~~~~~~~
|
||||
|
||||
:ref:`Specific shortcuts <muclisttab-keys>`
|
||||
|
||||
This tab lists all public rooms on a MUC service (with the :term:`/list` command).
|
||||
It is currently very limited but will be improved in the future. There currently
|
||||
is no way to search a room.
|
||||
|
|
|
@ -41,8 +41,8 @@ Install the python module:
|
|||
cd pure-python-otr
|
||||
python3 setup.py install --user
|
||||
|
||||
You can also use pip with the requirements.txt at the root of
|
||||
the poezio directory.
|
||||
You can also use pip in a virtualenv (built-in as pyvenv_ with python since 3.3)
|
||||
with the requirements.txt at the root of the poezio directory.
|
||||
|
||||
|
||||
Usage
|
||||
|
@ -143,25 +143,34 @@ Configuration
|
|||
|
||||
Allow OTRv1
|
||||
|
||||
timeout
|
||||
**Default:** ``3``
|
||||
|
||||
The number of seconds poezio will wait until notifying you
|
||||
that the OTR session was not established. A negative or null
|
||||
value will disable this notification.
|
||||
|
||||
log
|
||||
**Default:** false
|
||||
|
||||
Log conversations (OTR start/end marker, and messages).
|
||||
|
||||
The :term:`allow_v1`, :term:`allow_v2`, :term:`decode_html`
|
||||
The :term:`allow_v1`, :term:`allow_v2`, :term:`decode_xhtml`
|
||||
and :term:`log` configuration parameters are tab-specific.
|
||||
|
||||
Important details
|
||||
-----------------
|
||||
|
||||
The OTR session is considered for a full jid, but the trust is considered
|
||||
with a bare JID. This is important to know in the case of Private Chats, since
|
||||
you cannot always get the real the JID of your contact (or check if the same
|
||||
nick is used by different people).
|
||||
The OTR session is considered for a full JID (e.g. toto@example/**client1**),
|
||||
but the trust is set with a bare JID (e.g. toto@example). This is important
|
||||
in the case of Private Chats (in a chatroom), since you cannot always get the
|
||||
real JID of your contact (or check if the same nick is used by different people).
|
||||
|
||||
.. _Off The Record messaging: http://wiki.xmpp.org/web/OTR
|
||||
.. _pyvenv: https://docs.python.org/3/using/scripts.html#pyvenv-creating-virtual-environments
|
||||
|
||||
"""
|
||||
|
||||
from gettext import gettext as _
|
||||
import potr
|
||||
import logging
|
||||
|
@ -588,6 +597,7 @@ class Plugin(BasePlugin):
|
|||
name = tab.name
|
||||
color_jid = '\x19%s}' % dump_tuple(get_theme().COLOR_MUC_JID)
|
||||
color_info = '\x19%s}' % dump_tuple(get_theme().COLOR_INFORMATION_TEXT)
|
||||
color_normal = '\x19%s}' % dump_tuple(get_theme().COLOR_NORMAL_TEXT)
|
||||
if isinstance(tab, DynamicConversationTab) and tab.locked_resource:
|
||||
name = safeJID(tab.name)
|
||||
name.resource = tab.locked_resource
|
||||
|
@ -597,15 +607,54 @@ class Plugin(BasePlugin):
|
|||
context.disconnect()
|
||||
elif arg == 'start' or arg == 'refresh':
|
||||
otr = self.get_context(name)
|
||||
secs = self.config.get('timeout', 3)
|
||||
def notify_otr_timeout():
|
||||
if otr.state != STATE_ENCRYPTED:
|
||||
text = _('%(jid_c)s%(jid)s%(info)s did not enable'
|
||||
' OTR after %(sec)s seconds.') % {
|
||||
'jid': tab.name,
|
||||
'info': color_info,
|
||||
'jid_c': color_jid,
|
||||
'sec': secs}
|
||||
tab.add_message(text, typ=0)
|
||||
self.core.refresh_window()
|
||||
if secs > 0:
|
||||
event = self.api.create_delayed_event(secs, notify_otr_timeout)
|
||||
self.api.add_timed_event(event)
|
||||
self.core.xmpp.send_message(mto=name, mtype='chat',
|
||||
mbody=self.contexts[name].sendMessage(0, b'?OTRv?').decode())
|
||||
text = _('%(info)sOTR request to %(jid_c)s%(jid)s%(info)s sent.') % {
|
||||
'jid': tab.name,
|
||||
'info': color_info,
|
||||
'jid_c': color_jid}
|
||||
tab.add_message(text, typ=0)
|
||||
elif arg == 'ourfpr':
|
||||
fpr = self.account.getPrivkey()
|
||||
self.api.information('Your OTR key fingerprint is %s' % fpr, 'OTR')
|
||||
text = _('%(info)sYour OTR key fingerprint is %(norm)s%(fpr)s.') % {
|
||||
'jid': tab.name,
|
||||
'info': color_info,
|
||||
'norm': color_normal,
|
||||
'fpr': fpr}
|
||||
tab.add_message(text, typ=0)
|
||||
elif arg == 'fpr':
|
||||
if name in self.contexts:
|
||||
ctx = self.contexts[name]
|
||||
self.api.information('The key fingerprint for %s is %s' % (name, ctx.getCurrentKey()) , 'OTR')
|
||||
if ctx.getCurrentKey() is not None:
|
||||
text = _('%(info)sThe key fingerprint for %(jid_c)s'
|
||||
'%(jid)s%(info)s is %(norm)s%(fpr)s%(info)s.') % {
|
||||
'jid': tab.name,
|
||||
'info': color_info,
|
||||
'norm': color_normal,
|
||||
'jid_c': color_jid,
|
||||
'fpr': ctx.getCurrentKey()}
|
||||
tab.add_message(text, typ=0)
|
||||
else:
|
||||
text = _('%(jid_c)s%(jid)s%(info)s has no'
|
||||
' key currently in use.') % {
|
||||
'jid': tab.name,
|
||||
'info': color_info,
|
||||
'jid_c': color_jid}
|
||||
tab.add_message(text, typ=0)
|
||||
elif arg == 'drop':
|
||||
# drop the privkey (and obviously, end the current conversations before that)
|
||||
for context in self.contexts.values():
|
||||
|
|
|
@ -19,6 +19,28 @@ Usage
|
|||
|
||||
If there is a message at 21:12:23, it will be put in the input. If there
|
||||
isn’t, you will get a warning.
|
||||
|
||||
Options
|
||||
-------
|
||||
|
||||
.. glossary::
|
||||
:sorted:
|
||||
|
||||
before_quote
|
||||
|
||||
**Default value:** ``[empty]``
|
||||
|
||||
Text to insert before the quote. ``%(nick)s`` and ``%(time)s`` can
|
||||
be used to insert the nick of the user who sent the message or the
|
||||
time of the message.
|
||||
|
||||
after_quote
|
||||
|
||||
**Default value:** ``[empty]``
|
||||
|
||||
Text to insert after the quote. ``%(nick)s`` and ``%(time)s`` can
|
||||
be used to insert the nick of the user who sent the message or the
|
||||
time of the message.
|
||||
"""
|
||||
from plugin import BasePlugin
|
||||
from xhtml import clean_text
|
||||
|
|
|
@ -61,7 +61,7 @@ class Plugin(BasePlugin):
|
|||
if not nick in self.tabs[tab]:
|
||||
self.tabs[tab][nick] = []
|
||||
self.tabs[tab][nick].append(msg)
|
||||
self.api.information('Will tell %s' % nick, 'Info')
|
||||
self.api.information('Message for %s queued' % nick, 'Info')
|
||||
|
||||
def command_untell(self, args):
|
||||
"""/untell <nick>"""
|
||||
|
@ -72,10 +72,11 @@ class Plugin(BasePlugin):
|
|||
if not nick in self.tabs[tab]:
|
||||
return
|
||||
del self.tabs[tab][nick]
|
||||
self.api.information('Messages for %s unqueued' % nick, 'Info')
|
||||
|
||||
def completion_untell(self, the_input):
|
||||
tab = self.api.current_tab()
|
||||
if not tab in self.tabs:
|
||||
return the_input.auto_completion([], '')
|
||||
return the_input.auto_completion(list(self.tabs[tab]), '')
|
||||
return the_input.auto_completion(list(self.tabs[tab]), '', quotify=False)
|
||||
|
||||
|
|
|
@ -943,7 +943,7 @@ def command_xml_tab(self, arg=''):
|
|||
def command_adhoc(self, arg):
|
||||
arg = arg.split()
|
||||
if len(arg) > 1:
|
||||
return self.command_help('list')
|
||||
return self.command_help('ad-hoc')
|
||||
elif arg:
|
||||
jid = safeJID(arg[0])
|
||||
else:
|
||||
|
|
|
@ -9,7 +9,7 @@ import curses
|
|||
import ssl
|
||||
import time
|
||||
import functools
|
||||
from hashlib import sha1
|
||||
from hashlib import sha1, sha512
|
||||
from gettext import gettext as _
|
||||
|
||||
from slixmpp import InvalidJID
|
||||
|
@ -891,24 +891,25 @@ def on_session_start(self, event):
|
|||
def _join_initial_rooms(bookmarks):
|
||||
"""Join all rooms given in the iterator `bookmarks`"""
|
||||
for bm in bookmarks:
|
||||
tab = self.get_tab_by_name(bm.jid, tabs.MucTab)
|
||||
nick = bm.nick if bm.nick else self.own_nick
|
||||
if not tab:
|
||||
self.open_new_room(bm.jid, nick, False)
|
||||
self.initial_joins.append(bm.jid)
|
||||
histo_length = config.get('muc_history_length', 20)
|
||||
if histo_length == -1:
|
||||
histo_length = None
|
||||
if histo_length is not None:
|
||||
histo_length = str(histo_length)
|
||||
# do not join rooms that do not have autojoin
|
||||
# but display them anyway
|
||||
if bm.autojoin:
|
||||
muc.join_groupchat(self, bm.jid, nick,
|
||||
passwd=bm.password,
|
||||
maxhistory=histo_length,
|
||||
status=self.status.message,
|
||||
show=self.status.show)
|
||||
if bm.autojoin or config.get('open_all_bookmarks', False):
|
||||
tab = self.get_tab_by_name(bm.jid, tabs.MucTab)
|
||||
nick = bm.nick if bm.nick else self.own_nick
|
||||
if not tab:
|
||||
self.open_new_room(bm.jid, nick, False)
|
||||
self.initial_joins.append(bm.jid)
|
||||
histo_length = config.get('muc_history_length', 20)
|
||||
if histo_length == -1:
|
||||
histo_length = None
|
||||
if histo_length is not None:
|
||||
histo_length = str(histo_length)
|
||||
# do not join rooms that do not have autojoin
|
||||
# but display them anyway
|
||||
if bm.autojoin:
|
||||
muc.join_groupchat(self, bm.jid, nick,
|
||||
passwd=bm.password,
|
||||
maxhistory=histo_length,
|
||||
status=self.status.message,
|
||||
show=self.status.show)
|
||||
def _join_remote_only():
|
||||
remote_bookmarks = (bm for bm in bookmark.bookmarks if (bm.method in ("pep", "privatexml")))
|
||||
_join_initial_rooms(remote_bookmarks)
|
||||
|
@ -1101,16 +1102,27 @@ def validate_ssl(self, pem):
|
|||
config.set_and_save('certificate', cert)
|
||||
|
||||
der = ssl.PEM_cert_to_DER_cert(pem)
|
||||
digest = sha1(der).hexdigest().upper()
|
||||
found_cert = ':'.join(i + j for i, j in zip(digest[::2], digest[1::2]))
|
||||
sha1_digest = sha1(der).hexdigest().upper()
|
||||
sha1_found_cert = ':'.join(i + j for i, j in zip(sha1_digest[::2], sha1_digest[1::2]))
|
||||
sha2_digest = sha512(der).hexdigest().upper()
|
||||
sha2_found_cert = ':'.join(i + j for i, j in zip(sha2_digest[::2], sha2_digest[1::2]))
|
||||
if cert:
|
||||
if found_cert == cert:
|
||||
log.debug('Cert %s OK', found_cert)
|
||||
if sha1_found_cert == cert:
|
||||
log.debug('Cert %s OK', sha1_found_cert)
|
||||
log.debug('Current hash is SHA-1, moving to SHA-2 (%s)',
|
||||
sha2_found_cert)
|
||||
config.set_and_save('certificate', sha2_found_cert)
|
||||
return
|
||||
elif sha2_found_cert == cert:
|
||||
log.debug('Cert %s OK', sha2_found_cert)
|
||||
return
|
||||
else:
|
||||
saved_input = self.current_tab().input
|
||||
log.debug('\nWARNING: CERTIFICATE CHANGED old: %s, new: %s\n', cert, found_cert)
|
||||
input = windows.YesNoInput(text="WARNING! Server certificate has changed, accept? (y/n) (%s)" % found_cert)
|
||||
log.debug('\nWARNING: CERTIFICATE CHANGED old: %s, new: %s\n', cert, sha2_found_cert)
|
||||
self.information('New certificate found (sha-2 hash:'
|
||||
' %s)\nPlease validate or abort' % sha2_found_cert,
|
||||
'Warning')
|
||||
input = windows.YesNoInput(text="WARNING! Server certificate has changed, accept? (y/n)")
|
||||
self.current_tab().input = input
|
||||
input.resize(1, self.current_tab().width, self.current_tab().height-1, 0)
|
||||
input.refresh()
|
||||
|
@ -1121,16 +1133,16 @@ def validate_ssl(self, pem):
|
|||
self.current_tab().input = saved_input
|
||||
self.paused = False
|
||||
if input.value:
|
||||
self.information('Setting new certificate: old: %s, new: %s' % (cert, found_cert), 'Info')
|
||||
log.debug('Setting certificate to %s', found_cert)
|
||||
if not config.silent_set('certificate', found_cert):
|
||||
self.information('Setting new certificate: old: %s, new: %s' % (cert, sha2_found_cert), 'Info')
|
||||
log.debug('Setting certificate to %s', sha2_found_cert)
|
||||
if not config.silent_set('certificate', sha2_found_cert):
|
||||
self.information(_('Unable to write in the config file'), 'Error')
|
||||
else:
|
||||
self.information('You refused to validate the certificate. You are now disconnected', 'Info')
|
||||
self.xmpp.disconnect()
|
||||
else:
|
||||
log.debug('First time. Setting certificate to %s', found_cert)
|
||||
if not config.silent_set('certificate', found_cert):
|
||||
log.debug('First time. Setting certificate to %s', sha2_found_cert)
|
||||
if not config.silent_set('certificate', sha2_found_cert):
|
||||
self.information(_('Unable to write in the config file'), 'Error')
|
||||
|
||||
def _composing_tab_state(tab, state):
|
||||
|
|
|
@ -385,11 +385,15 @@ class DynamicConversationTab(ConversationTab):
|
|||
assert(resource)
|
||||
if resource != self.locked_resource:
|
||||
self.locked_resource = resource
|
||||
info = '\x19%s}' % dump_tuple(get_theme().COLOR_INFORMATION_TEXT)
|
||||
jid_c = '\x19%s}' % dump_tuple(get_theme().COLOR_MUC_JID)
|
||||
|
||||
message = _('\x19%s}Conversation locked to %s/%s.') % (
|
||||
dump_tuple(get_theme().COLOR_INFORMATION_TEXT),
|
||||
self.name,
|
||||
resource)
|
||||
message = _('%(info)sConversation locked to '
|
||||
'%(jid_c)s%(jid)s/%(resource)s%(info)s.') % {
|
||||
'info': info,
|
||||
'jid_c': jid_c,
|
||||
'jid': self.name,
|
||||
'resource': resource}
|
||||
self.add_message(message, typ=0)
|
||||
self.check_features()
|
||||
|
||||
|
@ -405,16 +409,18 @@ class DynamicConversationTab(ConversationTab):
|
|||
self.remote_wants_chatstates = None
|
||||
if self.locked_resource != None:
|
||||
self.locked_resource = None
|
||||
info = '\x19%s}' % dump_tuple(get_theme().COLOR_INFORMATION_TEXT)
|
||||
jid_c = '\x19%s}' % dump_tuple(get_theme().COLOR_MUC_JID)
|
||||
|
||||
if from_:
|
||||
message = _('\x19%s}Conversation unlocked '
|
||||
'(received activity from %s).') % (
|
||||
dump_tuple(get_theme().COLOR_INFORMATION_TEXT),
|
||||
from_)
|
||||
message = _('%(info)sConversation unlocked (received activity'
|
||||
' from %(jid_c)s%(jid)s%(info)s).') % {
|
||||
'info': info,
|
||||
'jid_c': jid_c,
|
||||
'jid': from_}
|
||||
self.add_message(message, typ=0)
|
||||
else:
|
||||
message = _('\x19%s}Conversation unlocked.') % (
|
||||
dump_tuple(get_theme().COLOR_INFORMATION_TEXT))
|
||||
message = _('%sConversation unlocked.') % info
|
||||
self.add_message(message, typ=0)
|
||||
|
||||
def get_dest_jid(self):
|
||||
|
|
|
@ -355,7 +355,8 @@ class MucTab(ChatTab):
|
|||
dump_tuple(theme.color_role(user.role)),
|
||||
user.role or 'None',
|
||||
'\n%s' % user.status if user.status else '')
|
||||
self.core.information(info, 'Info')
|
||||
self.add_message(info, typ=0)
|
||||
self.core.refresh_window()
|
||||
|
||||
def command_configure(self, arg):
|
||||
"""
|
||||
|
@ -1525,11 +1526,11 @@ class MucTab(ChatTab):
|
|||
config.get_by_tabname('notify_messages',
|
||||
True, self.name)):
|
||||
self.state = 'message'
|
||||
if time:
|
||||
if time and not txt.startswith('/me'):
|
||||
txt = '\x19%(info_col)s}%(txt)s' % {
|
||||
'txt': txt,
|
||||
'info_col': dump_tuple(get_theme().COLOR_LOG_MSG)}
|
||||
elif (not nickname or time) and not txt.startswith('/me '):
|
||||
elif not nickname:
|
||||
txt = '\x19%(info_col)s}%(txt)s' % {
|
||||
'txt': txt,
|
||||
'info_col': dump_tuple(get_theme().COLOR_INFORMATION_TEXT)}
|
||||
|
|
|
@ -11,12 +11,14 @@ import logging
|
|||
log = logging.getLogger(__name__)
|
||||
|
||||
import curses
|
||||
import os
|
||||
from slixmpp.xmlstream import matcher
|
||||
from slixmpp.xmlstream.handler import Callback
|
||||
|
||||
from . import Tab
|
||||
|
||||
import windows
|
||||
from xhtml import clean_text
|
||||
|
||||
class XMLTab(Tab):
|
||||
def __init__(self):
|
||||
|
@ -45,6 +47,10 @@ class XMLTab(Tab):
|
|||
usage=_('<xml mask>'),
|
||||
desc=_('Show only the stanzas matching the given xml mask.'),
|
||||
shortdesc=_('Filter by xml mask.'))
|
||||
self.register_command('dump', self.command_dump,
|
||||
usage=_('<filename>'),
|
||||
desc=_('Writes the content of the XML buffer into a file.'),
|
||||
shortdesc=_('Write in a file.'))
|
||||
self.input = self.default_help_message
|
||||
self.key_func['^T'] = self.close
|
||||
self.key_func['^I'] = self.completion
|
||||
|
@ -111,6 +117,17 @@ class XMLTab(Tab):
|
|||
self.filter = ''
|
||||
self.refresh()
|
||||
|
||||
def command_dump(self, arg):
|
||||
"""/dump <filename>"""
|
||||
xml = self.core.xml_buffer.messages[:]
|
||||
text = '\n'.join(('%s %s' % (msg.str_time, clean_text(msg.txt)) for msg in xml))
|
||||
filename = os.path.expandvars(os.path.expanduser(arg))
|
||||
try:
|
||||
with open(filename, 'w') as fd:
|
||||
fd.write(text)
|
||||
except Exception as e:
|
||||
self.core.information('Could not write the XML dump: %s' % e, 'Error')
|
||||
|
||||
def on_slash(self):
|
||||
"""
|
||||
'/' is pressed, activate the input
|
||||
|
|
|
@ -33,6 +33,9 @@ class HelpText(Win):
|
|||
def do_command(self, key, raw=False):
|
||||
return False
|
||||
|
||||
def on_delete(self):
|
||||
return
|
||||
|
||||
class YesNoInput(Win):
|
||||
"""
|
||||
A Window just displaying a Yes/No input
|
||||
|
@ -77,3 +80,6 @@ class YesNoInput(Win):
|
|||
keyboard.continuation_keys_callback = cb
|
||||
keyboard.continuation_keys_callback = cb
|
||||
|
||||
def on_delete(self):
|
||||
return
|
||||
|
||||
|
|
Loading…
Reference in a new issue