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