1package eu.siacs.conversations.entities;
2
3import android.content.ContentValues;
4import android.database.Cursor;
5import android.net.Uri;
6import android.os.SystemClock;
7import android.util.Log;
8
9import com.google.common.base.Strings;
10import com.google.common.collect.ImmutableList;
11
12import org.json.JSONException;
13import org.json.JSONObject;
14
15import java.util.ArrayList;
16import java.util.Collection;
17import java.util.HashMap;
18import java.util.HashSet;
19import java.util.List;
20import java.util.Map;
21import java.util.Set;
22import java.util.concurrent.CopyOnWriteArraySet;
23
24import eu.siacs.conversations.Config;
25import eu.siacs.conversations.R;
26import eu.siacs.conversations.crypto.PgpDecryptionService;
27import eu.siacs.conversations.crypto.axolotl.AxolotlService;
28import eu.siacs.conversations.crypto.axolotl.XmppAxolotlSession;
29import eu.siacs.conversations.crypto.sasl.ChannelBinding;
30import eu.siacs.conversations.crypto.sasl.ChannelBindingMechanism;
31import eu.siacs.conversations.crypto.sasl.HashedToken;
32import eu.siacs.conversations.crypto.sasl.HashedTokenSha256;
33import eu.siacs.conversations.crypto.sasl.HashedTokenSha512;
34import eu.siacs.conversations.crypto.sasl.SaslMechanism;
35import eu.siacs.conversations.crypto.sasl.ScramPlusMechanism;
36import eu.siacs.conversations.services.AvatarService;
37import eu.siacs.conversations.services.XmppConnectionService;
38import eu.siacs.conversations.utils.UIHelper;
39import eu.siacs.conversations.utils.XmppUri;
40import eu.siacs.conversations.xmpp.Jid;
41import eu.siacs.conversations.xmpp.XmppConnection;
42import eu.siacs.conversations.xmpp.jingle.RtpCapability;
43
44public class Account extends AbstractEntity implements AvatarService.Avatarable {
45
46 public static final String TABLENAME = "accounts";
47
48 public static final String USERNAME = "username";
49 public static final String SERVER = "server";
50 public static final String PASSWORD = "password";
51 public static final String OPTIONS = "options";
52 public static final String ROSTERVERSION = "rosterversion";
53 public static final String KEYS = "keys";
54 public static final String AVATAR = "avatar";
55 public static final String DISPLAY_NAME = "display_name";
56 public static final String HOSTNAME = "hostname";
57 public static final String PORT = "port";
58 public static final String STATUS = "status";
59 public static final String STATUS_MESSAGE = "status_message";
60 public static final String RESOURCE = "resource";
61 public static final String PINNED_MECHANISM = "pinned_mechanism";
62 public static final String PINNED_CHANNEL_BINDING = "pinned_channel_binding";
63 public static final String FAST_MECHANISM = "fast_mechanism";
64 public static final String FAST_TOKEN = "fast_token";
65
66 public static final int OPTION_DISABLED = 1;
67 public static final int OPTION_REGISTER = 2;
68 public static final int OPTION_MAGIC_CREATE = 4;
69 public static final int OPTION_REQUIRES_ACCESS_MODE_CHANGE = 5;
70 public static final int OPTION_LOGGED_IN_SUCCESSFULLY = 6;
71 public static final int OPTION_HTTP_UPLOAD_AVAILABLE = 7;
72 public static final int OPTION_UNVERIFIED = 8;
73 public static final int OPTION_FIXED_USERNAME = 9;
74 public static final int OPTION_QUICKSTART_AVAILABLE = 10;
75
76 private static final String KEY_PGP_SIGNATURE = "pgp_signature";
77 private static final String KEY_PGP_ID = "pgp_id";
78 private static final String KEY_PINNED_MECHANISM = "pinned_mechanism";
79 public static final String KEY_PRE_AUTH_REGISTRATION_TOKEN = "pre_auth_registration";
80
81 protected final JSONObject keys;
82 private final Roster roster = new Roster(this);
83 private final Collection<Jid> blocklist = new CopyOnWriteArraySet<>();
84 public final Set<Conversation> pendingConferenceJoins = new HashSet<>();
85 public final Set<Conversation> pendingConferenceLeaves = new HashSet<>();
86 public final Set<Conversation> inProgressConferenceJoins = new HashSet<>();
87 public final Set<Conversation> inProgressConferencePings = new HashSet<>();
88 protected Jid jid;
89 protected String password;
90 protected int options = 0;
91 protected State status = State.OFFLINE;
92 private State lastErrorStatus = State.OFFLINE;
93 protected String resource;
94 protected String avatar;
95 protected String hostname = null;
96 protected int port = 5222;
97 protected boolean online = false;
98 private String rosterVersion;
99 private String displayName = null;
100 private AxolotlService axolotlService = null;
101 private PgpDecryptionService pgpDecryptionService = null;
102 private XmppConnection xmppConnection = null;
103 private long mEndGracePeriod = 0L;
104 private final Map<Jid, Bookmark> bookmarks = new HashMap<>();
105 private boolean bookmarksLoaded = false;
106 private Presence.Status presenceStatus;
107 private String presenceStatusMessage;
108 private String pinnedMechanism;
109 private String pinnedChannelBinding;
110 private String fastMechanism;
111 private String fastToken;
112
113 public Account(final Jid jid, final String password) {
114 this(
115 java.util.UUID.randomUUID().toString(),
116 jid,
117 password,
118 0,
119 null,
120 "",
121 null,
122 null,
123 null,
124 5222,
125 Presence.Status.ONLINE,
126 null,
127 null,
128 null,
129 null,
130 null);
131 }
132
133 private Account(
134 final String uuid,
135 final Jid jid,
136 final String password,
137 final int options,
138 final String rosterVersion,
139 final String keys,
140 final String avatar,
141 String displayName,
142 String hostname,
143 int port,
144 final Presence.Status status,
145 String statusMessage,
146 final String pinnedMechanism,
147 final String pinnedChannelBinding,
148 final String fastMechanism,
149 final String fastToken) {
150 this.uuid = uuid;
151 this.jid = jid;
152 this.password = password;
153 this.options = options;
154 this.rosterVersion = rosterVersion;
155 JSONObject tmp;
156 try {
157 tmp = new JSONObject(keys);
158 } catch (JSONException e) {
159 tmp = new JSONObject();
160 }
161 this.keys = tmp;
162 this.avatar = avatar;
163 this.displayName = displayName;
164 this.hostname = hostname;
165 this.port = port;
166 this.presenceStatus = status;
167 this.presenceStatusMessage = statusMessage;
168 this.pinnedMechanism = pinnedMechanism;
169 this.pinnedChannelBinding = pinnedChannelBinding;
170 this.fastMechanism = fastMechanism;
171 this.fastToken = fastToken;
172 }
173
174 public static Account fromCursor(final Cursor cursor) {
175 final Jid jid;
176 try {
177 final String resource = cursor.getString(cursor.getColumnIndexOrThrow(RESOURCE));
178 jid =
179 Jid.of(
180 cursor.getString(cursor.getColumnIndexOrThrow(USERNAME)),
181 cursor.getString(cursor.getColumnIndexOrThrow(SERVER)),
182 resource == null || resource.trim().isEmpty() ? null : resource);
183 } catch (final IllegalArgumentException e) {
184 Log.d(
185 Config.LOGTAG,
186 cursor.getString(cursor.getColumnIndexOrThrow(USERNAME))
187 + "@"
188 + cursor.getString(cursor.getColumnIndexOrThrow(SERVER)));
189 throw new AssertionError(e);
190 }
191 return new Account(
192 cursor.getString(cursor.getColumnIndexOrThrow(UUID)),
193 jid,
194 cursor.getString(cursor.getColumnIndexOrThrow(PASSWORD)),
195 cursor.getInt(cursor.getColumnIndexOrThrow(OPTIONS)),
196 cursor.getString(cursor.getColumnIndexOrThrow(ROSTERVERSION)),
197 cursor.getString(cursor.getColumnIndexOrThrow(KEYS)),
198 cursor.getString(cursor.getColumnIndexOrThrow(AVATAR)),
199 cursor.getString(cursor.getColumnIndexOrThrow(DISPLAY_NAME)),
200 cursor.getString(cursor.getColumnIndexOrThrow(HOSTNAME)),
201 cursor.getInt(cursor.getColumnIndexOrThrow(PORT)),
202 Presence.Status.fromShowString(
203 cursor.getString(cursor.getColumnIndexOrThrow(STATUS))),
204 cursor.getString(cursor.getColumnIndexOrThrow(STATUS_MESSAGE)),
205 cursor.getString(cursor.getColumnIndexOrThrow(PINNED_MECHANISM)),
206 cursor.getString(cursor.getColumnIndexOrThrow(PINNED_CHANNEL_BINDING)),
207 cursor.getString(cursor.getColumnIndexOrThrow(FAST_MECHANISM)),
208 cursor.getString(cursor.getColumnIndexOrThrow(FAST_TOKEN)));
209 }
210
211 public boolean httpUploadAvailable(long size) {
212 return xmppConnection != null && xmppConnection.getFeatures().httpUpload(size);
213 }
214
215 public boolean httpUploadAvailable() {
216 return isOptionSet(OPTION_HTTP_UPLOAD_AVAILABLE) || httpUploadAvailable(0);
217 }
218
219 public String getDisplayName() {
220 return displayName;
221 }
222
223 public void setDisplayName(String displayName) {
224 this.displayName = displayName;
225 }
226
227 public Contact getSelfContact() {
228 return getRoster().getContact(jid);
229 }
230
231 public boolean hasPendingPgpIntent(Conversation conversation) {
232 return pgpDecryptionService != null && pgpDecryptionService.hasPendingIntent(conversation);
233 }
234
235 public boolean isPgpDecryptionServiceConnected() {
236 return pgpDecryptionService != null && pgpDecryptionService.isConnected();
237 }
238
239 public boolean setShowErrorNotification(boolean newValue) {
240 boolean oldValue = showErrorNotification();
241 setKey("show_error", Boolean.toString(newValue));
242 return newValue != oldValue;
243 }
244
245 public boolean showErrorNotification() {
246 String key = getKey("show_error");
247 return key == null || Boolean.parseBoolean(key);
248 }
249
250 public boolean isEnabled() {
251 return !isOptionSet(Account.OPTION_DISABLED);
252 }
253
254 public boolean isOptionSet(final int option) {
255 return ((options & (1 << option)) != 0);
256 }
257
258 public boolean setOption(final int option, final boolean value) {
259 final int before = this.options;
260 if (value) {
261 this.options |= 1 << option;
262 } else {
263 this.options &= ~(1 << option);
264 }
265 return before != this.options;
266 }
267
268 public String getUsername() {
269 return jid.getEscapedLocal();
270 }
271
272 public boolean setJid(final Jid next) {
273 final Jid previousFull = this.jid;
274 final Jid prev = this.jid != null ? this.jid.asBareJid() : null;
275 final boolean changed = prev == null || (next != null && !prev.equals(next.asBareJid()));
276 if (changed) {
277 final AxolotlService oldAxolotlService = this.axolotlService;
278 if (oldAxolotlService != null) {
279 oldAxolotlService.destroy();
280 this.jid = next;
281 this.axolotlService = oldAxolotlService.makeNew();
282 }
283 }
284 this.jid = next;
285 return next != null && !next.equals(previousFull);
286 }
287
288 public Jid getDomain() {
289 return jid.getDomain();
290 }
291
292 public String getServer() {
293 return jid.getDomain().toEscapedString();
294 }
295
296 public String getPassword() {
297 return password;
298 }
299
300 public void setPassword(final String password) {
301 this.password = password;
302 }
303
304 public String getHostname() {
305 return Strings.nullToEmpty(this.hostname);
306 }
307
308 public void setHostname(String hostname) {
309 this.hostname = hostname;
310 }
311
312 public boolean isOnion() {
313 final String server = getServer();
314 return server != null && server.endsWith(".onion");
315 }
316
317 public int getPort() {
318 return this.port;
319 }
320
321 public void setPort(int port) {
322 this.port = port;
323 }
324
325 public State getStatus() {
326 if (isOptionSet(OPTION_DISABLED)) {
327 return State.DISABLED;
328 } else {
329 return this.status;
330 }
331 }
332
333 public State getLastErrorStatus() {
334 return this.lastErrorStatus;
335 }
336
337 public void setStatus(final State status) {
338 this.status = status;
339 if (status.isError || status == State.ONLINE) {
340 this.lastErrorStatus = status;
341 }
342 }
343
344 public void setPinnedMechanism(final SaslMechanism mechanism) {
345 this.pinnedMechanism = mechanism.getMechanism();
346 if (mechanism instanceof ChannelBindingMechanism) {
347 this.pinnedChannelBinding =
348 ((ChannelBindingMechanism) mechanism).getChannelBinding().toString();
349 } else {
350 this.pinnedChannelBinding = null;
351 }
352 }
353
354 public void setFastToken(final HashedToken.Mechanism mechanism, final String token) {
355 this.fastMechanism = mechanism.name();
356 this.fastToken = token;
357 }
358
359 public void resetFastToken() {
360 this.fastMechanism = null;
361 this.fastToken = null;
362 }
363
364 public void resetPinnedMechanism() {
365 this.pinnedMechanism = null;
366 this.pinnedChannelBinding = null;
367 setKey(Account.KEY_PINNED_MECHANISM, String.valueOf(-1));
368 }
369
370 public int getPinnedMechanismPriority() {
371 final int fallback = getKeyAsInt(KEY_PINNED_MECHANISM, -1);
372 if (Strings.isNullOrEmpty(this.pinnedMechanism)) {
373 return fallback;
374 }
375 final SaslMechanism saslMechanism = getPinnedMechanism();
376 if (saslMechanism == null) {
377 return fallback;
378 } else {
379 return saslMechanism.getPriority();
380 }
381 }
382
383 private SaslMechanism getPinnedMechanism() {
384 final String mechanism = Strings.nullToEmpty(this.pinnedMechanism);
385 final ChannelBinding channelBinding = ChannelBinding.get(this.pinnedChannelBinding);
386 return new SaslMechanism.Factory(this).of(mechanism, channelBinding);
387 }
388
389 public HashedToken getFastMechanism() {
390 final HashedToken.Mechanism fastMechanism = HashedToken.Mechanism.ofOrNull(this.fastMechanism);
391 final String token = this.fastToken;
392 if (fastMechanism == null || Strings.isNullOrEmpty(token)) {
393 return null;
394 }
395 if (fastMechanism.hashFunction.equals("SHA-256")) {
396 return new HashedTokenSha256(this, fastMechanism.channelBinding);
397 } else if (fastMechanism.hashFunction.equals("SHA-512")) {
398 return new HashedTokenSha512(this, fastMechanism.channelBinding);
399 } else {
400 return null;
401 }
402 }
403
404 public SaslMechanism getQuickStartMechanism() {
405 final HashedToken hashedTokenMechanism = getFastMechanism();
406 if (hashedTokenMechanism != null) {
407 return hashedTokenMechanism;
408 }
409 return getPinnedMechanism();
410 }
411
412 public String getFastToken() {
413 return this.fastToken;
414 }
415
416 public State getTrueStatus() {
417 return this.status;
418 }
419
420 public boolean errorStatus() {
421 return getStatus().isError();
422 }
423
424 public boolean hasErrorStatus() {
425 return getXmppConnection() != null
426 && (getStatus().isError() || getStatus() == State.CONNECTING)
427 && getXmppConnection().getAttempt() >= 3;
428 }
429
430 public Presence.Status getPresenceStatus() {
431 return this.presenceStatus;
432 }
433
434 public void setPresenceStatus(Presence.Status status) {
435 this.presenceStatus = status;
436 }
437
438 public String getPresenceStatusMessage() {
439 return this.presenceStatusMessage;
440 }
441
442 public void setPresenceStatusMessage(String message) {
443 this.presenceStatusMessage = message;
444 }
445
446 public String getResource() {
447 return jid.getResource();
448 }
449
450 public void setResource(final String resource) {
451 this.jid = this.jid.withResource(resource);
452 }
453
454 public Jid getJid() {
455 return jid;
456 }
457
458 public JSONObject getKeys() {
459 return keys;
460 }
461
462 public String getKey(final String name) {
463 synchronized (this.keys) {
464 return this.keys.optString(name, null);
465 }
466 }
467
468 public int getKeyAsInt(final String name, int defaultValue) {
469 String key = getKey(name);
470 try {
471 return key == null ? defaultValue : Integer.parseInt(key);
472 } catch (NumberFormatException e) {
473 return defaultValue;
474 }
475 }
476
477 public boolean setKey(final String keyName, final String keyValue) {
478 synchronized (this.keys) {
479 try {
480 this.keys.put(keyName, keyValue);
481 return true;
482 } catch (final JSONException e) {
483 return false;
484 }
485 }
486 }
487
488 public void setPrivateKeyAlias(final String alias) {
489 setKey("private_key_alias", alias);
490 }
491
492 public String getPrivateKeyAlias() {
493 return getKey("private_key_alias");
494 }
495
496 @Override
497 public ContentValues getContentValues() {
498 final ContentValues values = new ContentValues();
499 values.put(UUID, uuid);
500 values.put(USERNAME, jid.getLocal());
501 values.put(SERVER, jid.getDomain().toEscapedString());
502 values.put(PASSWORD, password);
503 values.put(OPTIONS, options);
504 synchronized (this.keys) {
505 values.put(KEYS, this.keys.toString());
506 }
507 values.put(ROSTERVERSION, rosterVersion);
508 values.put(AVATAR, avatar);
509 values.put(DISPLAY_NAME, displayName);
510 values.put(HOSTNAME, hostname);
511 values.put(PORT, port);
512 values.put(STATUS, presenceStatus.toShowString());
513 values.put(STATUS_MESSAGE, presenceStatusMessage);
514 values.put(RESOURCE, jid.getResource());
515 values.put(PINNED_MECHANISM, pinnedMechanism);
516 values.put(PINNED_CHANNEL_BINDING, pinnedChannelBinding);
517 values.put(FAST_MECHANISM, this.fastMechanism);
518 values.put(FAST_TOKEN, this.fastToken);
519 return values;
520 }
521
522 public AxolotlService getAxolotlService() {
523 return axolotlService;
524 }
525
526 public void initAccountServices(final XmppConnectionService context) {
527 this.axolotlService = new AxolotlService(this, context);
528 this.pgpDecryptionService = new PgpDecryptionService(context);
529 if (xmppConnection != null) {
530 xmppConnection.addOnAdvancedStreamFeaturesAvailableListener(axolotlService);
531 }
532 }
533
534 public PgpDecryptionService getPgpDecryptionService() {
535 return this.pgpDecryptionService;
536 }
537
538 public XmppConnection getXmppConnection() {
539 return this.xmppConnection;
540 }
541
542 public void setXmppConnection(final XmppConnection connection) {
543 this.xmppConnection = connection;
544 }
545
546 public String getRosterVersion() {
547 if (this.rosterVersion == null) {
548 return "";
549 } else {
550 return this.rosterVersion;
551 }
552 }
553
554 public void setRosterVersion(final String version) {
555 this.rosterVersion = version;
556 }
557
558 public int countPresences() {
559 return this.getSelfContact().getPresences().size();
560 }
561
562 public int activeDevicesWithRtpCapability() {
563 int i = 0;
564 for (Presence presence : getSelfContact().getPresences().getPresences()) {
565 if (RtpCapability.check(presence) != RtpCapability.Capability.NONE) {
566 i++;
567 }
568 }
569 return i;
570 }
571
572 public String getPgpSignature() {
573 return getKey(KEY_PGP_SIGNATURE);
574 }
575
576 public boolean setPgpSignature(String signature) {
577 return setKey(KEY_PGP_SIGNATURE, signature);
578 }
579
580 public boolean unsetPgpSignature() {
581 synchronized (this.keys) {
582 return keys.remove(KEY_PGP_SIGNATURE) != null;
583 }
584 }
585
586 public long getPgpId() {
587 synchronized (this.keys) {
588 if (keys.has(KEY_PGP_ID)) {
589 try {
590 return keys.getLong(KEY_PGP_ID);
591 } catch (JSONException e) {
592 return 0;
593 }
594 } else {
595 return 0;
596 }
597 }
598 }
599
600 public boolean setPgpSignId(long pgpID) {
601 synchronized (this.keys) {
602 try {
603 if (pgpID == 0) {
604 keys.remove(KEY_PGP_ID);
605 } else {
606 keys.put(KEY_PGP_ID, pgpID);
607 }
608 } catch (JSONException e) {
609 return false;
610 }
611 return true;
612 }
613 }
614
615 public Roster getRoster() {
616 return this.roster;
617 }
618
619 public Collection<Bookmark> getBookmarks() {
620 synchronized (this.bookmarks) {
621 return ImmutableList.copyOf(this.bookmarks.values());
622 }
623 }
624
625 public boolean areBookmarksLoaded() { return bookmarksLoaded; }
626
627 public void setBookmarks(final Map<Jid, Bookmark> bookmarks) {
628 synchronized (this.bookmarks) {
629 this.bookmarks.clear();
630 this.bookmarks.putAll(bookmarks);
631 this.bookmarksLoaded = true;
632 }
633 }
634
635 public void putBookmark(final Bookmark bookmark) {
636 synchronized (this.bookmarks) {
637 this.bookmarks.put(bookmark.getJid(), bookmark);
638 }
639 }
640
641 public void removeBookmark(Bookmark bookmark) {
642 synchronized (this.bookmarks) {
643 this.bookmarks.remove(bookmark.getJid());
644 }
645 }
646
647 public void removeBookmark(Jid jid) {
648 synchronized (this.bookmarks) {
649 this.bookmarks.remove(jid);
650 }
651 }
652
653 public Set<Jid> getBookmarkedJids() {
654 synchronized (this.bookmarks) {
655 return new HashSet<>(this.bookmarks.keySet());
656 }
657 }
658
659 public Bookmark getBookmark(final Jid jid) {
660 synchronized (this.bookmarks) {
661 return this.bookmarks.get(jid.asBareJid());
662 }
663 }
664
665 public boolean setAvatar(final String filename) {
666 if (this.avatar != null && this.avatar.equals(filename)) {
667 return false;
668 } else {
669 this.avatar = filename;
670 return true;
671 }
672 }
673
674 public String getAvatar() {
675 return this.avatar;
676 }
677
678 public void activateGracePeriod(final long duration) {
679 if (duration > 0) {
680 this.mEndGracePeriod = SystemClock.elapsedRealtime() + duration;
681 }
682 }
683
684 public void deactivateGracePeriod() {
685 this.mEndGracePeriod = 0L;
686 }
687
688 public boolean inGracePeriod() {
689 return SystemClock.elapsedRealtime() < this.mEndGracePeriod;
690 }
691
692 public String getShareableUri() {
693 List<XmppUri.Fingerprint> fingerprints = this.getFingerprints();
694 String uri = "xmpp:" + Uri.encode(getJid().asBareJid().toEscapedString(), "@/+");
695 if (fingerprints.size() > 0) {
696 return XmppUri.getFingerprintUri(uri, fingerprints, ';');
697 } else {
698 return uri;
699 }
700 }
701
702 public String getShareableLink() {
703 List<XmppUri.Fingerprint> fingerprints = this.getFingerprints();
704 String uri =
705 "https://conversations.im/i/"
706 + XmppUri.lameUrlEncode(this.getJid().asBareJid().toEscapedString());
707 if (fingerprints.size() > 0) {
708 return XmppUri.getFingerprintUri(uri, fingerprints, '&');
709 } else {
710 return uri;
711 }
712 }
713
714 private List<XmppUri.Fingerprint> getFingerprints() {
715 ArrayList<XmppUri.Fingerprint> fingerprints = new ArrayList<>();
716 if (axolotlService == null) {
717 return fingerprints;
718 }
719 fingerprints.add(
720 new XmppUri.Fingerprint(
721 XmppUri.FingerprintType.OMEMO,
722 axolotlService.getOwnFingerprint().substring(2),
723 axolotlService.getOwnDeviceId()));
724 for (XmppAxolotlSession session : axolotlService.findOwnSessions()) {
725 if (session.getTrust().isVerified() && session.getTrust().isActive()) {
726 fingerprints.add(
727 new XmppUri.Fingerprint(
728 XmppUri.FingerprintType.OMEMO,
729 session.getFingerprint().substring(2).replaceAll("\\s", ""),
730 session.getRemoteAddress().getDeviceId()));
731 }
732 }
733 return fingerprints;
734 }
735
736 public boolean isBlocked(final ListItem contact) {
737 final Jid jid = contact.getJid();
738 return jid != null
739 && (blocklist.contains(jid.asBareJid()) || blocklist.contains(jid.getDomain()));
740 }
741
742 public boolean isBlocked(final Jid jid) {
743 return jid != null && blocklist.contains(jid.asBareJid());
744 }
745
746 public Collection<Jid> getBlocklist() {
747 return this.blocklist;
748 }
749
750 public void clearBlocklist() {
751 getBlocklist().clear();
752 }
753
754 public boolean isOnlineAndConnected() {
755 return this.getStatus() == State.ONLINE && this.getXmppConnection() != null;
756 }
757
758 @Override
759 public int getAvatarBackgroundColor() {
760 return UIHelper.getColorForName(jid.asBareJid().toString());
761 }
762
763 @Override
764 public String getAvatarName() {
765 throw new IllegalStateException("This method should not be called");
766 }
767
768 public enum State {
769 DISABLED(false, false),
770 OFFLINE(false),
771 CONNECTING(false),
772 ONLINE(false),
773 NO_INTERNET(false),
774 UNAUTHORIZED,
775 TEMPORARY_AUTH_FAILURE,
776 SERVER_NOT_FOUND,
777 REGISTRATION_SUCCESSFUL(false),
778 REGISTRATION_FAILED(true, false),
779 REGISTRATION_WEB(true, false),
780 REGISTRATION_CONFLICT(true, false),
781 REGISTRATION_NOT_SUPPORTED(true, false),
782 REGISTRATION_PLEASE_WAIT(true, false),
783 REGISTRATION_INVALID_TOKEN(true, false),
784 REGISTRATION_PASSWORD_TOO_WEAK(true, false),
785 TLS_ERROR,
786 TLS_ERROR_DOMAIN,
787 INCOMPATIBLE_SERVER,
788 INCOMPATIBLE_CLIENT,
789 TOR_NOT_AVAILABLE,
790 DOWNGRADE_ATTACK,
791 SESSION_FAILURE,
792 BIND_FAILURE,
793 HOST_UNKNOWN,
794 STREAM_ERROR,
795 STREAM_OPENING_ERROR,
796 POLICY_VIOLATION,
797 PAYMENT_REQUIRED,
798 MISSING_INTERNET_PERMISSION(false);
799
800 private final boolean isError;
801 private final boolean attemptReconnect;
802
803 State(final boolean isError) {
804 this(isError, true);
805 }
806
807 State(final boolean isError, final boolean reconnect) {
808 this.isError = isError;
809 this.attemptReconnect = reconnect;
810 }
811
812 State() {
813 this(true, true);
814 }
815
816 public boolean isError() {
817 return this.isError;
818 }
819
820 public boolean isAttemptReconnect() {
821 return this.attemptReconnect;
822 }
823
824 public int getReadableId() {
825 switch (this) {
826 case DISABLED:
827 return R.string.account_status_disabled;
828 case ONLINE:
829 return R.string.account_status_online;
830 case CONNECTING:
831 return R.string.account_status_connecting;
832 case OFFLINE:
833 return R.string.account_status_offline;
834 case UNAUTHORIZED:
835 return R.string.account_status_unauthorized;
836 case SERVER_NOT_FOUND:
837 return R.string.account_status_not_found;
838 case NO_INTERNET:
839 return R.string.account_status_no_internet;
840 case REGISTRATION_FAILED:
841 return R.string.account_status_regis_fail;
842 case REGISTRATION_WEB:
843 return R.string.account_status_regis_web;
844 case REGISTRATION_CONFLICT:
845 return R.string.account_status_regis_conflict;
846 case REGISTRATION_SUCCESSFUL:
847 return R.string.account_status_regis_success;
848 case REGISTRATION_NOT_SUPPORTED:
849 return R.string.account_status_regis_not_sup;
850 case REGISTRATION_INVALID_TOKEN:
851 return R.string.account_status_regis_invalid_token;
852 case TLS_ERROR:
853 return R.string.account_status_tls_error;
854 case TLS_ERROR_DOMAIN:
855 return R.string.account_status_tls_error_domain;
856 case INCOMPATIBLE_SERVER:
857 return R.string.account_status_incompatible_server;
858 case INCOMPATIBLE_CLIENT:
859 return R.string.account_status_incompatible_client;
860 case TOR_NOT_AVAILABLE:
861 return R.string.account_status_tor_unavailable;
862 case BIND_FAILURE:
863 return R.string.account_status_bind_failure;
864 case SESSION_FAILURE:
865 return R.string.session_failure;
866 case DOWNGRADE_ATTACK:
867 return R.string.sasl_downgrade;
868 case HOST_UNKNOWN:
869 return R.string.account_status_host_unknown;
870 case POLICY_VIOLATION:
871 return R.string.account_status_policy_violation;
872 case REGISTRATION_PLEASE_WAIT:
873 return R.string.registration_please_wait;
874 case REGISTRATION_PASSWORD_TOO_WEAK:
875 return R.string.registration_password_too_weak;
876 case STREAM_ERROR:
877 return R.string.account_status_stream_error;
878 case STREAM_OPENING_ERROR:
879 return R.string.account_status_stream_opening_error;
880 case PAYMENT_REQUIRED:
881 return R.string.payment_required;
882 case MISSING_INTERNET_PERMISSION:
883 return R.string.missing_internet_permission;
884 case TEMPORARY_AUTH_FAILURE:
885 return R.string.account_status_temporary_auth_failure;
886 default:
887 return R.string.account_status_unknown;
888 }
889 }
890 }
891}