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