Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Maxime Buquet
slixmpp
Commits
6a43559f
Commit
6a43559f
authored
Nov 23, 2017
by
Link Mauve
Browse files
Add a Markup plugin.
parent
80b9cd43
Changes
4
Hide whitespace changes
Inline
Side-by-side
examples/markup.py
0 → 100755
View file @
6a43559f
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Slixmpp: The Slick XMPP Library
Copyright (C) 2010 Nathanael C. Fritz
This file is part of Slixmpp.
See the file LICENSE for copying permission.
"""
import
logging
from
getpass
import
getpass
from
argparse
import
ArgumentParser
import
slixmpp
from
slixmpp.plugins.xep_0394
import
stanza
as
markup_stanza
class
EchoBot
(
slixmpp
.
ClientXMPP
):
"""
A simple Slixmpp bot that will echo messages it
receives, along with a short thank you message.
"""
def
__init__
(
self
,
jid
,
password
):
slixmpp
.
ClientXMPP
.
__init__
(
self
,
jid
,
password
)
# The session_start event will be triggered when
# the bot establishes its connection with the server
# and the XML streams are ready for use. We want to
# listen for this event so that we we can initialize
# our roster.
self
.
add_event_handler
(
"session_start"
,
self
.
start
)
# The message event is triggered whenever a message
# stanza is received. Be aware that that includes
# MUC messages and error messages.
self
.
add_event_handler
(
"message"
,
self
.
message
)
def
start
(
self
,
event
):
"""
Process the session_start event.
Typical actions for the session_start event are
requesting the roster and broadcasting an initial
presence stanza.
Arguments:
event -- An empty dictionary. The session_start
event does not provide any additional
data.
"""
self
.
send_presence
()
self
.
get_roster
()
def
message
(
self
,
msg
):
"""
Process incoming message stanzas. Be aware that this also
includes MUC messages and error messages. It is usually
a good idea to check the messages's type before processing
or sending replies.
Arguments:
msg -- The received message stanza. See the documentation
for stanza objects and the Message stanza to see
how it may be used.
"""
body
=
msg
[
'body'
]
new_body
=
self
[
'xep_0394'
].
to_plain_text
(
body
,
msg
[
'markup'
])
xhtml
=
self
[
'xep_0394'
].
to_xhtml_im
(
body
,
msg
[
'markup'
])
print
(
'Plain text:'
,
new_body
)
print
(
'XHTML-IM:'
,
xhtml
[
'body'
])
message
=
msg
.
reply
()
message
[
'body'
]
=
new_body
message
[
'html'
][
'body'
]
=
xhtml
[
'body'
]
self
.
send
(
message
)
if
__name__
==
'__main__'
:
# Setup the command line arguments.
parser
=
ArgumentParser
(
description
=
EchoBot
.
__doc__
)
# Output verbosity options.
parser
.
add_argument
(
"-q"
,
"--quiet"
,
help
=
"set logging to ERROR"
,
action
=
"store_const"
,
dest
=
"loglevel"
,
const
=
logging
.
ERROR
,
default
=
logging
.
INFO
)
parser
.
add_argument
(
"-d"
,
"--debug"
,
help
=
"set logging to DEBUG"
,
action
=
"store_const"
,
dest
=
"loglevel"
,
const
=
logging
.
DEBUG
,
default
=
logging
.
INFO
)
# JID and password options.
parser
.
add_argument
(
"-j"
,
"--jid"
,
dest
=
"jid"
,
help
=
"JID to use"
)
parser
.
add_argument
(
"-p"
,
"--password"
,
dest
=
"password"
,
help
=
"password to use"
)
args
=
parser
.
parse_args
()
# Setup logging.
logging
.
basicConfig
(
level
=
args
.
loglevel
,
format
=
'%(levelname)-8s %(message)s'
)
if
args
.
jid
is
None
:
args
.
jid
=
input
(
"Username: "
)
if
args
.
password
is
None
:
args
.
password
=
getpass
(
"Password: "
)
# Setup the EchoBot and register plugins. Note that while plugins may
# have interdependencies, the order in which you register them does
# not matter.
xmpp
=
EchoBot
(
args
.
jid
,
args
.
password
)
xmpp
.
register_plugin
(
'xep_0030'
)
# Service Discovery
xmpp
.
register_plugin
(
'xep_0199'
)
# XMPP Ping
xmpp
.
register_plugin
(
'xep_0394'
)
# Message Markup
# Connect to the XMPP server and start processing XMPP stanzas.
xmpp
.
connect
()
xmpp
.
process
()
slixmpp/plugins/xep_0394/__init__.py
0 → 100644
View file @
6a43559f
"""
Slixmpp: The Slick XMPP Library
Copyright (C) 2017 Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
This file is part of Slixmpp.
See the file LICENSE for copying permission.
"""
from
slixmpp.plugins.base
import
register_plugin
from
slixmpp.plugins.xep_0394.stanza
import
Markup
,
Span
,
BlockCode
,
List
,
Li
,
BlockQuote
from
slixmpp.plugins.xep_0394.markup
import
XEP_0394
register_plugin
(
XEP_0394
)
slixmpp/plugins/xep_0394/markup.py
0 → 100644
View file @
6a43559f
"""
Slixmpp: The Slick XMPP Library
Copyright (C) 2017 Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
This file is part of Slixmpp.
See the file LICENSE for copying permission.
"""
from
slixmpp.stanza
import
Message
from
slixmpp.plugins
import
BasePlugin
from
slixmpp.xmlstream
import
register_stanza_plugin
,
ET
,
tostring
from
slixmpp.plugins.xep_0394
import
stanza
,
Markup
,
Span
,
BlockCode
,
List
,
Li
,
BlockQuote
from
slixmpp.plugins.xep_0071
import
XHTML_IM
class
Start
:
def
__init__
(
self
,
elem
):
self
.
elem
=
elem
def
__repr__
(
self
):
return
'Start(%s)'
%
self
.
elem
class
End
:
def
__init__
(
self
,
elem
):
self
.
elem
=
elem
def
__repr__
(
self
):
return
'End(%s)'
%
self
.
elem
class
XEP_0394
(
BasePlugin
):
name
=
'xep_0394'
description
=
'XEP-0394: Message Markup'
dependencies
=
{
'xep_0030'
,
'xep_0071'
}
stanza
=
stanza
def
plugin_init
(
self
):
register_stanza_plugin
(
Message
,
Markup
)
def
session_bind
(
self
,
jid
):
self
.
xmpp
[
'xep_0030'
].
add_feature
(
feature
=
Markup
.
namespace
)
def
plugin_end
(
self
):
self
.
xmpp
[
'xep_0030'
].
del_feature
(
feature
=
Markup
.
namespace
)
@
staticmethod
def
_split_first_level
(
body
,
markup_elem
):
split_points
=
[]
elements
=
{}
for
markup
in
markup_elem
[
'substanzas'
]:
start
=
markup
[
'start'
]
end
=
markup
[
'end'
]
split_points
.
append
(
start
)
split_points
.
append
(
end
)
elements
.
setdefault
(
start
,
[]).
append
(
Start
(
markup
))
elements
.
setdefault
(
end
,
[]).
append
(
End
(
markup
))
if
isinstance
(
markup
,
List
):
lis
=
markup
[
'lis'
]
for
i
,
li
in
enumerate
(
lis
):
start
=
li
[
'start'
]
split_points
.
append
(
start
)
li_end
=
lis
[
i
+
1
][
'start'
]
if
i
<
len
(
lis
)
-
1
else
end
elements
.
setdefault
(
li_end
,
[]).
append
(
End
(
li
))
elements
.
setdefault
(
start
,
[]).
append
(
Start
(
li
))
split_points
=
set
(
split_points
)
new_body
=
[[]]
for
i
,
letter
in
enumerate
(
body
+
'
\x00
'
):
if
i
in
split_points
:
body_elements
=
[]
for
elem
in
elements
[
i
]:
body_elements
.
append
(
elem
)
new_body
.
append
(
body_elements
)
new_body
.
append
([])
new_body
[
-
1
].
append
(
letter
)
new_body
[
-
1
]
=
new_body
[
-
1
][:
-
1
]
final
=
[]
for
chunk
in
new_body
:
if
not
chunk
:
continue
final
.
append
(
''
.
join
(
chunk
)
if
isinstance
(
chunk
[
0
],
str
)
else
chunk
)
return
final
def
to_plain_text
(
self
,
body
,
markup_elem
):
chunks
=
self
.
_split_first_level
(
body
,
markup_elem
)
final
=
[]
for
chunk
in
chunks
:
if
isinstance
(
chunk
,
str
):
final
.
append
(
chunk
)
return
''
.
join
(
final
)
def
to_xhtml_im
(
self
,
body
,
markup_elem
):
chunks
=
self
.
_split_first_level
(
body
,
markup_elem
)
final
=
[]
stack
=
[]
for
chunk
in
chunks
:
if
isinstance
(
chunk
,
str
):
chunk
=
(
chunk
.
replace
(
"&"
,
'&'
)
.
replace
(
'<'
,
'<'
)
.
replace
(
'>'
,
'>'
)
.
replace
(
'"'
,
'"'
)
.
replace
(
"'"
,
'''
)
.
replace
(
'
\n
'
,
'<br/>'
))
final
.
append
(
chunk
)
continue
num_end
=
0
for
elem
in
chunk
:
if
isinstance
(
elem
,
End
):
num_end
+=
1
for
i
in
range
(
num_end
):
stack_top
=
stack
.
pop
()
for
elem
in
chunk
:
if
not
isinstance
(
elem
,
End
):
continue
elem
=
elem
.
elem
if
elem
is
stack_top
:
if
isinstance
(
elem
,
Span
):
final
.
append
(
'</span>'
)
elif
isinstance
(
elem
,
BlockCode
):
final
.
append
(
'</code></pre>'
)
elif
isinstance
(
elem
,
List
):
final
.
append
(
'</ul>'
)
elif
isinstance
(
elem
,
Li
):
final
.
append
(
'</li>'
)
elif
isinstance
(
elem
,
BlockQuote
):
final
.
append
(
'</blockquote>'
)
break
else
:
assert
False
for
elem
in
chunk
:
if
not
isinstance
(
elem
,
Start
):
continue
elem
=
elem
.
elem
stack
.
append
(
elem
)
if
isinstance
(
elem
,
Span
):
style
=
[]
for
type_
in
elem
[
'types'
]:
if
type_
==
'emphasis'
:
style
.
append
(
'font-style: italic;'
)
if
type_
==
'code'
:
style
.
append
(
'font-family: monospace;'
)
if
type_
==
'deleted'
:
style
.
append
(
'text-decoration: line-through;'
)
final
.
append
(
"<span style='%s'>"
%
' '
.
join
(
style
))
elif
isinstance
(
elem
,
BlockCode
):
final
.
append
(
'<pre><code>'
)
elif
isinstance
(
elem
,
List
):
final
.
append
(
'<ul>'
)
elif
isinstance
(
elem
,
Li
):
final
.
append
(
'<li>'
)
elif
isinstance
(
elem
,
BlockQuote
):
final
.
append
(
'<blockquote>'
)
p
=
"<p xmlns='http://www.w3.org/1999/xhtml'>%s</p>"
%
''
.
join
(
final
)
p2
=
ET
.
fromstring
(
p
)
print
(
'coucou'
,
p
,
tostring
(
p2
))
xhtml_im
=
XHTML_IM
()
xhtml_im
[
'body'
]
=
p2
return
xhtml_im
slixmpp/plugins/xep_0394/stanza.py
0 → 100644
View file @
6a43559f
"""
Slixmpp: The Slick XMPP Library
Copyright (C) 2017 Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
This file is part of Slixmpp.
See the file LICENSE for copying permission.
"""
from
slixmpp.xmlstream
import
ElementBase
,
register_stanza_plugin
,
ET
class
Markup
(
ElementBase
):
namespace
=
'urn:xmpp:markup:0'
name
=
'markup'
plugin_attrib
=
'markup'
class
_FirstLevel
(
ElementBase
):
namespace
=
'urn:xmpp:markup:0'
interfaces
=
{
'start'
,
'end'
}
def
get_start
(
self
):
return
int
(
self
.
_get_attr
(
'start'
))
def
set_start
(
self
,
value
):
self
.
_set_attr
(
'start'
,
'%d'
%
value
)
def
get_end
(
self
):
return
int
(
self
.
_get_attr
(
'end'
))
def
set_end
(
self
,
value
):
self
.
_set_attr
(
'end'
,
'%d'
%
value
)
class
Span
(
_FirstLevel
):
name
=
'span'
plugin_attrib
=
'span'
plugin_multi_attrib
=
'spans'
interfaces
=
{
'start'
,
'end'
,
'types'
}
def
get_types
(
self
):
types
=
[]
if
self
.
xml
.
find
(
'{urn:xmpp:markup:0}emphasis'
)
is
not
None
:
types
.
append
(
'emphasis'
)
if
self
.
xml
.
find
(
'{urn:xmpp:markup:0}code'
)
is
not
None
:
types
.
append
(
'code'
)
if
self
.
xml
.
find
(
'{urn:xmpp:markup:0}deleted'
)
is
not
None
:
types
.
append
(
'deleted'
)
return
types
def
set_types
(
self
,
value
):
del
self
[
'types'
]
for
type_
in
value
:
if
type_
==
'emphasis'
:
self
.
xml
.
append
(
ET
.
Element
(
'{urn:xmpp:markup:0}emphasis'
))
elif
type_
==
'code'
:
self
.
xml
.
append
(
ET
.
Element
(
'{urn:xmpp:markup:0}code'
))
elif
type_
==
'deleted'
:
self
.
xml
.
append
(
ET
.
Element
(
'{urn:xmpp:markup:0}deleted'
))
def
det_types
(
self
):
for
child
in
self
.
xml
:
self
.
xml
.
remove
(
child
)
class
_SpanType
(
ElementBase
):
namespace
=
'urn:xmpp:markup:0'
class
EmphasisType
(
_SpanType
):
name
=
'emphasis'
plugin_attrib
=
'emphasis'
class
CodeType
(
_SpanType
):
name
=
'code'
plugin_attrib
=
'code'
class
DeletedType
(
_SpanType
):
name
=
'deleted'
plugin_attrib
=
'deleted'
class
BlockCode
(
_FirstLevel
):
name
=
'bcode'
plugin_attrib
=
'bcode'
plugin_multi_attrib
=
'bcodes'
class
List
(
_FirstLevel
):
name
=
'list'
plugin_attrib
=
'list'
plugin_multi_attrib
=
'lists'
interfaces
=
{
'start'
,
'end'
,
'li'
}
class
Li
(
ElementBase
):
namespace
=
'urn:xmpp:markup:0'
name
=
'li'
plugin_attrib
=
'li'
plugin_multi_attrib
=
'lis'
interfaces
=
{
'start'
}
def
get_start
(
self
):
return
int
(
self
.
_get_attr
(
'start'
))
def
set_start
(
self
,
value
):
self
.
_set_attr
(
'start'
,
'%d'
%
value
)
class
BlockQuote
(
_FirstLevel
):
name
=
'bquote'
plugin_attrib
=
'bquote'
plugin_multi_attrib
=
'bquotes'
register_stanza_plugin
(
Markup
,
Span
,
iterable
=
True
)
register_stanza_plugin
(
Markup
,
BlockCode
,
iterable
=
True
)
register_stanza_plugin
(
Markup
,
List
,
iterable
=
True
)
register_stanza_plugin
(
Markup
,
BlockQuote
,
iterable
=
True
)
register_stanza_plugin
(
Span
,
EmphasisType
)
register_stanza_plugin
(
Span
,
CodeType
)
register_stanza_plugin
(
Span
,
DeletedType
)
register_stanza_plugin
(
List
,
Li
,
iterable
=
True
)
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment