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