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