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