1package im.conversations.android.xmpp.model.stanza;
2
3import com.google.common.base.Joiner;
4import com.google.common.base.Strings;
5import com.google.common.collect.ImmutableMultimap;
6import com.google.common.collect.Iterables;
7import com.google.common.collect.Maps;
8import eu.siacs.conversations.Config;
9import eu.siacs.conversations.xml.Element;
10import eu.siacs.conversations.xml.LocalizedContent;
11import im.conversations.android.annotation.XmlElement;
12import im.conversations.android.xmpp.model.Extension;
13import im.conversations.android.xmpp.model.jabber.Body;
14import im.conversations.android.xmpp.model.jabber.Subject;
15import java.util.Locale;
16
17@XmlElement
18public class Message extends Stanza {
19
20 public Message() {
21 super(Message.class);
22 }
23
24 public Message(Type type) {
25 this();
26 this.setType(type);
27 }
28
29 public LocalizedContent getBody() {
30 return getLocalizedContent(Body.class);
31 }
32
33 public LocalizedContent getSubject() {
34 return getLocalizedContent(Subject.class);
35 }
36
37 private LocalizedContent getLocalizedContent(final Class<? extends Extension> clazz) {
38 final var builder = new ImmutableMultimap.Builder<String, String>();
39 final var messageLanguage = this.getAttribute("xml:lang");
40 final var parentLanguage =
41 Strings.isNullOrEmpty(messageLanguage)
42 ? LocalizedContent.STREAM_LANGUAGE
43 : messageLanguage;
44 for (final var element : this.getExtensions(clazz)) {
45 final var elementLanguage = element.getAttribute("xml:lang");
46 final var language =
47 Strings.isNullOrEmpty(elementLanguage) ? parentLanguage : elementLanguage;
48 final var content = element.getContent();
49 if (content == null) {
50 continue;
51 }
52 builder.put(language, content);
53 }
54 final var multiMap = builder.build().asMap();
55 if (Config.TREAT_MULTI_CONTENT_AS_INVALID
56 && Iterables.any(multiMap.values(), v -> v.size() > 1)) {
57 return null;
58 }
59 return LocalizedContent.get(Maps.transformValues(multiMap, v -> Joiner.on('\n').join(v)));
60 }
61
62 public Type getType() {
63 final var value = this.getAttribute("type");
64 if (value == null) {
65 return Type.NORMAL;
66 } else {
67 try {
68 return Type.valueOf(value.toUpperCase(Locale.ROOT));
69 } catch (final IllegalArgumentException e) {
70 return null;
71 }
72 }
73 }
74
75 public void setType(final Type type) {
76 if (type == null || type == Type.NORMAL) {
77 this.removeAttribute("type");
78 } else {
79 this.setAttribute("type", type.toString().toLowerCase(Locale.ROOT));
80 }
81 }
82
83 public void setBody(final String text) {
84 this.addExtension(new Body(text));
85 }
86
87 public void setAxolotlMessage(Element axolotlMessage) {
88 this.children.remove(findChild("body"));
89 this.children.add(0, axolotlMessage);
90 }
91
92 public enum Type {
93 ERROR,
94 NORMAL,
95 GROUPCHAT,
96 HEADLINE,
97 CHAT
98 }
99}