1package eu.siacs.conversations.entities;
2
3import java.util.ArrayList;
4import java.util.List;
5import java.util.concurrent.CopyOnWriteArrayList;
6
7import eu.siacs.conversations.crypto.PgpEngine;
8import eu.siacs.conversations.xml.Element;
9import eu.siacs.conversations.xmpp.jid.InvalidJidException;
10import eu.siacs.conversations.xmpp.jid.Jid;
11import eu.siacs.conversations.xmpp.stanzas.PresencePacket;
12import android.annotation.SuppressLint;
13
14@SuppressLint("DefaultLocale")
15public class MucOptions {
16 public static final int ERROR_NO_ERROR = 0;
17 public static final int ERROR_NICK_IN_USE = 1;
18 public static final int ERROR_ROOM_NOT_FOUND = 2;
19 public static final int ERROR_PASSWORD_REQUIRED = 3;
20 public static final int ERROR_BANNED = 4;
21 public static final int ERROR_MEMBERS_ONLY = 5;
22
23 public static final int KICKED_FROM_ROOM = 9;
24
25 public static final String STATUS_CODE_BANNED = "301";
26 public static final String STATUS_CODE_KICKED = "307";
27
28 public interface OnRenameListener {
29 public void onRename(boolean success);
30 }
31
32 public class User {
33 public static final int ROLE_MODERATOR = 3;
34 public static final int ROLE_NONE = 0;
35 public static final int ROLE_PARTICIPANT = 2;
36 public static final int ROLE_VISITOR = 1;
37 public static final int AFFILIATION_ADMIN = 4;
38 public static final int AFFILIATION_OWNER = 3;
39 public static final int AFFILIATION_MEMBER = 2;
40 public static final int AFFILIATION_OUTCAST = 1;
41 public static final int AFFILIATION_NONE = 0;
42
43 private int role;
44 private int affiliation;
45 private String name;
46 private Jid jid;
47 private long pgpKeyId = 0;
48
49 public String getName() {
50 return name;
51 }
52
53 public void setName(String user) {
54 this.name = user;
55 }
56
57 public void setJid(Jid jid) {
58 this.jid = jid;
59 }
60
61 public Jid getJid() {
62 return this.jid;
63 }
64
65 public int getRole() {
66 return this.role;
67 }
68
69 public void setRole(String role) {
70 role = role.toLowerCase();
71 switch (role) {
72 case "moderator":
73 this.role = ROLE_MODERATOR;
74 break;
75 case "participant":
76 this.role = ROLE_PARTICIPANT;
77 break;
78 case "visitor":
79 this.role = ROLE_VISITOR;
80 break;
81 default:
82 this.role = ROLE_NONE;
83 break;
84 }
85 }
86
87 public int getAffiliation() {
88 return this.affiliation;
89 }
90
91 public void setAffiliation(String affiliation) {
92 if (affiliation.equalsIgnoreCase("admin")) {
93 this.affiliation = AFFILIATION_ADMIN;
94 } else if (affiliation.equalsIgnoreCase("owner")) {
95 this.affiliation = AFFILIATION_OWNER;
96 } else if (affiliation.equalsIgnoreCase("member")) {
97 this.affiliation = AFFILIATION_MEMBER;
98 } else if (affiliation.equalsIgnoreCase("outcast")) {
99 this.affiliation = AFFILIATION_OUTCAST;
100 } else {
101 this.affiliation = AFFILIATION_NONE;
102 }
103 }
104
105 public void setPgpKeyId(long id) {
106 this.pgpKeyId = id;
107 }
108
109 public long getPgpKeyId() {
110 return this.pgpKeyId;
111 }
112
113 public Contact getContact() {
114 return account.getRoster().getContactFromRoster(getJid());
115 }
116 }
117
118 private Account account;
119 private List<User> users = new CopyOnWriteArrayList<>();
120 private Conversation conversation;
121 private boolean isOnline = false;
122 private int error = ERROR_ROOM_NOT_FOUND;
123 private OnRenameListener renameListener = null;
124 private boolean aboutToRename = false;
125 private User self = new User();
126 private String subject = null;
127 private String joinnick;
128 private String password = null;
129
130 public MucOptions(Conversation conversation) {
131 this.account = conversation.getAccount();
132 this.conversation = conversation;
133 }
134
135 public void deleteUser(String name) {
136 for (int i = 0; i < users.size(); ++i) {
137 if (users.get(i).getName().equals(name)) {
138 users.remove(i);
139 return;
140 }
141 }
142 }
143
144 public void addUser(User user) {
145 for (int i = 0; i < users.size(); ++i) {
146 if (users.get(i).getName().equals(user.getName())) {
147 users.set(i, user);
148 return;
149 }
150 }
151 users.add(user);
152 }
153
154 public void processPacket(PresencePacket packet, PgpEngine pgp) {
155 final Jid from = packet.getFrom();
156 if (!from.isBareJid()) {
157 final String name = from.getResourcepart();
158 String type = packet.getAttribute("type");
159 if (type == null) {
160 User user = new User();
161 Element x = packet.findChild("x","http://jabber.org/protocol/muc#user");
162 if (x != null) {
163 Element item = x.findChild("item");
164 if (item != null) {
165 user.setName(name);
166 user.setAffiliation(item.getAttribute("affiliation"));
167 user.setRole(item.getAttribute("role"));
168 user.setJid(item.getAttributeAsJid("jid"));
169 user.setName(name);
170 if (name.equals(this.joinnick)) {
171 this.isOnline = true;
172 this.error = ERROR_NO_ERROR;
173 self = user;
174 if (aboutToRename) {
175 if (renameListener != null) {
176 renameListener.onRename(true);
177 }
178 aboutToRename = false;
179 }
180 } else {
181 addUser(user);
182 }
183 if (pgp != null) {
184 Element signed = packet.findChild("x", "jabber:x:signed");
185 if (signed != null) {
186 Element status = packet.findChild("status");
187 String msg;
188 if (status != null) {
189 msg = status.getContent();
190 } else {
191 msg = "";
192 }
193 user.setPgpKeyId(pgp.fetchKeyId(account, msg,
194 signed.getContent()));
195 }
196 }
197 }
198 }
199 } else if (type.equals("unavailable") && name.equals(this.joinnick)) {
200 Element x = packet.findChild("x",
201 "http://jabber.org/protocol/muc#user");
202 if (x != null) {
203 Element status = x.findChild("status");
204 if (status != null) {
205 String code = status.getAttribute("code");
206 if (STATUS_CODE_KICKED.equals(code)) {
207 this.isOnline = false;
208 this.error = KICKED_FROM_ROOM;
209 } else if (STATUS_CODE_BANNED.equals(code)) {
210 this.isOnline = false;
211 this.error = ERROR_BANNED;
212 }
213 }
214 }
215 } else if (type.equals("unavailable")) {
216 deleteUser(packet.getAttribute("from").split("/", 2)[1]);
217 } else if (type.equals("error")) {
218 Element error = packet.findChild("error");
219 if (error != null && error.hasChild("conflict")) {
220 if (aboutToRename) {
221 if (renameListener != null) {
222 renameListener.onRename(false);
223 }
224 aboutToRename = false;
225 this.setJoinNick(getActualNick());
226 } else {
227 this.error = ERROR_NICK_IN_USE;
228 }
229 } else if (error != null && error.hasChild("not-authorized")) {
230 this.error = ERROR_PASSWORD_REQUIRED;
231 } else if (error != null && error.hasChild("forbidden")) {
232 this.error = ERROR_BANNED;
233 } else if (error != null
234 && error.hasChild("registration-required")) {
235 this.error = ERROR_MEMBERS_ONLY;
236 }
237 }
238 }
239 }
240
241 public List<User> getUsers() {
242 return this.users;
243 }
244
245 public String getProposedNick() {
246 if (conversation.getBookmark() != null
247 && conversation.getBookmark().getNick() != null) {
248 return conversation.getBookmark().getNick();
249 } else {
250 if (!conversation.getContactJid().isBareJid()) {
251 return conversation.getContactJid().getResourcepart();
252 } else {
253 return account.getUsername();
254 }
255 }
256 }
257
258 public String getActualNick() {
259 if (this.self.getName() != null) {
260 return this.self.getName();
261 } else {
262 return this.getProposedNick();
263 }
264 }
265
266 public void setJoinNick(String nick) {
267 this.joinnick = nick;
268 }
269
270 public boolean online() {
271 return this.isOnline;
272 }
273
274 public int getError() {
275 return this.error;
276 }
277
278 public void setOnRenameListener(OnRenameListener listener) {
279 this.renameListener = listener;
280 }
281
282 public OnRenameListener getOnRenameListener() {
283 return this.renameListener;
284 }
285
286 public void setOffline() {
287 this.users.clear();
288 this.error = 0;
289 this.isOnline = false;
290 }
291
292 public User getSelf() {
293 return self;
294 }
295
296 public void setSubject(String content) {
297 this.subject = content;
298 }
299
300 public String getSubject() {
301 return this.subject;
302 }
303
304 public void flagAboutToRename() {
305 this.aboutToRename = true;
306 }
307
308 public long[] getPgpKeyIds() {
309 List<Long> ids = new ArrayList<>();
310 for (User user : getUsers()) {
311 if (user.getPgpKeyId() != 0) {
312 ids.add(user.getPgpKeyId());
313 }
314 }
315 long[] primitivLongArray = new long[ids.size()];
316 for (int i = 0; i < ids.size(); ++i) {
317 primitivLongArray[i] = ids.get(i);
318 }
319 return primitivLongArray;
320 }
321
322 public boolean pgpKeysInUse() {
323 for (User user : getUsers()) {
324 if (user.getPgpKeyId() != 0) {
325 return true;
326 }
327 }
328 return false;
329 }
330
331 public boolean everybodyHasKeys() {
332 for (User user : getUsers()) {
333 if (user.getPgpKeyId() == 0) {
334 return false;
335 }
336 }
337 return true;
338 }
339
340 public Jid getJoinJid() {
341 try {
342 return Jid.fromString(this.conversation.getContactJid().toBareJid().toString() + "/"
343+ this.joinnick);
344 } catch (final InvalidJidException e) {
345 return null;
346 }
347 }
348
349 public Jid getTrueCounterpart(String counterpart) {
350 for (User user : this.getUsers()) {
351 if (user.getName().equals(counterpart)) {
352 return user.getJid();
353 }
354 }
355 return null;
356 }
357
358 public String getPassword() {
359 this.password = conversation
360 .getAttribute(Conversation.ATTRIBUTE_MUC_PASSWORD);
361 if (this.password == null && conversation.getBookmark() != null
362 && conversation.getBookmark().getPassword() != null) {
363 return conversation.getBookmark().getPassword();
364 } else {
365 return this.password;
366 }
367 }
368
369 public void setPassword(String password) {
370 if (conversation.getBookmark() != null) {
371 conversation.getBookmark().setPassword(password);
372 } else {
373 this.password = password;
374 }
375 conversation
376 .setAttribute(Conversation.ATTRIBUTE_MUC_PASSWORD, password);
377 }
378
379 public Conversation getConversation() {
380 return this.conversation;
381 }
382}