mirror of
https://codeberg.org/Mercury-IM/Smack
synced 2024-11-25 15:52:06 +01:00
Merge branch '4.2'
This commit is contained in:
commit
026f3a2f8c
34 changed files with 2250 additions and 3 deletions
|
@ -93,11 +93,14 @@ Experimental Smack Extensions and currently supported XEPs of smack-experimental
|
||||||
| [Internet of Things - Discovery](iot.md) | [XEP-0347](http://xmpp.org/extensions/xep-0347.html) | Describes how Things can be installed and discovered by their owners. |
|
| [Internet of Things - Discovery](iot.md) | [XEP-0347](http://xmpp.org/extensions/xep-0347.html) | Describes how Things can be installed and discovered by their owners. |
|
||||||
| Client State Indication | [XEP-0352](http://xmpp.org/extensions/xep-0352.html) | A way for the client to indicate its active/inactive state. |
|
| Client State Indication | [XEP-0352](http://xmpp.org/extensions/xep-0352.html) | A way for the client to indicate its active/inactive state. |
|
||||||
| [Push Notifications](pushnotifications.md) | [XEP-0357](http://xmpp.org/extensions/xep-0357.html) | Defines a way to manage push notifications from an XMPP Server. |
|
| [Push Notifications](pushnotifications.md) | [XEP-0357](http://xmpp.org/extensions/xep-0357.html) | Defines a way to manage push notifications from an XMPP Server. |
|
||||||
|
| Stable and Unique Stanza IDs | [XEP-0359](http://xmpp.org/extensions/xep-0359.html) | This specification describes unique and stable IDs for messages. |
|
||||||
| HTTP File Upload | [XEP-0363](http://xmpp.org/extensions/xep-0363.html) | Protocol to request permissions to upload a file to an HTTP server and get a shareable URL. |
|
| HTTP File Upload | [XEP-0363](http://xmpp.org/extensions/xep-0363.html) | Protocol to request permissions to upload a file to an HTTP server and get a shareable URL. |
|
||||||
|
| [Spoiler Messages](spoiler.md) | [XEP-0382](http://xmpp.org/extensions/xep-0382.html) | Indicate that the body of a message should be treated as a spoiler |
|
||||||
| [Multi-User Chat Light](muclight.md) | [XEP-xxxx](http://mongooseim.readthedocs.io/en/latest/open-extensions/xeps/xep-muc-light.html) | Multi-User Chats for mobile XMPP applications and specific enviroment. |
|
| [Multi-User Chat Light](muclight.md) | [XEP-xxxx](http://mongooseim.readthedocs.io/en/latest/open-extensions/xeps/xep-muc-light.html) | Multi-User Chats for mobile XMPP applications and specific enviroment. |
|
||||||
| [OMEMO Multi End Message and Object Encryption](omemo.md) | [XEP-XXXX](https://conversations.im/omemo/xep-omemo.html) | Encrypt messages using OMEMO encryption (currently only with smack-omemo-signal -> GPLv3). |
|
| [OMEMO Multi End Message and Object Encryption](omemo.md) | [XEP-XXXX](https://conversations.im/omemo/xep-omemo.html) | Encrypt messages using OMEMO encryption (currently only with smack-omemo-signal -> GPLv3). |
|
||||||
| [Consistent Color Generation](consistent_colors.md) | [XEP-0392](http://xmpp.org/extensions/xep-0392.html) | Generate consistent colors for identifiers like usernames to provide a consistent user experience. |
|
| [Consistent Color Generation](consistent_colors.md) | [XEP-0392](http://xmpp.org/extensions/xep-0392.html) | Generate consistent colors for identifiers like usernames to provide a consistent user experience. |
|
||||||
| Google GCM JSON payload | n/a | Semantically the same as XEP-0335: JSON Containers |
|
| Google GCM JSON payload | n/a | Semantically the same as XEP-0335: JSON Containers |
|
||||||
|
| [Message Markup](messagemarkup.md) | [XEP-0394](http://xmpp.org/extensions/xep-0394.html)| Style message bodies while keeping body and markup information separated. |
|
||||||
|
|
||||||
|
|
||||||
Legacy Smack Extensions and currently supported XEPs of smack-legacy
|
Legacy Smack Extensions and currently supported XEPs of smack-legacy
|
||||||
|
|
68
documentation/extensions/messagemarkup.md
Normal file
68
documentation/extensions/messagemarkup.md
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
Message Markup
|
||||||
|
==============
|
||||||
|
|
||||||
|
[Back](index.md)
|
||||||
|
|
||||||
|
[Message Markup (XEP-0394)](https://xmpp.org/extensions/xep-0394.html) can be used as a an alternative to XHTML-IM to style messages, while keeping the body and markup information strictly separated.
|
||||||
|
This implementation can *not* be used to render message bodies, but will offer a simple to use interface for creating ExtensionElements which encode the markup information.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
The most important class is the `MarkupElement` class, which contains a Builder.
|
||||||
|
|
||||||
|
To start creating a Message Markup Extension, call `MarkupElement.getBuilder()`.
|
||||||
|
(Almost) all method calls documented below will be made on the builder.
|
||||||
|
|
||||||
|
Whenever a method call receives a `start` and `end` index, `start` represents the first character, which is affected by the styling, while `end` is the character *after* the last affected character.
|
||||||
|
|
||||||
|
### Inline styling
|
||||||
|
|
||||||
|
Currently there are 3 styles available:
|
||||||
|
* *emphasis*, which should be rendered by a client as *italic*, or **bold**
|
||||||
|
* *code*, which should be rendered in `monospace`
|
||||||
|
* *deleted*, which should be rendered as ~~strikethrough~~.
|
||||||
|
|
||||||
|
Those styles are available by calling `builder.setEmphasis(int start, int end)`,
|
||||||
|
`builder.setDeleted(int start, int end)` and `builder.setCode(int start, int end)`.
|
||||||
|
|
||||||
|
If you want to apply multiple inline styles to a section, you can do the following:
|
||||||
|
```
|
||||||
|
Set<SpanElement.SpanStyle> spanStyles = new HashSet<>();
|
||||||
|
styles.add(SpanElement.SpanStyle.emphasis);
|
||||||
|
styles.add(SpanElement.SpanStyle.deleted);
|
||||||
|
builder.addSpan(start, end, spanStyles);
|
||||||
|
```
|
||||||
|
|
||||||
|
Note, that spans cannot overlap one another.
|
||||||
|
|
||||||
|
### Block Level Styling
|
||||||
|
|
||||||
|
Available block level styles are:
|
||||||
|
* Code blocks, which should be rendered as
|
||||||
|
```
|
||||||
|
blocks
|
||||||
|
of
|
||||||
|
code
|
||||||
|
```
|
||||||
|
|
||||||
|
* Itemized lists, which should render as
|
||||||
|
* Lists
|
||||||
|
* with possibly multiple
|
||||||
|
* entries
|
||||||
|
|
||||||
|
* Block Quotes, which should be rendered by the client
|
||||||
|
> as quotes, which
|
||||||
|
>> also can be nested
|
||||||
|
|
||||||
|
To mark a section as code block, call `builder.setCodeBlock(start, end)`.
|
||||||
|
|
||||||
|
To create a list, call `MarkupElement.Builder.ListBuilder lbuilder = builder.beginList()`, which will return a list builder.
|
||||||
|
On this you can call `lbuilder.addEntry(start, end)` to add an entry.
|
||||||
|
|
||||||
|
Note: If you add an entry, the start value MUST be equal to the end value of the previous added entry!
|
||||||
|
|
||||||
|
To end the list, call `lbuilder.endList()`, which will return the MessageMarkup builder.
|
||||||
|
|
||||||
|
To create a block quote, call `builder.setBlockQuote(start, end)`.
|
||||||
|
|
||||||
|
Note that block level elements MUST NOT overlap each other boundaries, but may be fully contained (nested) within each other.
|
33
documentation/extensions/spoiler.md
Normal file
33
documentation/extensions/spoiler.md
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
Spoiler Messages
|
||||||
|
================
|
||||||
|
|
||||||
|
[Back](index.md)
|
||||||
|
|
||||||
|
Spoiler Messages can be used to indicate that the body of a message is a spoiler and should be displayed as such.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
To get an instance of the SpoilerManager, call
|
||||||
|
```
|
||||||
|
SpoilerManager manager = SpoilerManager.getInstanceFor(connection);
|
||||||
|
```
|
||||||
|
This will automatically add Spoilers to the list of supported features of your client.
|
||||||
|
|
||||||
|
The manager can then be used to add SpoilerElements to messages like follows:
|
||||||
|
```
|
||||||
|
Message message = new Message();
|
||||||
|
|
||||||
|
// spoiler without hint
|
||||||
|
SpoilerElement.addSpoiler(message);
|
||||||
|
|
||||||
|
// spoiler with hint about content
|
||||||
|
SpoilerElement.addSpoiler(message, "End of Love Story");
|
||||||
|
|
||||||
|
// spoiler with localized hint
|
||||||
|
SpoilerElement.addSpoiler(message, "de", "Der Kuchen ist eine Lüge");
|
||||||
|
```
|
||||||
|
|
||||||
|
To get Spoilers from a message call
|
||||||
|
```
|
||||||
|
Map<String, String> spoilers = SpoilerElement.getSpoilers(message);
|
||||||
|
```
|
|
@ -0,0 +1,62 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright © 2018 Paul Schaub
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smackx.message_markup.element;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.util.XmlStringBuilder;
|
||||||
|
|
||||||
|
public class BlockQuoteElement implements MarkupElement.BlockLevelMarkupElement {
|
||||||
|
|
||||||
|
public static final String ELEMENT = "bquote";
|
||||||
|
|
||||||
|
private final int start, end;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new Block Quote element.
|
||||||
|
*
|
||||||
|
* @param start start index
|
||||||
|
* @param end end index
|
||||||
|
*/
|
||||||
|
public BlockQuoteElement(int start, int end) {
|
||||||
|
this.start = start;
|
||||||
|
this.end = end;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getStart() {
|
||||||
|
return start;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getEnd() {
|
||||||
|
return end;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getElementName() {
|
||||||
|
return ELEMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public XmlStringBuilder toXML() {
|
||||||
|
XmlStringBuilder xml = new XmlStringBuilder();
|
||||||
|
xml.halfOpenElement(this);
|
||||||
|
xml.attribute(ATTR_START, getStart());
|
||||||
|
xml.attribute(ATTR_END, getEnd());
|
||||||
|
xml.closeEmptyElement();
|
||||||
|
return xml;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright © 2018 Paul Schaub
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smackx.message_markup.element;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.util.XmlStringBuilder;
|
||||||
|
|
||||||
|
public class CodeBlockElement implements MarkupElement.BlockLevelMarkupElement {
|
||||||
|
|
||||||
|
public static final String ELEMENT = "bcode";
|
||||||
|
|
||||||
|
private final int start, end;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new Code Block element.
|
||||||
|
*
|
||||||
|
* @param start start index
|
||||||
|
* @param end end index
|
||||||
|
*/
|
||||||
|
public CodeBlockElement(int start, int end) {
|
||||||
|
this.start = start;
|
||||||
|
this.end = end;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getStart() {
|
||||||
|
return start;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getEnd() {
|
||||||
|
return end;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getElementName() {
|
||||||
|
return ELEMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public XmlStringBuilder toXML() {
|
||||||
|
XmlStringBuilder xml = new XmlStringBuilder();
|
||||||
|
xml.halfOpenElement(this);
|
||||||
|
xml.attribute(ATTR_START, getStart());
|
||||||
|
xml.attribute(ATTR_END, getEnd());
|
||||||
|
xml.closeEmptyElement();
|
||||||
|
return xml;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,121 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright © 2018 Paul Schaub
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smackx.message_markup.element;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.packet.NamedElement;
|
||||||
|
import org.jivesoftware.smack.util.XmlStringBuilder;
|
||||||
|
|
||||||
|
public class ListElement implements MarkupElement.MarkupChildElement {
|
||||||
|
|
||||||
|
public static final String ELEMENT = "list";
|
||||||
|
public static final String ELEM_LI = "li";
|
||||||
|
|
||||||
|
private final int start, end;
|
||||||
|
private final List<ListEntryElement> entries;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new List element.
|
||||||
|
*
|
||||||
|
* @param start start index of the list
|
||||||
|
* @param end end index of the list
|
||||||
|
* @param entries list entries
|
||||||
|
*/
|
||||||
|
public ListElement(int start, int end, List<ListEntryElement> entries) {
|
||||||
|
this.start = start;
|
||||||
|
this.end = end;
|
||||||
|
this.entries = Collections.unmodifiableList(entries);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getStart() {
|
||||||
|
return start;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getEnd() {
|
||||||
|
return end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a list of all list entries.
|
||||||
|
*
|
||||||
|
* @return entries
|
||||||
|
*/
|
||||||
|
public List<ListEntryElement> getEntries() {
|
||||||
|
return entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getElementName() {
|
||||||
|
return ELEMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CharSequence toXML() {
|
||||||
|
XmlStringBuilder xml = new XmlStringBuilder();
|
||||||
|
xml.halfOpenElement(this);
|
||||||
|
xml.attribute(ATTR_START, getStart());
|
||||||
|
xml.attribute(ATTR_END, getEnd());
|
||||||
|
xml.rightAngleBracket();
|
||||||
|
|
||||||
|
for (ListEntryElement li : getEntries()) {
|
||||||
|
xml.append(li.toXML());
|
||||||
|
}
|
||||||
|
|
||||||
|
xml.closeElement(this);
|
||||||
|
return xml;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ListEntryElement implements NamedElement {
|
||||||
|
|
||||||
|
private final int start;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new ListEntry element.
|
||||||
|
*
|
||||||
|
* @param start start index
|
||||||
|
*/
|
||||||
|
public ListEntryElement(int start) {
|
||||||
|
this.start = start;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the start index of this entry.
|
||||||
|
* @return start index
|
||||||
|
*/
|
||||||
|
public int getStart() {
|
||||||
|
return start;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getElementName() {
|
||||||
|
return ELEM_LI;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public XmlStringBuilder toXML() {
|
||||||
|
XmlStringBuilder xml = new XmlStringBuilder();
|
||||||
|
xml.halfOpenElement(this);
|
||||||
|
xml.attribute(ATTR_START, getStart());
|
||||||
|
xml.closeEmptyElement();
|
||||||
|
return xml;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,312 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright © 2018 Paul Schaub
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smackx.message_markup.element;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.packet.ExtensionElement;
|
||||||
|
import org.jivesoftware.smack.packet.NamedElement;
|
||||||
|
import org.jivesoftware.smack.util.XmlStringBuilder;
|
||||||
|
|
||||||
|
public class MarkupElement implements ExtensionElement {
|
||||||
|
|
||||||
|
public static final String NAMESPACE = "urn:xmpp:markup:0";
|
||||||
|
public static final String ELEMENT = "markup";
|
||||||
|
|
||||||
|
private final List<MarkupChildElement> childElements;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new MarkupElement.
|
||||||
|
*
|
||||||
|
* @param childElements child elements.
|
||||||
|
*/
|
||||||
|
public MarkupElement(List<MarkupChildElement> childElements) {
|
||||||
|
this.childElements = Collections.unmodifiableList(childElements);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a new Builder for Message Markup elements.
|
||||||
|
* @return builder.
|
||||||
|
*/
|
||||||
|
public static Builder getBuilder() {
|
||||||
|
return new Builder();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a list of all child elements.
|
||||||
|
* @return children
|
||||||
|
*/
|
||||||
|
public List<MarkupChildElement> getChildElements() {
|
||||||
|
return childElements;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getNamespace() {
|
||||||
|
return NAMESPACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getElementName() {
|
||||||
|
return ELEMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public XmlStringBuilder toXML() {
|
||||||
|
XmlStringBuilder xml = new XmlStringBuilder(this).rightAngleBracket();
|
||||||
|
|
||||||
|
for (MarkupChildElement child : getChildElements()) {
|
||||||
|
xml.append(child.toXML());
|
||||||
|
}
|
||||||
|
|
||||||
|
xml.closeElement(this);
|
||||||
|
return xml;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static final class Builder {
|
||||||
|
|
||||||
|
private final List<SpanElement> spans = new ArrayList<>();
|
||||||
|
private final List<BlockQuoteElement> quotes = new ArrayList<>();
|
||||||
|
private final List<CodeBlockElement> codes = new ArrayList<>();
|
||||||
|
private final List<ListElement> lists = new ArrayList<>();
|
||||||
|
|
||||||
|
private Builder() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mark a section of a message as deleted.
|
||||||
|
*
|
||||||
|
* @param start start index
|
||||||
|
* @param end end index
|
||||||
|
* @return builder
|
||||||
|
*/
|
||||||
|
public Builder setDeleted(int start, int end) {
|
||||||
|
return addSpan(start, end, Collections.singleton(SpanElement.SpanStyle.deleted));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mark a section of a message as emphasized.
|
||||||
|
*
|
||||||
|
* @param start start index
|
||||||
|
* @param end end index
|
||||||
|
* @return builder
|
||||||
|
*/
|
||||||
|
public Builder setEmphasis(int start, int end) {
|
||||||
|
return addSpan(start, end, Collections.singleton(SpanElement.SpanStyle.emphasis));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mark a section of a message as inline code.
|
||||||
|
*
|
||||||
|
* @param start start index
|
||||||
|
* @param end end index
|
||||||
|
* @return builder
|
||||||
|
*/
|
||||||
|
public Builder setCode(int start, int end) {
|
||||||
|
return addSpan(start, end, Collections.singleton(SpanElement.SpanStyle.code));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a span element.
|
||||||
|
*
|
||||||
|
* @param start start index
|
||||||
|
* @param end end index
|
||||||
|
* @param styles list of text styles for that span
|
||||||
|
* @return builder
|
||||||
|
*/
|
||||||
|
public Builder addSpan(int start, int end, Set<SpanElement.SpanStyle> styles) {
|
||||||
|
verifyStartEnd(start, end);
|
||||||
|
|
||||||
|
for (SpanElement other : spans) {
|
||||||
|
if ((start >= other.getStart() && start <= other.getEnd()) ||
|
||||||
|
(end >= other.getStart() && end <= other.getEnd())) {
|
||||||
|
throw new IllegalArgumentException("Spans MUST NOT overlap each other.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
spans.add(new SpanElement(start, end, styles));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mark a section of a message as block quote.
|
||||||
|
*
|
||||||
|
* @param start start index
|
||||||
|
* @param end end index
|
||||||
|
* @return builder
|
||||||
|
*/
|
||||||
|
public Builder setBlockQuote(int start, int end) {
|
||||||
|
verifyStartEnd(start, end);
|
||||||
|
|
||||||
|
for (BlockQuoteElement other : quotes) {
|
||||||
|
// 1 if out, 0 if on, -1 if in
|
||||||
|
Integer s = start;
|
||||||
|
Integer e = end;
|
||||||
|
int startPos = s.compareTo(other.getStart()) * s.compareTo(other.getEnd());
|
||||||
|
int endPos = e.compareTo(other.getStart()) * e.compareTo(other.getEnd());
|
||||||
|
int allowed = startPos * endPos;
|
||||||
|
|
||||||
|
if (allowed < 1) {
|
||||||
|
throw new IllegalArgumentException("BlockQuotes MUST NOT overlap each others boundaries");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
quotes.add(new BlockQuoteElement(start, end));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mark a section of a message as a code block.
|
||||||
|
*
|
||||||
|
* @param start start index
|
||||||
|
* @param end end index
|
||||||
|
* @return builder
|
||||||
|
*/
|
||||||
|
public Builder setCodeBlock(int start, int end) {
|
||||||
|
verifyStartEnd(start, end);
|
||||||
|
|
||||||
|
codes.add(new CodeBlockElement(start, end));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Begin a list.
|
||||||
|
*
|
||||||
|
* @return list builder
|
||||||
|
*/
|
||||||
|
public Builder.ListBuilder beginList() {
|
||||||
|
return new Builder.ListBuilder(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final class ListBuilder {
|
||||||
|
private final Builder markup;
|
||||||
|
private final ArrayList<ListElement.ListEntryElement> entries = new ArrayList<>();
|
||||||
|
private int end = -1;
|
||||||
|
|
||||||
|
private ListBuilder(Builder markup) {
|
||||||
|
this.markup = markup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add an entry to the list.
|
||||||
|
* The start index of an entry must correspond to the end index of the previous entry
|
||||||
|
* (if a previous entry exists.)
|
||||||
|
*
|
||||||
|
* @param start start index
|
||||||
|
* @param end end index
|
||||||
|
* @return list builder
|
||||||
|
*/
|
||||||
|
public Builder.ListBuilder addEntry(int start, int end) {
|
||||||
|
verifyStartEnd(start, end);
|
||||||
|
|
||||||
|
ListElement.ListEntryElement last = entries.size() == 0 ? null : entries.get(entries.size() - 1);
|
||||||
|
// Entries themselves do not store end values, that's why we store the last entries end value in this.end
|
||||||
|
if (last != null && start != this.end) {
|
||||||
|
throw new IllegalArgumentException("Next entries start must be equal to last entries end (" + this.end + ").");
|
||||||
|
}
|
||||||
|
entries.add(new ListElement.ListEntryElement(start));
|
||||||
|
this.end = end;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* End the list.
|
||||||
|
*
|
||||||
|
* @return builder
|
||||||
|
*/
|
||||||
|
public Builder endList() {
|
||||||
|
if (entries.size() > 0) {
|
||||||
|
ListElement.ListEntryElement first = entries.get(0);
|
||||||
|
ListElement list = new ListElement(first.getStart(), end, entries);
|
||||||
|
markup.lists.add(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
return markup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build a Message Markup element.
|
||||||
|
*
|
||||||
|
* @return extension element
|
||||||
|
*/
|
||||||
|
public MarkupElement build() {
|
||||||
|
List<MarkupElement.MarkupChildElement> children = new ArrayList<>();
|
||||||
|
children.addAll(spans);
|
||||||
|
children.addAll(quotes);
|
||||||
|
children.addAll(codes);
|
||||||
|
children.addAll(lists);
|
||||||
|
return new MarkupElement(children);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void verifyStartEnd(int start, int end) {
|
||||||
|
if (start >= end || start < 0) {
|
||||||
|
throw new IllegalArgumentException("Start value (" + start + ") MUST be greater equal than 0 " +
|
||||||
|
"and MUST be smaller than end value (" + end + ").");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for child elements.
|
||||||
|
*/
|
||||||
|
public interface MarkupChildElement extends NamedElement {
|
||||||
|
|
||||||
|
String ATTR_START = "start";
|
||||||
|
String ATTR_END = "end";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the start index of this element.
|
||||||
|
*
|
||||||
|
* @return start index
|
||||||
|
*/
|
||||||
|
int getStart();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the end index of this element.
|
||||||
|
*
|
||||||
|
* @return end index
|
||||||
|
*/
|
||||||
|
int getEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for block level child elements.
|
||||||
|
*/
|
||||||
|
public interface BlockLevelMarkupElement extends MarkupChildElement {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,93 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright © 2018 Paul Schaub
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smackx.message_markup.element;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.util.XmlStringBuilder;
|
||||||
|
|
||||||
|
public class SpanElement implements MarkupElement.MarkupChildElement {
|
||||||
|
|
||||||
|
public static final String ELEMENT = "span";
|
||||||
|
|
||||||
|
private final int start, end;
|
||||||
|
private final Set<SpanStyle> styles;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new Span element.
|
||||||
|
*
|
||||||
|
* @param start start index
|
||||||
|
* @param end end index
|
||||||
|
* @param styles list of styles that apply to this span
|
||||||
|
*/
|
||||||
|
public SpanElement(int start, int end, Set<SpanStyle> styles) {
|
||||||
|
this.start = start;
|
||||||
|
this.end = end;
|
||||||
|
this.styles = Collections.unmodifiableSet(styles);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getStart() {
|
||||||
|
return start;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getEnd() {
|
||||||
|
return end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return all styles of this span.
|
||||||
|
*
|
||||||
|
* @return styles
|
||||||
|
*/
|
||||||
|
public Set<SpanStyle> getStyles() {
|
||||||
|
return styles;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final String emphasis = "emphasis";
|
||||||
|
public static final String code = "code";
|
||||||
|
public static final String deleted = "deleted";
|
||||||
|
|
||||||
|
public enum SpanStyle {
|
||||||
|
emphasis,
|
||||||
|
code,
|
||||||
|
deleted
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getElementName() {
|
||||||
|
return ELEMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public XmlStringBuilder toXML() {
|
||||||
|
XmlStringBuilder xml = new XmlStringBuilder();
|
||||||
|
xml.halfOpenElement(this);
|
||||||
|
xml.attribute(ATTR_START, getStart());
|
||||||
|
xml.attribute(ATTR_END, getEnd());
|
||||||
|
xml.rightAngleBracket();
|
||||||
|
|
||||||
|
for (SpanStyle style : getStyles()) {
|
||||||
|
xml.halfOpenElement(style.toString()).closeEmptyElement();
|
||||||
|
}
|
||||||
|
|
||||||
|
xml.closeElement(this);
|
||||||
|
return xml;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright 2018 Paul Schaub
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* XEP-0394: Message Markup.
|
||||||
|
*
|
||||||
|
* @see <a href="http://xmpp.org/extensions/xep-0394.html">XEP-0394: Message
|
||||||
|
* Markup</a>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smackx.message_markup.element;
|
|
@ -0,0 +1,25 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright 2018 Paul Schaub
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* XEP-0394: Message Markup.
|
||||||
|
*
|
||||||
|
* @see <a href="http://xmpp.org/extensions/xep-0394.html">XEP-0394: Message
|
||||||
|
* Markup</a>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smackx.message_markup;
|
|
@ -0,0 +1,139 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright © 2018 Paul Schaub
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smackx.message_markup.provider;
|
||||||
|
|
||||||
|
import static org.xmlpull.v1.XmlPullParser.END_TAG;
|
||||||
|
import static org.xmlpull.v1.XmlPullParser.START_TAG;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.SmackException;
|
||||||
|
import org.jivesoftware.smack.provider.ExtensionElementProvider;
|
||||||
|
import org.jivesoftware.smack.util.ParserUtils;
|
||||||
|
import org.jivesoftware.smackx.message_markup.element.BlockQuoteElement;
|
||||||
|
import org.jivesoftware.smackx.message_markup.element.CodeBlockElement;
|
||||||
|
import org.jivesoftware.smackx.message_markup.element.ListElement;
|
||||||
|
import org.jivesoftware.smackx.message_markup.element.MarkupElement;
|
||||||
|
import org.jivesoftware.smackx.message_markup.element.SpanElement;
|
||||||
|
|
||||||
|
import org.xmlpull.v1.XmlPullParser;
|
||||||
|
|
||||||
|
public class MarkupElementProvider extends ExtensionElementProvider<MarkupElement> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MarkupElement parse(XmlPullParser parser, int initialDepth) throws Exception {
|
||||||
|
|
||||||
|
MarkupElement.Builder markup = MarkupElement.getBuilder();
|
||||||
|
|
||||||
|
int spanStart = -1, spanEnd = -1;
|
||||||
|
Set<SpanElement.SpanStyle> spanStyles = new HashSet<>();
|
||||||
|
|
||||||
|
int listStart = -1, listEnd = -1;
|
||||||
|
List<ListElement.ListEntryElement> lis = new ArrayList<>();
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
int tag = parser.next();
|
||||||
|
String name = parser.getName();
|
||||||
|
int start, end;
|
||||||
|
switch (tag) {
|
||||||
|
case START_TAG:
|
||||||
|
switch (name) {
|
||||||
|
case BlockQuoteElement.ELEMENT:
|
||||||
|
start = ParserUtils.getIntegerAttributeOrThrow(parser, BlockQuoteElement.ATTR_START,
|
||||||
|
"Message Markup BlockQuoteElement MUST contain a 'start' attribute.");
|
||||||
|
end = ParserUtils.getIntegerAttributeOrThrow(parser, BlockQuoteElement.ATTR_END,
|
||||||
|
"Message Markup BlockQuoteElement MUST contain a 'end' attribute.");
|
||||||
|
markup.setBlockQuote(start, end);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CodeBlockElement.ELEMENT:
|
||||||
|
start = ParserUtils.getIntegerAttributeOrThrow(parser, CodeBlockElement.ATTR_START,
|
||||||
|
"Message Markup CodeBlockElement MUST contain a 'start' attribute.");
|
||||||
|
end = ParserUtils.getIntegerAttributeOrThrow(parser, CodeBlockElement.ATTR_END,
|
||||||
|
"Message Markup CodeBlockElement MUST contain a 'end' attribute.");
|
||||||
|
markup.setCodeBlock(start, end);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SpanElement.ELEMENT:
|
||||||
|
spanStyles = new HashSet<>();
|
||||||
|
spanStart = ParserUtils.getIntegerAttributeOrThrow(parser, SpanElement.ATTR_START,
|
||||||
|
"Message Markup SpanElement MUST contain a 'start' attribute.");
|
||||||
|
spanEnd = ParserUtils.getIntegerAttributeOrThrow(parser, SpanElement.ATTR_END,
|
||||||
|
"Message Markup SpanElement MUST contain a 'end' attribute.");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SpanElement.code:
|
||||||
|
spanStyles.add(SpanElement.SpanStyle.code);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SpanElement.emphasis:
|
||||||
|
spanStyles.add(SpanElement.SpanStyle.emphasis);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SpanElement.deleted:
|
||||||
|
spanStyles.add(SpanElement.SpanStyle.deleted);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ListElement.ELEMENT:
|
||||||
|
lis = new ArrayList<>();
|
||||||
|
listStart = ParserUtils.getIntegerAttributeOrThrow(parser, ListElement.ATTR_START,
|
||||||
|
"Message Markup ListElement MUST contain a 'start' attribute.");
|
||||||
|
listEnd = ParserUtils.getIntegerAttributeOrThrow(parser, ListElement.ATTR_END,
|
||||||
|
"Message Markup ListElement MUST contain a 'end' attribute.");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ListElement.ELEM_LI:
|
||||||
|
start = ParserUtils.getIntegerAttributeOrThrow(parser, ListElement.ATTR_START,
|
||||||
|
"Message Markup ListElement 'li' MUST contain a 'start' attribute.");
|
||||||
|
lis.add(new ListElement.ListEntryElement(start));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case END_TAG:
|
||||||
|
switch (name) {
|
||||||
|
case SpanElement.ELEMENT:
|
||||||
|
markup.addSpan(spanStart, spanEnd, spanStyles);
|
||||||
|
spanStart = -1; spanEnd = -1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ListElement.ELEMENT:
|
||||||
|
MarkupElement.Builder.ListBuilder listBuilder = markup.beginList();
|
||||||
|
if (lis.size() > 0 && lis.get(0).getStart() != listStart) {
|
||||||
|
throw new SmackException("Error while parsing incoming MessageMarkup ListElement: " +
|
||||||
|
"'start' attribute of first 'li' element must equal 'start' attribute of list.");
|
||||||
|
}
|
||||||
|
for (int i = 0; i < lis.size(); i++) {
|
||||||
|
int elemStart = lis.get(i).getStart();
|
||||||
|
int elemEnd = i < lis.size() - 1 ? lis.get(i + 1).getStart() : listEnd;
|
||||||
|
listBuilder.addEntry(elemStart, elemEnd);
|
||||||
|
}
|
||||||
|
listBuilder.endList();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MarkupElement.ELEMENT:
|
||||||
|
return markup.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright 2018 Paul Schaub
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* XEP-0394: Message Markup.
|
||||||
|
*
|
||||||
|
* @see <a href="http://xmpp.org/extensions/xep-0394.html">XEP-0394: Message
|
||||||
|
* Markup</a>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smackx.message_markup.provider;
|
|
@ -0,0 +1,118 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright 2018 Paul Schaub
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smackx.sid;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.WeakHashMap;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.ConnectionCreationListener;
|
||||||
|
import org.jivesoftware.smack.Manager;
|
||||||
|
import org.jivesoftware.smack.StanzaListener;
|
||||||
|
import org.jivesoftware.smack.XMPPConnection;
|
||||||
|
import org.jivesoftware.smack.XMPPConnectionRegistry;
|
||||||
|
import org.jivesoftware.smack.filter.AndFilter;
|
||||||
|
import org.jivesoftware.smack.filter.MessageTypeFilter;
|
||||||
|
import org.jivesoftware.smack.filter.NotFilter;
|
||||||
|
import org.jivesoftware.smack.filter.StanzaExtensionFilter;
|
||||||
|
import org.jivesoftware.smack.filter.StanzaFilter;
|
||||||
|
import org.jivesoftware.smack.filter.ToTypeFilter;
|
||||||
|
import org.jivesoftware.smack.packet.Message;
|
||||||
|
import org.jivesoftware.smack.packet.Stanza;
|
||||||
|
import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
|
||||||
|
import org.jivesoftware.smackx.sid.element.OriginIdElement;
|
||||||
|
|
||||||
|
public final class StableUniqueStanzaIdManager extends Manager {
|
||||||
|
|
||||||
|
public static final String NAMESPACE = "urn:xmpp:sid:0";
|
||||||
|
|
||||||
|
private static final Map<XMPPConnection, StableUniqueStanzaIdManager> INSTANCES = new WeakHashMap<>();
|
||||||
|
|
||||||
|
// Filter for outgoing stanzas.
|
||||||
|
private static final StanzaFilter OUTGOING_FILTER = new AndFilter(
|
||||||
|
MessageTypeFilter.NORMAL_OR_CHAT_OR_HEADLINE,
|
||||||
|
ToTypeFilter.ENTITY_FULL_OR_BARE_JID);
|
||||||
|
|
||||||
|
private static final StanzaFilter ORIGIN_ID_FILTER = new StanzaExtensionFilter(OriginIdElement.ELEMENT, NAMESPACE);
|
||||||
|
|
||||||
|
// Listener for outgoing stanzas that adds origin-ids to outgoing stanzas.
|
||||||
|
private final StanzaListener stanzaListener = new StanzaListener() {
|
||||||
|
@Override
|
||||||
|
public void processStanza(Stanza stanza) {
|
||||||
|
OriginIdElement.addOriginId((Message) stanza);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static {
|
||||||
|
XMPPConnectionRegistry.addConnectionCreationListener(new ConnectionCreationListener() {
|
||||||
|
@Override
|
||||||
|
public void connectionCreated(XMPPConnection connection) {
|
||||||
|
getInstanceFor(connection);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private constructor.
|
||||||
|
* @param connection
|
||||||
|
*/
|
||||||
|
private StableUniqueStanzaIdManager(XMPPConnection connection) {
|
||||||
|
super(connection);
|
||||||
|
enable();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return an instance of the StableUniqueStanzaIdManager for the given connection.
|
||||||
|
*
|
||||||
|
* @param connection xmpp-connection
|
||||||
|
* @return manager instance for the connection
|
||||||
|
*/
|
||||||
|
public static StableUniqueStanzaIdManager getInstanceFor(XMPPConnection connection) {
|
||||||
|
StableUniqueStanzaIdManager manager = INSTANCES.get(connection);
|
||||||
|
if (manager == null) {
|
||||||
|
manager = new StableUniqueStanzaIdManager(connection);
|
||||||
|
INSTANCES.put(connection, manager);
|
||||||
|
}
|
||||||
|
return manager;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start appending origin-id elements to outgoing stanzas and add the feature to disco.
|
||||||
|
*/
|
||||||
|
public synchronized void enable() {
|
||||||
|
ServiceDiscoveryManager.getInstanceFor(connection()).addFeature(NAMESPACE);
|
||||||
|
StanzaFilter filter = new AndFilter(OUTGOING_FILTER, new NotFilter(OUTGOING_FILTER));
|
||||||
|
connection().addPacketInterceptor(stanzaListener, filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stop appending origin-id elements to outgoing stanzas and remove the feature from disco.
|
||||||
|
*/
|
||||||
|
public synchronized void disable() {
|
||||||
|
ServiceDiscoveryManager.getInstanceFor(connection()).removeFeature(NAMESPACE);
|
||||||
|
connection().removePacketInterceptor(stanzaListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true, if we automatically append origin-id elements to outgoing stanzas.
|
||||||
|
*
|
||||||
|
* @return true if functionality is enabled, otherwise false.
|
||||||
|
*/
|
||||||
|
public synchronized boolean isEnabled() {
|
||||||
|
ServiceDiscoveryManager disco = ServiceDiscoveryManager.getInstanceFor(connection());
|
||||||
|
return disco.includesFeature(NAMESPACE);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,84 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright 2018 Paul Schaub
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smackx.sid.element;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.packet.Message;
|
||||||
|
import org.jivesoftware.smack.util.XmlStringBuilder;
|
||||||
|
import org.jivesoftware.smackx.sid.StableUniqueStanzaIdManager;
|
||||||
|
|
||||||
|
public class OriginIdElement extends StableAndUniqueIdElement {
|
||||||
|
|
||||||
|
public static final String ELEMENT = "origin-id";
|
||||||
|
|
||||||
|
public OriginIdElement() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public OriginIdElement(String id) {
|
||||||
|
super(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add an origin-id element to a message and set the stanzas id to the same id as in the origin-id element.
|
||||||
|
*
|
||||||
|
* @param message message.
|
||||||
|
*/
|
||||||
|
public static OriginIdElement addOriginId(Message message) {
|
||||||
|
OriginIdElement originId = new OriginIdElement();
|
||||||
|
message.addExtension(originId);
|
||||||
|
// TODO: Find solution to have both the originIds stanzaId and a nice to look at incremental stanzaID.
|
||||||
|
// message.setStanzaId(originId.getId());
|
||||||
|
return originId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true, if the message contains a origin-id element.
|
||||||
|
*
|
||||||
|
* @param message message
|
||||||
|
* @return true if the message contains a origin-id, false otherwise.
|
||||||
|
*/
|
||||||
|
public static boolean hasOriginId(Message message) {
|
||||||
|
return getOriginId(message) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the origin-id element of a message or null, if absent.
|
||||||
|
*
|
||||||
|
* @param message message
|
||||||
|
* @return origin-id element
|
||||||
|
*/
|
||||||
|
public static OriginIdElement getOriginId(Message message) {
|
||||||
|
return message.getExtension(OriginIdElement.ELEMENT, StableUniqueStanzaIdManager.NAMESPACE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getNamespace() {
|
||||||
|
return StableUniqueStanzaIdManager.NAMESPACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getElementName() {
|
||||||
|
return ELEMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CharSequence toXML() {
|
||||||
|
return new XmlStringBuilder(this)
|
||||||
|
.attribute(ATTR_ID, getId())
|
||||||
|
.closeEmptyElement();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright 2018 Paul Schaub
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smackx.sid.element;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.packet.ExtensionElement;
|
||||||
|
import org.jivesoftware.smack.util.StringUtils;
|
||||||
|
|
||||||
|
public abstract class StableAndUniqueIdElement implements ExtensionElement {
|
||||||
|
|
||||||
|
public static final String ATTR_ID = "id";
|
||||||
|
|
||||||
|
private final String id;
|
||||||
|
|
||||||
|
public StableAndUniqueIdElement() {
|
||||||
|
this.id = UUID.randomUUID().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public StableAndUniqueIdElement(String id) {
|
||||||
|
if (StringUtils.isNullOrEmpty(id)) {
|
||||||
|
throw new IllegalArgumentException("Argument 'id' cannot be null or empty.");
|
||||||
|
}
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,81 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright 2018 Paul Schaub
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smackx.sid.element;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.packet.Message;
|
||||||
|
import org.jivesoftware.smack.util.XmlStringBuilder;
|
||||||
|
import org.jivesoftware.smackx.sid.StableUniqueStanzaIdManager;
|
||||||
|
|
||||||
|
public class StanzaIdElement extends StableAndUniqueIdElement {
|
||||||
|
|
||||||
|
public static final String ELEMENT = "stanza-id";
|
||||||
|
public static final String ATTR_BY = "by";
|
||||||
|
|
||||||
|
private final String by;
|
||||||
|
|
||||||
|
public StanzaIdElement(String by) {
|
||||||
|
super();
|
||||||
|
this.by = by;
|
||||||
|
}
|
||||||
|
|
||||||
|
public StanzaIdElement(String id, String by) {
|
||||||
|
super(id);
|
||||||
|
this.by = by;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true, if a message contains a stanza-id element.
|
||||||
|
*
|
||||||
|
* @param message message
|
||||||
|
* @return true if message contains stanza-id element, otherwise false.
|
||||||
|
*/
|
||||||
|
public static boolean hasStanzaId(Message message) {
|
||||||
|
return getStanzaId(message) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the stanza-id element of a message.
|
||||||
|
*
|
||||||
|
* @param message message
|
||||||
|
* @return stanza-id element of a jid, or null if absent.
|
||||||
|
*/
|
||||||
|
public static StanzaIdElement getStanzaId(Message message) {
|
||||||
|
return message.getExtension(StanzaIdElement.ELEMENT, StableUniqueStanzaIdManager.NAMESPACE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getBy() {
|
||||||
|
return by;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getNamespace() {
|
||||||
|
return StableUniqueStanzaIdManager.NAMESPACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getElementName() {
|
||||||
|
return ELEMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public XmlStringBuilder toXML() {
|
||||||
|
return new XmlStringBuilder(this)
|
||||||
|
.attribute(ATTR_ID, getId())
|
||||||
|
.attribute(ATTR_BY, getBy())
|
||||||
|
.closeEmptyElement();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright 2018 Paul Schaub
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* Smack's API for XEP-0359: Stable and Unique Stanza IDs.
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smackx.sid.element;
|
|
@ -0,0 +1,20 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright 2018 Paul Schaub
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* Smack's API for XEP-0359: Stable and Unique Stanza IDs.
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smackx.sid;
|
|
@ -0,0 +1,32 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright 2018 Paul Schaub
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smackx.sid.provider;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.provider.ExtensionElementProvider;
|
||||||
|
import org.jivesoftware.smackx.sid.element.OriginIdElement;
|
||||||
|
|
||||||
|
import org.xmlpull.v1.XmlPullParser;
|
||||||
|
|
||||||
|
public class OriginIdProvider extends ExtensionElementProvider<OriginIdElement> {
|
||||||
|
|
||||||
|
public static final OriginIdProvider TEST_INSTANCE = new OriginIdProvider();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public OriginIdElement parse(XmlPullParser parser, int initialDepth) throws Exception {
|
||||||
|
return new OriginIdElement(parser.getAttributeValue(null, OriginIdElement.ATTR_ID));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright 2018 Paul Schaub
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smackx.sid.provider;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.provider.ExtensionElementProvider;
|
||||||
|
import org.jivesoftware.smackx.sid.element.StanzaIdElement;
|
||||||
|
|
||||||
|
import org.xmlpull.v1.XmlPullParser;
|
||||||
|
|
||||||
|
public class StanzaIdProvider extends ExtensionElementProvider<StanzaIdElement> {
|
||||||
|
|
||||||
|
public static StanzaIdProvider TEST_INSTANCE = new StanzaIdProvider();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StanzaIdElement parse(XmlPullParser parser, int initialDepth) throws Exception {
|
||||||
|
String id = parser.getAttributeValue(null, StanzaIdElement.ATTR_ID);
|
||||||
|
String by = parser.getAttributeValue(null, StanzaIdElement.ATTR_BY);
|
||||||
|
return new StanzaIdElement(id, by);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright 2018 Paul Schaub
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* Smack's API for XEP-0359: Stable and Unique Stanza IDs.
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smackx.sid.provider;
|
|
@ -0,0 +1,72 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright 2018 Paul Schaub
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smackx.spoiler;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.WeakHashMap;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.Manager;
|
||||||
|
import org.jivesoftware.smack.XMPPConnection;
|
||||||
|
import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
|
||||||
|
|
||||||
|
public final class SpoilerManager extends Manager {
|
||||||
|
|
||||||
|
public static final String NAMESPACE_0 = "urn:xmpp:spoiler:0";
|
||||||
|
|
||||||
|
private static final Map<XMPPConnection, SpoilerManager> INSTANCES = new WeakHashMap<>();
|
||||||
|
|
||||||
|
private final ServiceDiscoveryManager serviceDiscoveryManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new SpoilerManager and add Spoiler to disco features.
|
||||||
|
*
|
||||||
|
* @param connection xmpp connection
|
||||||
|
*/
|
||||||
|
private SpoilerManager(XMPPConnection connection) {
|
||||||
|
super(connection);
|
||||||
|
serviceDiscoveryManager = ServiceDiscoveryManager.getInstanceFor(connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Begin announcing support for Spoiler messages.
|
||||||
|
*/
|
||||||
|
public void startAnnounceSupport() {
|
||||||
|
serviceDiscoveryManager.addFeature(NAMESPACE_0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* End announcing support for Spoiler messages.
|
||||||
|
*/
|
||||||
|
public void stopAnnounceSupport() {
|
||||||
|
serviceDiscoveryManager.removeFeature(NAMESPACE_0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the connections instance of the SpoilerManager.
|
||||||
|
*
|
||||||
|
* @param connection xmpp connection
|
||||||
|
* @return SpoilerManager
|
||||||
|
*/
|
||||||
|
public static SpoilerManager getInstanceFor(XMPPConnection connection) {
|
||||||
|
SpoilerManager manager = INSTANCES.get(connection);
|
||||||
|
if (manager == null) {
|
||||||
|
manager = new SpoilerManager(connection);
|
||||||
|
INSTANCES.put(connection, manager);
|
||||||
|
}
|
||||||
|
return manager;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,166 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright 2018 Paul Schaub
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smackx.spoiler.element;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.packet.ExtensionElement;
|
||||||
|
import org.jivesoftware.smack.packet.Message;
|
||||||
|
import org.jivesoftware.smack.util.StringUtils;
|
||||||
|
import org.jivesoftware.smack.util.XmlStringBuilder;
|
||||||
|
import org.jivesoftware.smackx.spoiler.SpoilerManager;
|
||||||
|
|
||||||
|
public class SpoilerElement implements ExtensionElement {
|
||||||
|
|
||||||
|
public static final String ELEMENT = "spoiler";
|
||||||
|
public static final String NAMESPACE = SpoilerManager.NAMESPACE_0;
|
||||||
|
|
||||||
|
public static final SpoilerElement EMPTY = new SpoilerElement(null, null);
|
||||||
|
|
||||||
|
private final String hint;
|
||||||
|
private final String language;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new SpoilerElement with a hint about a content and a language attribute.
|
||||||
|
*
|
||||||
|
* @param language language of the hint.
|
||||||
|
* @param hint hint about the content.
|
||||||
|
*/
|
||||||
|
public SpoilerElement(String language, String hint) {
|
||||||
|
if (StringUtils.isNotEmpty(language) && StringUtils.isNullOrEmpty(hint)) {
|
||||||
|
throw new IllegalArgumentException("Hint cannot be null or empty if language is not empty.");
|
||||||
|
}
|
||||||
|
this.language = language;
|
||||||
|
this.hint = hint;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the hint text of the spoiler.
|
||||||
|
* May be null.
|
||||||
|
*
|
||||||
|
* @return hint text
|
||||||
|
*/
|
||||||
|
public String getHint() {
|
||||||
|
return hint;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a SpoilerElement to a message.
|
||||||
|
*
|
||||||
|
* @param message message to add the Spoiler to.
|
||||||
|
*/
|
||||||
|
public static void addSpoiler(Message message) {
|
||||||
|
message.addExtension(SpoilerElement.EMPTY);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a SpoilerElement with a hint to a message.
|
||||||
|
*
|
||||||
|
* @param message Message to add the Spoiler to.
|
||||||
|
* @param hint Hint about the Spoilers content.
|
||||||
|
*/
|
||||||
|
public static void addSpoiler(Message message, String hint) {
|
||||||
|
message.addExtension(new SpoilerElement(null, hint));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a SpoilerElement with a hint in a certain language to a message.
|
||||||
|
*
|
||||||
|
* @param message Message to add the Spoiler to.
|
||||||
|
* @param lang language of the Spoiler hint.
|
||||||
|
* @param hint hint.
|
||||||
|
*/
|
||||||
|
public static void addSpoiler(Message message, String lang, String hint) {
|
||||||
|
message.addExtension(new SpoilerElement(lang, hint));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true, if the message has at least one spoiler element.
|
||||||
|
*
|
||||||
|
* @param message message
|
||||||
|
* @return true if message has spoiler extension
|
||||||
|
*/
|
||||||
|
public static boolean containsSpoiler(Message message) {
|
||||||
|
return message.hasExtension(SpoilerElement.ELEMENT, NAMESPACE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a map of all spoilers contained in a message.
|
||||||
|
* The map uses the language of a spoiler as key.
|
||||||
|
* If a spoiler has no language attribute, its key will be an empty String.
|
||||||
|
*
|
||||||
|
* @param message message
|
||||||
|
* @return map of spoilers
|
||||||
|
*/
|
||||||
|
public static Map<String, String> getSpoilers(Message message) {
|
||||||
|
if (!containsSpoiler(message)) {
|
||||||
|
return Collections.emptyMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<ExtensionElement> spoilers = message.getExtensions(SpoilerElement.ELEMENT, NAMESPACE);
|
||||||
|
Map<String, String> map = new HashMap<>();
|
||||||
|
|
||||||
|
for (ExtensionElement e : spoilers) {
|
||||||
|
SpoilerElement s = (SpoilerElement) e;
|
||||||
|
if (s.getLanguage() == null || s.getLanguage().equals("")) {
|
||||||
|
map.put("", s.getHint());
|
||||||
|
} else {
|
||||||
|
map.put(s.getLanguage(), s.getHint());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the language of the hint.
|
||||||
|
* May be null.
|
||||||
|
*
|
||||||
|
* @return language of hint text
|
||||||
|
*/
|
||||||
|
public String getLanguage() {
|
||||||
|
return language;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getNamespace() {
|
||||||
|
return NAMESPACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getElementName() {
|
||||||
|
return ELEMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CharSequence toXML() {
|
||||||
|
XmlStringBuilder xml = new XmlStringBuilder(this);
|
||||||
|
xml.optXmlLangAttribute(getLanguage());
|
||||||
|
if (getHint() == null) {
|
||||||
|
xml.closeEmptyElement();
|
||||||
|
} else {
|
||||||
|
xml.rightAngleBracket();
|
||||||
|
xml.append(getHint());
|
||||||
|
xml.closeElement(this);
|
||||||
|
}
|
||||||
|
return xml;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright 2018 Paul Schaub
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* Smack's API for XEP-0382: Spoiler Messages.
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smackx.spoiler.element;
|
|
@ -0,0 +1,20 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright 2018 Paul Schaub
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* Smack's API for XEP-0382: Spoiler Messages.
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smackx.spoiler;
|
|
@ -0,0 +1,49 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright 2018 Paul Schaub
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smackx.spoiler.provider;
|
||||||
|
|
||||||
|
import static org.xmlpull.v1.XmlPullParser.END_TAG;
|
||||||
|
import static org.xmlpull.v1.XmlPullParser.TEXT;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.provider.ExtensionElementProvider;
|
||||||
|
import org.jivesoftware.smack.util.ParserUtils;
|
||||||
|
import org.jivesoftware.smackx.spoiler.element.SpoilerElement;
|
||||||
|
|
||||||
|
import org.xmlpull.v1.XmlPullParser;
|
||||||
|
|
||||||
|
public class SpoilerProvider extends ExtensionElementProvider<SpoilerElement> {
|
||||||
|
|
||||||
|
public static SpoilerProvider INSTANCE = new SpoilerProvider();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SpoilerElement parse(XmlPullParser parser, int initialDepth) throws Exception {
|
||||||
|
String lang = ParserUtils.getXmlLang(parser);
|
||||||
|
String hint = null;
|
||||||
|
|
||||||
|
outerloop: while (true) {
|
||||||
|
int tag = parser.next();
|
||||||
|
switch (tag) {
|
||||||
|
case TEXT:
|
||||||
|
hint = parser.getText();
|
||||||
|
break;
|
||||||
|
case END_TAG:
|
||||||
|
break outerloop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new SpoilerElement(lang, hint);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright 2018 Paul Schaub
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* Smack's API for XEP-0382: Spoiler Messages.
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smackx.spoiler.provider;
|
|
@ -211,6 +211,18 @@
|
||||||
<className>org.jivesoftware.smackx.push_notifications.provider.RemoteDisablingProvider</className>
|
<className>org.jivesoftware.smackx.push_notifications.provider.RemoteDisablingProvider</className>
|
||||||
</extensionProvider>
|
</extensionProvider>
|
||||||
|
|
||||||
|
<!-- XEP-0359: Stable and Unique Stanza IDs -->
|
||||||
|
<extensionProvider>
|
||||||
|
<elementName>stanza-id</elementName>
|
||||||
|
<namespace>urn:xmpp:sid:0</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.sid.provider.StanzaIdProvider</className>
|
||||||
|
</extensionProvider>
|
||||||
|
<extensionProvider>
|
||||||
|
<elementName>origin-id</elementName>
|
||||||
|
<namespace>urn:xmpp:sid:0</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.sid.provider.OriginIdProvider</className>
|
||||||
|
</extensionProvider>
|
||||||
|
|
||||||
<!-- XEP-0333: Chat Markers -->
|
<!-- XEP-0333: Chat Markers -->
|
||||||
<extensionProvider>
|
<extensionProvider>
|
||||||
<elementName>markable</elementName>
|
<elementName>markable</elementName>
|
||||||
|
@ -284,4 +296,18 @@
|
||||||
<className>org.jivesoftware.smackx.eme.provider.ExplicitMessageEncryptionProvider</className>
|
<className>org.jivesoftware.smackx.eme.provider.ExplicitMessageEncryptionProvider</className>
|
||||||
</extensionProvider>
|
</extensionProvider>
|
||||||
|
|
||||||
|
<!-- XEP-0382: Spoiler Messages -->
|
||||||
|
<extensionProvider>
|
||||||
|
<elementName>spoiler</elementName>
|
||||||
|
<namespace>urn:xmpp:spoiler:0</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.spoiler.provider.SpoilerProvider</className>
|
||||||
|
</extensionProvider>
|
||||||
|
|
||||||
|
<!-- XEP-0394: Message Markup -->
|
||||||
|
<extensionProvider>
|
||||||
|
<elementName>markup</elementName>
|
||||||
|
<namespace>urn:xmpp:markup:0</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.message_markup.provider.MarkupElementProvider</className>
|
||||||
|
</extensionProvider>
|
||||||
|
|
||||||
</smackProviders>
|
</smackProviders>
|
||||||
|
|
|
@ -6,5 +6,6 @@
|
||||||
<className>org.jivesoftware.smackx.iot.provisioning.IoTProvisioningManager</className>
|
<className>org.jivesoftware.smackx.iot.provisioning.IoTProvisioningManager</className>
|
||||||
<className>org.jivesoftware.smackx.httpfileupload.HttpFileUploadManager</className>
|
<className>org.jivesoftware.smackx.httpfileupload.HttpFileUploadManager</className>
|
||||||
<className>org.jivesoftware.smackx.eme.ExplicitMessageEncryptionManager</className>
|
<className>org.jivesoftware.smackx.eme.ExplicitMessageEncryptionManager</className>
|
||||||
|
<className>org.jivesoftware.smackx.sid.StableUniqueStanzaIdManager</className>
|
||||||
</startupClasses>
|
</startupClasses>
|
||||||
</smack>
|
</smack>
|
||||||
|
|
|
@ -0,0 +1,227 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright © 2018 Paul Schaub
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smackx.message_markup;
|
||||||
|
|
||||||
|
import static junit.framework.TestCase.assertEquals;
|
||||||
|
import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.test.util.SmackTestSuite;
|
||||||
|
import org.jivesoftware.smack.test.util.TestUtils;
|
||||||
|
import org.jivesoftware.smackx.message_markup.element.BlockQuoteElement;
|
||||||
|
import org.jivesoftware.smackx.message_markup.element.CodeBlockElement;
|
||||||
|
import org.jivesoftware.smackx.message_markup.element.ListElement;
|
||||||
|
import org.jivesoftware.smackx.message_markup.element.MarkupElement;
|
||||||
|
import org.jivesoftware.smackx.message_markup.element.SpanElement;
|
||||||
|
import org.jivesoftware.smackx.message_markup.provider.MarkupElementProvider;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.xmlpull.v1.XmlPullParser;
|
||||||
|
|
||||||
|
public class MessageMarkupTest extends SmackTestSuite {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void emphasisTest() throws Exception {
|
||||||
|
String xml =
|
||||||
|
"<markup xmlns='urn:xmpp:markup:0'>" +
|
||||||
|
"<span start='9' end='15'>" +
|
||||||
|
"<emphasis/>" +
|
||||||
|
"</span>" +
|
||||||
|
"</markup>";
|
||||||
|
MarkupElement.Builder m = MarkupElement.getBuilder();
|
||||||
|
m.setEmphasis(9, 15);
|
||||||
|
assertXMLEqual(xml, m.build().toXML().toString());
|
||||||
|
|
||||||
|
XmlPullParser parser = TestUtils.getParser(xml);
|
||||||
|
MarkupElement parsed = new MarkupElementProvider().parse(parser);
|
||||||
|
List<MarkupElement.MarkupChildElement> children = parsed.getChildElements();
|
||||||
|
assertEquals(1, children.size());
|
||||||
|
|
||||||
|
SpanElement spanElement = (SpanElement) children.get(0);
|
||||||
|
assertEquals(9, spanElement.getStart());
|
||||||
|
assertEquals(15, spanElement.getEnd());
|
||||||
|
assertEquals(1, spanElement.getStyles().size());
|
||||||
|
assertEquals(SpanElement.SpanStyle.emphasis, spanElement.getStyles().iterator().next());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void codeTest() throws Exception {
|
||||||
|
String xml =
|
||||||
|
"<markup xmlns='urn:xmpp:markup:0'>" +
|
||||||
|
"<span start='9' end='15'>" +
|
||||||
|
"<code/>" +
|
||||||
|
"</span>" +
|
||||||
|
"</markup>";
|
||||||
|
MarkupElement.Builder m = MarkupElement.getBuilder();
|
||||||
|
m.setCode(9, 15);
|
||||||
|
assertXMLEqual(xml, m.build().toXML().toString());
|
||||||
|
|
||||||
|
XmlPullParser parser = TestUtils.getParser(xml);
|
||||||
|
MarkupElement parsed = new MarkupElementProvider().parse(parser);
|
||||||
|
List<MarkupElement.MarkupChildElement> children = parsed.getChildElements();
|
||||||
|
assertEquals(1, children.size());
|
||||||
|
|
||||||
|
SpanElement spanElement = (SpanElement) children.get(0);
|
||||||
|
assertEquals(9, spanElement.getStart());
|
||||||
|
assertEquals(15, spanElement.getEnd());
|
||||||
|
assertEquals(1, spanElement.getStyles().size());
|
||||||
|
assertEquals(SpanElement.SpanStyle.code, spanElement.getStyles().iterator().next());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deletedTest() throws Exception {
|
||||||
|
String xml =
|
||||||
|
"<markup xmlns='urn:xmpp:markup:0'>" +
|
||||||
|
"<span start='9' end='15'>" +
|
||||||
|
"<deleted/>" +
|
||||||
|
"</span>" +
|
||||||
|
"</markup>";
|
||||||
|
MarkupElement.Builder m = MarkupElement.getBuilder();
|
||||||
|
m.setDeleted(9, 15);
|
||||||
|
assertXMLEqual(xml, m.build().toXML().toString());
|
||||||
|
|
||||||
|
XmlPullParser parser = TestUtils.getParser(xml);
|
||||||
|
MarkupElement parsed = new MarkupElementProvider().parse(parser);
|
||||||
|
List<MarkupElement.MarkupChildElement> children = parsed.getChildElements();
|
||||||
|
assertEquals(1, children.size());
|
||||||
|
|
||||||
|
SpanElement spanElement = (SpanElement) children.get(0);
|
||||||
|
assertEquals(9, spanElement.getStart());
|
||||||
|
assertEquals(15, spanElement.getEnd());
|
||||||
|
assertEquals(1, spanElement.getStyles().size());
|
||||||
|
assertEquals(SpanElement.SpanStyle.deleted, spanElement.getStyles().iterator().next());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
public void wrongStartEndTest() {
|
||||||
|
MarkupElement.getBuilder().setEmphasis(12, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
public void overlappingSpansTest() {
|
||||||
|
MarkupElement.Builder m = MarkupElement.getBuilder();
|
||||||
|
m.setEmphasis(0, 10);
|
||||||
|
m.setDeleted(5, 15);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void codeBlockTest() throws Exception {
|
||||||
|
String xml =
|
||||||
|
"<markup xmlns='urn:xmpp:markup:0'>" +
|
||||||
|
"<bcode start='23' end='48'/>" +
|
||||||
|
"</markup>";
|
||||||
|
MarkupElement.Builder m = MarkupElement.getBuilder();
|
||||||
|
m.setCodeBlock(23, 48);
|
||||||
|
assertXMLEqual(xml, m.build().toXML().toString());
|
||||||
|
|
||||||
|
XmlPullParser parser = TestUtils.getParser(xml);
|
||||||
|
MarkupElement parsed = new MarkupElementProvider().parse(parser);
|
||||||
|
List<MarkupElement.MarkupChildElement> children = parsed.getChildElements();
|
||||||
|
assertEquals(1, children.size());
|
||||||
|
|
||||||
|
CodeBlockElement codeBlock = (CodeBlockElement) children.get(0);
|
||||||
|
assertEquals(23, codeBlock.getStart());
|
||||||
|
assertEquals(48, codeBlock.getEnd());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void listTest() throws Exception {
|
||||||
|
String xml =
|
||||||
|
"<markup xmlns='urn:xmpp:markup:0'>" +
|
||||||
|
"<list start='31' end='89'>" +
|
||||||
|
"<li start='31'/>" +
|
||||||
|
"<li start='47'/>" +
|
||||||
|
"<li start='61'/>" +
|
||||||
|
"<li start='69'/>" +
|
||||||
|
"</list>" +
|
||||||
|
"</markup>";
|
||||||
|
MarkupElement.Builder m = MarkupElement.getBuilder();
|
||||||
|
m = m.beginList()
|
||||||
|
.addEntry(31, 47)
|
||||||
|
.addEntry(47, 61)
|
||||||
|
.addEntry(61, 69)
|
||||||
|
.addEntry(69, 89)
|
||||||
|
.endList();
|
||||||
|
assertXMLEqual(xml, m.build().toXML().toString());
|
||||||
|
|
||||||
|
XmlPullParser parser = TestUtils.getParser(xml);
|
||||||
|
MarkupElement parsed = new MarkupElementProvider().parse(parser);
|
||||||
|
List<MarkupElement.MarkupChildElement> children = parsed.getChildElements();
|
||||||
|
assertEquals(1, children.size());
|
||||||
|
|
||||||
|
ListElement list = (ListElement) children.get(0);
|
||||||
|
assertEquals(31, list.getStart());
|
||||||
|
assertEquals(89, list.getEnd());
|
||||||
|
assertEquals(4, list.getEntries().size());
|
||||||
|
assertEquals(list.getStart(), list.getEntries().get(0).getStart());
|
||||||
|
assertEquals(47, list.getEntries().get(1).getStart());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
public void listWrongSecondEntryTest() {
|
||||||
|
MarkupElement.Builder m = MarkupElement.getBuilder();
|
||||||
|
m.beginList().addEntry(0,1).addEntry(3,4);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void blockQuoteTest() throws Exception {
|
||||||
|
String xml =
|
||||||
|
"<markup xmlns='urn:xmpp:markup:0'>" +
|
||||||
|
"<bquote start='9' end='32'/>" +
|
||||||
|
"</markup>";
|
||||||
|
MarkupElement.Builder m = MarkupElement.getBuilder();
|
||||||
|
m.setBlockQuote(9 ,32);
|
||||||
|
assertXMLEqual(xml, m.build().toXML().toString());
|
||||||
|
|
||||||
|
XmlPullParser parser = TestUtils.getParser(xml);
|
||||||
|
MarkupElement parsed = new MarkupElementProvider().parse(parser);
|
||||||
|
List<MarkupElement.MarkupChildElement> children = parsed.getChildElements();
|
||||||
|
assertEquals(1, children.size());
|
||||||
|
|
||||||
|
BlockQuoteElement quote = (BlockQuoteElement) children.get(0);
|
||||||
|
assertEquals(9, quote.getStart());
|
||||||
|
assertEquals(32, quote.getEnd());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void nestedBlockQuoteTest() throws Exception {
|
||||||
|
String xml =
|
||||||
|
"<markup xmlns='urn:xmpp:markup:0'>" +
|
||||||
|
"<bquote start='0' end='57'/>" +
|
||||||
|
"<bquote start='11' end='34'/>" +
|
||||||
|
"</markup>";
|
||||||
|
MarkupElement.Builder m = MarkupElement.getBuilder();
|
||||||
|
m.setBlockQuote(0, 57);
|
||||||
|
m.setBlockQuote(11, 34);
|
||||||
|
assertXMLEqual(xml, m.build().toXML().toString());
|
||||||
|
|
||||||
|
XmlPullParser parser = TestUtils.getParser(xml);
|
||||||
|
MarkupElement parsed = new MarkupElementProvider().parse(parser);
|
||||||
|
List<MarkupElement.MarkupChildElement> children = parsed.getChildElements();
|
||||||
|
assertEquals(2, children.size());
|
||||||
|
|
||||||
|
BlockQuoteElement q1 = (BlockQuoteElement) children.get(0);
|
||||||
|
BlockQuoteElement q2 = (BlockQuoteElement) children.get(1);
|
||||||
|
|
||||||
|
assertEquals(0, q1.getStart());
|
||||||
|
assertEquals(57, q1.getEnd());
|
||||||
|
|
||||||
|
assertEquals(11, q2.getStart());
|
||||||
|
assertEquals(34, q2.getEnd());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,84 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright 2018 Paul Schaub
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smackx.sid;
|
||||||
|
|
||||||
|
import static junit.framework.TestCase.assertEquals;
|
||||||
|
import static junit.framework.TestCase.assertFalse;
|
||||||
|
import static junit.framework.TestCase.assertNotNull;
|
||||||
|
import static junit.framework.TestCase.assertTrue;
|
||||||
|
import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.packet.Message;
|
||||||
|
import org.jivesoftware.smack.test.util.SmackTestSuite;
|
||||||
|
import org.jivesoftware.smack.test.util.TestUtils;
|
||||||
|
import org.jivesoftware.smackx.sid.element.OriginIdElement;
|
||||||
|
import org.jivesoftware.smackx.sid.element.StanzaIdElement;
|
||||||
|
import org.jivesoftware.smackx.sid.provider.OriginIdProvider;
|
||||||
|
import org.jivesoftware.smackx.sid.provider.StanzaIdProvider;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class StableUniqueStanzaIdTest extends SmackTestSuite {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void stanzaIdProviderTest() throws Exception {
|
||||||
|
String xml = "<stanza-id xmlns='urn:xmpp:sid:0' id='de305d54-75b4-431b-adb2-eb6b9e546013' by='alice@wonderland.lit' />";
|
||||||
|
StanzaIdElement element = new StanzaIdElement("de305d54-75b4-431b-adb2-eb6b9e546013", "alice@wonderland.lit");
|
||||||
|
assertEquals("de305d54-75b4-431b-adb2-eb6b9e546013", element.getId());
|
||||||
|
assertEquals("alice@wonderland.lit", element.getBy());
|
||||||
|
assertXMLEqual(xml, element.toXML().toString());
|
||||||
|
|
||||||
|
StanzaIdElement parsed = StanzaIdProvider.TEST_INSTANCE.parse(TestUtils.getParser(xml));
|
||||||
|
assertEquals(element.getId(), parsed.getId());
|
||||||
|
assertEquals(element.getBy(), parsed.getBy());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void originIdProviderTest() throws Exception {
|
||||||
|
String xml = "<origin-id xmlns='urn:xmpp:sid:0' id='de305d54-75b4-431b-adb2-eb6b9e546013' />";
|
||||||
|
OriginIdElement element = new OriginIdElement("de305d54-75b4-431b-adb2-eb6b9e546013");
|
||||||
|
assertEquals("de305d54-75b4-431b-adb2-eb6b9e546013", element.getId());
|
||||||
|
assertXMLEqual(xml, element.toXML().toString());
|
||||||
|
|
||||||
|
OriginIdElement parsed = OriginIdProvider.TEST_INSTANCE.parse(TestUtils.getParser(xml));
|
||||||
|
assertEquals(element.getId(), parsed.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createOriginIdTest() {
|
||||||
|
OriginIdElement element = new OriginIdElement();
|
||||||
|
assertNotNull(element);
|
||||||
|
assertEquals(StableUniqueStanzaIdManager.NAMESPACE, element.getNamespace());
|
||||||
|
assertEquals(36, element.getId().length());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void fromMessageTest() {
|
||||||
|
Message message = new Message();
|
||||||
|
assertFalse(OriginIdElement.hasOriginId(message));
|
||||||
|
assertFalse(StanzaIdElement.hasStanzaId(message));
|
||||||
|
|
||||||
|
OriginIdElement.addOriginId(message);
|
||||||
|
|
||||||
|
assertTrue(OriginIdElement.hasOriginId(message));
|
||||||
|
|
||||||
|
StanzaIdElement stanzaId = new StanzaIdElement("alice@wonderland.lit");
|
||||||
|
message.addExtension(stanzaId);
|
||||||
|
assertTrue(StanzaIdElement.hasStanzaId(message));
|
||||||
|
assertEquals(stanzaId, StanzaIdElement.getStanzaId(message));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,128 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright 2018 Paul Schaub
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smackx.spoiler;
|
||||||
|
|
||||||
|
import static junit.framework.TestCase.assertEquals;
|
||||||
|
import static junit.framework.TestCase.assertNull;
|
||||||
|
import static junit.framework.TestCase.assertTrue;
|
||||||
|
import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.packet.Message;
|
||||||
|
import org.jivesoftware.smack.test.util.SmackTestSuite;
|
||||||
|
import org.jivesoftware.smack.test.util.TestUtils;
|
||||||
|
import org.jivesoftware.smackx.spoiler.element.SpoilerElement;
|
||||||
|
import org.jivesoftware.smackx.spoiler.provider.SpoilerProvider;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.xmlpull.v1.XmlPullParser;
|
||||||
|
|
||||||
|
public class SpoilerTest extends SmackTestSuite {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void emptySpoilerTest() throws Exception {
|
||||||
|
final String xml = "<spoiler xmlns='urn:xmpp:spoiler:0'/>";
|
||||||
|
|
||||||
|
Message message = new Message();
|
||||||
|
SpoilerElement.addSpoiler(message);
|
||||||
|
|
||||||
|
SpoilerElement empty = message.getExtension(SpoilerElement.ELEMENT, SpoilerManager.NAMESPACE_0);
|
||||||
|
|
||||||
|
assertNull(empty.getHint());
|
||||||
|
assertNull(empty.getLanguage());
|
||||||
|
|
||||||
|
assertXMLEqual(xml, empty.toXML().toString());
|
||||||
|
|
||||||
|
XmlPullParser parser = TestUtils.getParser(xml);
|
||||||
|
SpoilerElement parsed = SpoilerProvider.INSTANCE.parse(parser);
|
||||||
|
assertXMLEqual(xml, parsed.toXML().toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void hintSpoilerTest() throws Exception {
|
||||||
|
final String xml = "<spoiler xmlns='urn:xmpp:spoiler:0'>Love story end</spoiler>";
|
||||||
|
|
||||||
|
Message message = new Message();
|
||||||
|
SpoilerElement.addSpoiler(message, "Love story end");
|
||||||
|
|
||||||
|
SpoilerElement withHint = message.getExtension(SpoilerElement.ELEMENT, SpoilerManager.NAMESPACE_0);
|
||||||
|
|
||||||
|
assertEquals("Love story end", withHint.getHint());
|
||||||
|
assertNull(withHint.getLanguage());
|
||||||
|
|
||||||
|
assertXMLEqual(xml, withHint.toXML().toString());
|
||||||
|
|
||||||
|
XmlPullParser parser = TestUtils.getParser(xml);
|
||||||
|
SpoilerElement parsed = SpoilerProvider.INSTANCE.parse(parser);
|
||||||
|
|
||||||
|
assertXMLEqual(xml, parsed.toXML().toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void i18nHintSpoilerTest() throws Exception {
|
||||||
|
final String xml = "<spoiler xml:lang='de' xmlns='urn:xmpp:spoiler:0'>Der Kuchen ist eine Lüge!</spoiler>";
|
||||||
|
|
||||||
|
Message message = new Message();
|
||||||
|
SpoilerElement.addSpoiler(message, "de", "Der Kuchen ist eine Lüge!");
|
||||||
|
|
||||||
|
SpoilerElement i18nHint = message.getExtension(SpoilerElement.ELEMENT, SpoilerManager.NAMESPACE_0);
|
||||||
|
|
||||||
|
assertEquals("Der Kuchen ist eine Lüge!", i18nHint.getHint());
|
||||||
|
assertEquals("de", i18nHint.getLanguage());
|
||||||
|
|
||||||
|
assertXMLEqual(xml, i18nHint.toXML().toString());
|
||||||
|
|
||||||
|
XmlPullParser parser = TestUtils.getParser(xml);
|
||||||
|
SpoilerElement parsed = SpoilerProvider.INSTANCE.parse(parser);
|
||||||
|
assertEquals(i18nHint.getLanguage(), parsed.getLanguage());
|
||||||
|
|
||||||
|
assertXMLEqual(xml, parsed.toXML().toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getSpoilersTest() {
|
||||||
|
Message m = new Message();
|
||||||
|
assertTrue(SpoilerElement.getSpoilers(m).isEmpty());
|
||||||
|
|
||||||
|
SpoilerElement.addSpoiler(m);
|
||||||
|
assertTrue(SpoilerElement.containsSpoiler(m));
|
||||||
|
|
||||||
|
Map<String, String> spoilers = SpoilerElement.getSpoilers(m);
|
||||||
|
assertEquals(1, spoilers.size());
|
||||||
|
assertEquals(null, spoilers.get(""));
|
||||||
|
|
||||||
|
final String spoilerText = "Spoiler Text";
|
||||||
|
|
||||||
|
SpoilerElement.addSpoiler(m, "de", spoilerText);
|
||||||
|
spoilers = SpoilerElement.getSpoilers(m);
|
||||||
|
assertEquals(2, spoilers.size());
|
||||||
|
assertEquals(spoilerText, spoilers.get("de"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
public void spoilerCheckArgumentsNullTest() {
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
SpoilerElement spoilerElement = new SpoilerElement("de", null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
public void spoilerCheckArgumentsEmptyTest() {
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
SpoilerElement spoilerElement = new SpoilerElement("de", "");
|
||||||
|
}
|
||||||
|
}
|
|
@ -271,7 +271,11 @@ public final class AdHocCommandManager extends Manager {
|
||||||
* @throws XMPPException if the operation failed for some reason.
|
* @throws XMPPException if the operation failed for some reason.
|
||||||
* @throws SmackException if there was no response from the server.
|
* @throws SmackException if there was no response from the server.
|
||||||
* @throws InterruptedException
|
* @throws InterruptedException
|
||||||
|
* @deprecated This method uses no longer existent XEP-0030 features and will be removed.
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
@Deprecated
|
||||||
|
// TODO: Remove in Smack 4.4.
|
||||||
public void publishCommands(Jid jid) throws XMPPException, SmackException, InterruptedException {
|
public void publishCommands(Jid jid) throws XMPPException, SmackException, InterruptedException {
|
||||||
// Collects the commands to publish as items
|
// Collects the commands to publish as items
|
||||||
DiscoverItems discoverItems = new DiscoverItems();
|
DiscoverItems discoverItems = new DiscoverItems();
|
||||||
|
|
|
@ -27,7 +27,6 @@ import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.WeakHashMap;
|
import java.util.WeakHashMap;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
import org.jivesoftware.smack.ConnectionCreationListener;
|
import org.jivesoftware.smack.ConnectionCreationListener;
|
||||||
import org.jivesoftware.smack.Manager;
|
import org.jivesoftware.smack.Manager;
|
||||||
|
@ -71,8 +70,6 @@ import org.jxmpp.util.cache.ExpirationCache;
|
||||||
*/
|
*/
|
||||||
public final class ServiceDiscoveryManager extends Manager {
|
public final class ServiceDiscoveryManager extends Manager {
|
||||||
|
|
||||||
private static final Logger LOGGER = Logger.getLogger(ServiceDiscoveryManager.class.getName());
|
|
||||||
|
|
||||||
private static final String DEFAULT_IDENTITY_NAME = "Smack";
|
private static final String DEFAULT_IDENTITY_NAME = "Smack";
|
||||||
private static final String DEFAULT_IDENTITY_CATEGORY = "client";
|
private static final String DEFAULT_IDENTITY_CATEGORY = "client";
|
||||||
private static final String DEFAULT_IDENTITY_TYPE = "pc";
|
private static final String DEFAULT_IDENTITY_TYPE = "pc";
|
||||||
|
@ -595,7 +592,10 @@ public final class ServiceDiscoveryManager extends Manager {
|
||||||
* @throws NoResponseException
|
* @throws NoResponseException
|
||||||
* @throws NotConnectedException
|
* @throws NotConnectedException
|
||||||
* @throws InterruptedException
|
* @throws InterruptedException
|
||||||
|
* @deprecated The disco-publish feature was removed from XEP-0030 in 2008 in favor of XEP-0060: Publish-Subscribe.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
|
// TODO: Remove in Smack 4.4
|
||||||
public boolean canPublishItems(Jid entityID) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
public boolean canPublishItems(Jid entityID) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
||||||
DiscoverInfo info = discoverInfo(entityID);
|
DiscoverInfo info = discoverInfo(entityID);
|
||||||
return canPublishItems(info);
|
return canPublishItems(info);
|
||||||
|
@ -609,7 +609,10 @@ public final class ServiceDiscoveryManager extends Manager {
|
||||||
*
|
*
|
||||||
* @param info the discover info stanza(/packet) to check.
|
* @param info the discover info stanza(/packet) to check.
|
||||||
* @return true if the server supports publishing of items.
|
* @return true if the server supports publishing of items.
|
||||||
|
* @deprecated The disco-publish feature was removed from XEP-0030 in 2008 in favor of XEP-0060: Publish-Subscribe.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
|
// TODO: Remove in Smack 4.4
|
||||||
public static boolean canPublishItems(DiscoverInfo info) {
|
public static boolean canPublishItems(DiscoverInfo info) {
|
||||||
return info.containsFeature("http://jabber.org/protocol/disco#publish");
|
return info.containsFeature("http://jabber.org/protocol/disco#publish");
|
||||||
}
|
}
|
||||||
|
@ -626,7 +629,10 @@ public final class ServiceDiscoveryManager extends Manager {
|
||||||
* @throws NoResponseException
|
* @throws NoResponseException
|
||||||
* @throws NotConnectedException
|
* @throws NotConnectedException
|
||||||
* @throws InterruptedException
|
* @throws InterruptedException
|
||||||
|
* @deprecated The disco-publish feature was removed from XEP-0030 in 2008 in favor of XEP-0060: Publish-Subscribe.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
|
// TODO: Remove in Smack 4.4
|
||||||
public void publishItems(Jid entityID, DiscoverItems discoverItems) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
public void publishItems(Jid entityID, DiscoverItems discoverItems) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
||||||
publishItems(entityID, null, discoverItems);
|
publishItems(entityID, null, discoverItems);
|
||||||
}
|
}
|
||||||
|
@ -644,7 +650,10 @@ public final class ServiceDiscoveryManager extends Manager {
|
||||||
* @throws NoResponseException if there was no response from the server.
|
* @throws NoResponseException if there was no response from the server.
|
||||||
* @throws NotConnectedException
|
* @throws NotConnectedException
|
||||||
* @throws InterruptedException
|
* @throws InterruptedException
|
||||||
|
* @deprecated The disco-publish feature was removed from XEP-0030 in 2008 in favor of XEP-0060: Publish-Subscribe.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
|
// TODO: Remove in Smack 4.4
|
||||||
public void publishItems(Jid entityID, String node, DiscoverItems discoverItems) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException
|
public void publishItems(Jid entityID, String node, DiscoverItems discoverItems) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException
|
||||||
{
|
{
|
||||||
discoverItems.setType(IQ.Type.set);
|
discoverItems.setType(IQ.Type.set);
|
||||||
|
|
Loading…
Reference in a new issue