MucOptions.java

  1package eu.siacs.conversations.entities;
  2
  3import android.annotation.SuppressLint;
  4
  5import java.util.ArrayList;
  6import java.util.Collections;
  7import java.util.LinkedHashMap;
  8import java.util.List;
  9import java.util.Map;
 10
 11import eu.siacs.conversations.R;
 12import eu.siacs.conversations.xmpp.forms.Data;
 13import eu.siacs.conversations.xmpp.forms.Field;
 14import eu.siacs.conversations.xmpp.jid.InvalidJidException;
 15import eu.siacs.conversations.xmpp.jid.Jid;
 16import eu.siacs.conversations.xmpp.pep.Avatar;
 17
 18@SuppressLint("DefaultLocale")
 19public class MucOptions {
 20
 21	public Account getAccount() {
 22		return this.conversation.getAccount();
 23	}
 24
 25	public void setSelf(User user) {
 26		this.self = user;
 27	}
 28
 29	public enum Affiliation {
 30		OWNER("owner", 4, R.string.owner),
 31		ADMIN("admin", 3, R.string.admin),
 32		MEMBER("member", 2, R.string.member),
 33		OUTCAST("outcast", 0, R.string.outcast),
 34		NONE("none", 1, R.string.no_affiliation);
 35
 36		Affiliation(String string, int rank, int resId) {
 37			this.string = string;
 38			this.resId = resId;
 39			this.rank = rank;
 40		}
 41
 42		private String string;
 43		private int resId;
 44		private int rank;
 45
 46		public int getResId() {
 47			return resId;
 48		}
 49
 50		@Override
 51		public String toString() {
 52			return this.string;
 53		}
 54
 55		public boolean outranks(Affiliation affiliation) {
 56			return rank > affiliation.rank;
 57		}
 58
 59		public boolean ranks(Affiliation affiliation) {
 60			return rank >= affiliation.rank;
 61		}
 62	}
 63
 64	public enum Role {
 65		MODERATOR("moderator", R.string.moderator,3),
 66		VISITOR("visitor", R.string.visitor,1),
 67		PARTICIPANT("participant", R.string.participant,2),
 68		NONE("none", R.string.no_role,0);
 69
 70		Role(String string, int resId, int rank) {
 71			this.string = string;
 72			this.resId = resId;
 73			this.rank = rank;
 74		}
 75
 76		private String string;
 77		private int resId;
 78		private int rank;
 79
 80		public int getResId() {
 81			return resId;
 82		}
 83
 84		@Override
 85		public String toString() {
 86			return this.string;
 87		}
 88
 89		public boolean ranks(Role role) {
 90			return rank >= role.rank;
 91		}
 92	}
 93
 94	public enum Error {
 95		NO_RESPONSE,
 96		NONE,
 97		NICK_IN_USE,
 98		PASSWORD_REQUIRED,
 99		BANNED,
100		MEMBERS_ONLY,
101		KICKED,
102		SHUTDOWN,
103		UNKNOWN
104	}
105
106	public static final String STATUS_CODE_ROOM_CONFIG_CHANGED = "104";
107	public static final String STATUS_CODE_SELF_PRESENCE = "110";
108	public static final String STATUS_CODE_BANNED = "301";
109	public static final String STATUS_CODE_CHANGED_NICK = "303";
110	public static final String STATUS_CODE_KICKED = "307";
111	public static final String STATUS_CODE_AFFILIATION_CHANGE = "321";
112	public static final String STATUS_CODE_LOST_MEMBERSHIP = "322";
113	public static final String STATUS_CODE_SHUTDOWN = "332";
114
115	private interface OnEventListener {
116		void onSuccess();
117
118		void onFailure();
119	}
120
121	public interface OnRenameListener extends OnEventListener {
122
123	}
124
125	public static class User {
126		private Role role = Role.NONE;
127		private Affiliation affiliation = Affiliation.NONE;
128		private Jid jid;
129		private Jid fullJid;
130		private long pgpKeyId = 0;
131		private Avatar avatar;
132		private MucOptions options;
133
134		public User(MucOptions options, Jid from) {
135			this.options = options;
136			this.fullJid = from;
137		}
138
139		public String getName() {
140			return this.fullJid.getResourcepart();
141		}
142
143		public void setJid(Jid jid) {
144			this.jid = jid;
145		}
146
147		public Jid getJid() {
148			return this.jid;
149		}
150
151		public Role getRole() {
152			return this.role;
153		}
154
155		public void setRole(String role) {
156			role = role.toLowerCase();
157			switch (role) {
158				case "moderator":
159					this.role = Role.MODERATOR;
160					break;
161				case "participant":
162					this.role = Role.PARTICIPANT;
163					break;
164				case "visitor":
165					this.role = Role.VISITOR;
166					break;
167				default:
168					this.role = Role.NONE;
169					break;
170			}
171		}
172
173		@Override
174		public boolean equals(Object other) {
175			if (this == other) {
176				return true;
177			} else if (!(other instanceof User)) {
178				return false;
179			} else {
180				User o = (User) other;
181				return getName() != null && getName().equals(o.getName())
182						&& jid != null && jid.equals(o.jid)
183						&& affiliation == o.affiliation
184						&& role == o.role;
185			}
186		}
187
188		public Affiliation getAffiliation() {
189			return this.affiliation;
190		}
191
192		public void setAffiliation(String affiliation) {
193			affiliation = affiliation.toLowerCase();
194			switch (affiliation) {
195				case "admin":
196					this.affiliation = Affiliation.ADMIN;
197					break;
198				case "owner":
199					this.affiliation = Affiliation.OWNER;
200					break;
201				case "member":
202					this.affiliation = Affiliation.MEMBER;
203					break;
204				case "outcast":
205					this.affiliation = Affiliation.OUTCAST;
206					break;
207				default:
208					this.affiliation = Affiliation.NONE;
209			}
210		}
211
212		public void setPgpKeyId(long id) {
213			this.pgpKeyId = id;
214		}
215
216		public long getPgpKeyId() {
217			return this.pgpKeyId;
218		}
219
220		public Contact getContact() {
221			return getAccount().getRoster().getContactFromRoster(getJid());
222		}
223
224		public boolean setAvatar(Avatar avatar) {
225			if (this.avatar != null && this.avatar.equals(avatar)) {
226				return false;
227			} else {
228				this.avatar = avatar;
229				return true;
230			}
231		}
232
233		public String getAvatar() {
234			return avatar == null ? null : avatar.getFilename();
235		}
236
237		public Account getAccount() {
238			return options.getAccount();
239		}
240
241		public Jid getFullJid() {
242			return fullJid;
243		}
244	}
245
246	private Account account;
247	private final Map<String, User> users = Collections.synchronizedMap(new LinkedHashMap<String, User>());
248	private List<String> features = new ArrayList<>();
249	private Data form = new Data();
250	private Conversation conversation;
251	private boolean isOnline = false;
252	private Error error = Error.NONE;
253	public OnRenameListener onRenameListener = null;
254	private User self;
255	private String subject = null;
256	private String password = null;
257	public boolean mNickChangingInProgress = false;
258
259	public MucOptions(Conversation conversation) {
260		this.account = conversation.getAccount();
261		this.conversation = conversation;
262		this.self = new User(this,createJoinJid(getProposedNick()));
263	}
264
265	public void updateFeatures(ArrayList<String> features) {
266		this.features.clear();
267		this.features.addAll(features);
268	}
269
270	public void updateFormData(Data form) {
271		this.form = form;
272	}
273
274	public boolean hasFeature(String feature) {
275		return this.features.contains(feature);
276	}
277
278	public boolean canInvite() {
279		Field field = this.form.getFieldByName("muc#roomconfig_allowinvites");
280		return !membersOnly() || self.getRole().ranks(Role.MODERATOR) || (field != null && "1".equals(field.getValue()));
281	}
282
283	public boolean canChangeSubject() {
284		Field field = this.form.getFieldByName("muc#roomconfig_changesubject");
285		return self.getRole().ranks(Role.MODERATOR) || (field != null && "1".equals(field.getValue()));
286	}
287
288	public boolean participating() {
289		return !online()
290				|| self.getRole().ranks(Role.PARTICIPANT)
291				|| hasFeature("muc_unmoderated");
292	}
293
294	public boolean membersOnly() {
295		return hasFeature("muc_membersonly");
296	}
297
298	public boolean mamSupport() {
299		// Update with "urn:xmpp:mam:1" once we support it
300		return hasFeature("urn:xmpp:mam:0");
301	}
302
303	public boolean nonanonymous() {
304		return hasFeature("muc_nonanonymous");
305	}
306
307	public boolean persistent() {
308		return hasFeature("muc_persistent");
309	}
310
311	public boolean moderated() {
312		return hasFeature("muc_moderated");
313	}
314
315	public User deleteUser(String name) {
316		return this.users.remove(name);
317	}
318
319	public void addUser(User user) {
320		this.users.put(user.getName(), user);
321	}
322
323	public User findUser(String name) {
324		return this.users.get(name);
325	}
326
327	public boolean isUserInRoom(String name) {
328		return findUser(name) != null;
329	}
330
331	public void setError(Error error) {
332		this.isOnline = isOnline && error == Error.NONE;
333		this.error = error;
334	}
335
336	public void setOnline() {
337		this.isOnline = true;
338	}
339
340	public ArrayList<User> getUsers() {
341		return new ArrayList<>(users.values());
342	}
343
344	public List<User> getUsers(int max) {
345		ArrayList<User> users = new ArrayList<>();
346		int i = 1;
347		for(User user : this.users.values()) {
348			users.add(user);
349			if (i >= max) {
350				break;
351			} else {
352				++i;
353			}
354		}
355		return users;
356	}
357
358	public int getUserCount() {
359		return this.users.size();
360	}
361
362	public String getProposedNick() {
363		if (conversation.getBookmark() != null
364				&& conversation.getBookmark().getNick() != null
365				&& !conversation.getBookmark().getNick().isEmpty()) {
366			return conversation.getBookmark().getNick();
367		} else if (!conversation.getJid().isBareJid()) {
368			return conversation.getJid().getResourcepart();
369		} else {
370			return account.getUsername();
371		}
372	}
373
374	public String getActualNick() {
375		if (this.self.getName() != null) {
376			return this.self.getName();
377		} else {
378			return this.getProposedNick();
379		}
380	}
381
382	public boolean online() {
383		return this.isOnline;
384	}
385
386	public Error getError() {
387		return this.error;
388	}
389
390	public void setOnRenameListener(OnRenameListener listener) {
391		this.onRenameListener = listener;
392	}
393
394	public void setOffline() {
395		this.users.clear();
396		this.error = Error.NO_RESPONSE;
397		this.isOnline = false;
398	}
399
400	public User getSelf() {
401		return self;
402	}
403
404	public void setSubject(String content) {
405		this.subject = content;
406	}
407
408	public String getSubject() {
409		return this.subject;
410	}
411
412	public String createNameFromParticipants() {
413		if (users.size() >= 2) {
414			List<String> names = new ArrayList<>();
415			for (User user : getUsers(5)) {
416				Contact contact = user.getContact();
417				if (contact != null && !contact.getDisplayName().isEmpty()) {
418					names.add(contact.getDisplayName().split("\\s+")[0]);
419				} else {
420					names.add(user.getName());
421				}
422			}
423			StringBuilder builder = new StringBuilder();
424			for (int i = 0; i < names.size(); ++i) {
425				builder.append(names.get(i));
426				if (i != names.size() - 1) {
427					builder.append(", ");
428				}
429			}
430			return builder.toString();
431		} else {
432			return null;
433		}
434	}
435
436	public long[] getPgpKeyIds() {
437		List<Long> ids = new ArrayList<>();
438		for (User user : this.users.values()) {
439			if (user.getPgpKeyId() != 0) {
440				ids.add(user.getPgpKeyId());
441			}
442		}
443		ids.add(account.getPgpId());
444		long[] primitiveLongArray = new long[ids.size()];
445		for (int i = 0; i < ids.size(); ++i) {
446			primitiveLongArray[i] = ids.get(i);
447		}
448		return primitiveLongArray;
449	}
450
451	public boolean pgpKeysInUse() {
452		for (User user : this.users.values()) {
453			if (user.getPgpKeyId() != 0) {
454				return true;
455			}
456		}
457		return false;
458	}
459
460	public boolean everybodyHasKeys() {
461		for (User user : this.users.values()) {
462			if (user.getPgpKeyId() == 0) {
463				return false;
464			}
465		}
466		return true;
467	}
468
469	public Jid createJoinJid(String nick) {
470		try {
471			return Jid.fromString(this.conversation.getJid().toBareJid().toString() + "/" + nick);
472		} catch (final InvalidJidException e) {
473			return null;
474		}
475	}
476
477	public Jid getTrueCounterpart(String name) {
478		User user = findUser(name);
479		return user == null ? null : user.getJid();
480	}
481
482	public String getPassword() {
483		this.password = conversation.getAttribute(Conversation.ATTRIBUTE_MUC_PASSWORD);
484		if (this.password == null && conversation.getBookmark() != null
485				&& conversation.getBookmark().getPassword() != null) {
486			return conversation.getBookmark().getPassword();
487		} else {
488			return this.password;
489		}
490	}
491
492	public void setPassword(String password) {
493		if (conversation.getBookmark() != null) {
494			conversation.getBookmark().setPassword(password);
495		} else {
496			this.password = password;
497		}
498		conversation.setAttribute(Conversation.ATTRIBUTE_MUC_PASSWORD, password);
499	}
500
501	public Conversation getConversation() {
502		return this.conversation;
503	}
504}