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 String 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(String jid) {
58 this.jid = jid;
59 }
60
61 public String 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 item = packet.findChild("x",
162 "http://jabber.org/protocol/muc#user")
163 .findChild("item");
164 user.setName(name);
165 user.setAffiliation(item.getAttribute("affiliation"));
166 user.setRole(item.getAttribute("role"));
167 user.setJid(item.getAttribute("jid"));
168 user.setName(name);
169 if (name.equals(this.joinnick)) {
170 this.isOnline = true;
171 this.error = ERROR_NO_ERROR;
172 self = user;
173 if (aboutToRename) {
174 if (renameListener != null) {
175 renameListener.onRename(true);
176 }
177 aboutToRename = false;
178 }
179 } else {
180 addUser(user);
181 }
182 if (pgp != null) {
183 Element x = packet.findChild("x", "jabber:x:signed");
184 if (x != null) {
185 Element status = packet.findChild("status");
186 String msg;
187 if (status != null) {
188 msg = status.getContent();
189 } else {
190 msg = "";
191 }
192 user.setPgpKeyId(pgp.fetchKeyId(account, msg,
193 x.getContent()));
194 }
195 }
196 } else if (type.equals("unavailable") && name.equals(this.joinnick)) {
197 Element x = packet.findChild("x",
198 "http://jabber.org/protocol/muc#user");
199 if (x != null) {
200 Element status = x.findChild("status");
201 if (status != null) {
202 String code = status.getAttribute("code");
203 if (STATUS_CODE_KICKED.equals(code)) {
204 this.isOnline = false;
205 this.error = KICKED_FROM_ROOM;
206 } else if (STATUS_CODE_BANNED.equals(code)) {
207 this.isOnline = false;
208 this.error = ERROR_BANNED;
209 }
210 }
211 }
212 } else if (type.equals("unavailable")) {
213 deleteUser(packet.getAttribute("from").split("/", 2)[1]);
214 } else if (type.equals("error")) {
215 Element error = packet.findChild("error");
216 if (error != null && error.hasChild("conflict")) {
217 if (aboutToRename) {
218 if (renameListener != null) {
219 renameListener.onRename(false);
220 }
221 aboutToRename = false;
222 this.setJoinNick(getActualNick());
223 } else {
224 this.error = ERROR_NICK_IN_USE;
225 }
226 } else if (error != null && error.hasChild("not-authorized")) {
227 this.error = ERROR_PASSWORD_REQUIRED;
228 } else if (error != null && error.hasChild("forbidden")) {
229 this.error = ERROR_BANNED;
230 } else if (error != null
231 && error.hasChild("registration-required")) {
232 this.error = ERROR_MEMBERS_ONLY;
233 }
234 }
235 }
236 }
237
238 public List<User> getUsers() {
239 return this.users;
240 }
241
242 public String getProposedNick() {
243 if (conversation.getBookmark() != null
244 && conversation.getBookmark().getNick() != null) {
245 return conversation.getBookmark().getNick();
246 } else {
247 if (!conversation.getContactJid().isBareJid()) {
248 return conversation.getContactJid().getResourcepart();
249 } else {
250 return account.getUsername();
251 }
252 }
253 }
254
255 public String getActualNick() {
256 if (this.self.getName() != null) {
257 return this.self.getName();
258 } else {
259 return this.getProposedNick();
260 }
261 }
262
263 public void setJoinNick(String nick) {
264 this.joinnick = nick;
265 }
266
267 public boolean online() {
268 return this.isOnline;
269 }
270
271 public int getError() {
272 return this.error;
273 }
274
275 public void setOnRenameListener(OnRenameListener listener) {
276 this.renameListener = listener;
277 }
278
279 public OnRenameListener getOnRenameListener() {
280 return this.renameListener;
281 }
282
283 public void setOffline() {
284 this.users.clear();
285 this.error = 0;
286 this.isOnline = false;
287 }
288
289 public User getSelf() {
290 return self;
291 }
292
293 public void setSubject(String content) {
294 this.subject = content;
295 }
296
297 public String getSubject() {
298 return this.subject;
299 }
300
301 public void flagAboutToRename() {
302 this.aboutToRename = true;
303 }
304
305 public long[] getPgpKeyIds() {
306 List<Long> ids = new ArrayList<>();
307 for (User user : getUsers()) {
308 if (user.getPgpKeyId() != 0) {
309 ids.add(user.getPgpKeyId());
310 }
311 }
312 long[] primitivLongArray = new long[ids.size()];
313 for (int i = 0; i < ids.size(); ++i) {
314 primitivLongArray[i] = ids.get(i);
315 }
316 return primitivLongArray;
317 }
318
319 public boolean pgpKeysInUse() {
320 for (User user : getUsers()) {
321 if (user.getPgpKeyId() != 0) {
322 return true;
323 }
324 }
325 return false;
326 }
327
328 public boolean everybodyHasKeys() {
329 for (User user : getUsers()) {
330 if (user.getPgpKeyId() == 0) {
331 return false;
332 }
333 }
334 return true;
335 }
336
337 public Jid getJoinJid() {
338 try {
339 return Jid.fromString(this.conversation.getContactJid().toBareJid().toString() + "/"
340+ this.joinnick);
341 } catch (final InvalidJidException e) {
342 return null;
343 }
344 }
345
346 public String getTrueCounterpart(String counterpart) {
347 for (User user : this.getUsers()) {
348 if (user.getName().equals(counterpart)) {
349 return user.getJid();
350 }
351 }
352 return null;
353 }
354
355 public String getPassword() {
356 this.password = conversation
357 .getAttribute(Conversation.ATTRIBUTE_MUC_PASSWORD);
358 if (this.password == null && conversation.getBookmark() != null
359 && conversation.getBookmark().getPassword() != null) {
360 return conversation.getBookmark().getPassword();
361 } else {
362 return this.password;
363 }
364 }
365
366 public void setPassword(String password) {
367 if (conversation.getBookmark() != null) {
368 conversation.getBookmark().setPassword(password);
369 } else {
370 this.password = password;
371 }
372 conversation
373 .setAttribute(Conversation.ATTRIBUTE_MUC_PASSWORD, password);
374 }
375
376 public Conversation getConversation() {
377 return this.conversation;
378 }
379}