MucOptions.java

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