diff options
Diffstat (limited to 'src/main')
40 files changed, 763 insertions, 699 deletions
diff --git a/src/main/java/eu/siacs/conversations/Config.java b/src/main/java/eu/siacs/conversations/Config.java index 7af29451..d777e5cc 100644 --- a/src/main/java/eu/siacs/conversations/Config.java +++ b/src/main/java/eu/siacs/conversations/Config.java @@ -18,7 +18,6 @@ public final class Config { public static final int MESSAGE_MERGE_WINDOW = 20; - public static final boolean PARSE_EMOTICONS = false; public static final int PROGRESS_UI_UPDATE_INTERVAL = 750; public static final boolean NO_PROXY_LOOKUP = false; //useful to debug ibb diff --git a/src/main/java/eu/siacs/conversations/crypto/sasl/DigestMd5.java b/src/main/java/eu/siacs/conversations/crypto/sasl/DigestMd5.java index 850cacc2..8b16215b 100644 --- a/src/main/java/eu/siacs/conversations/crypto/sasl/DigestMd5.java +++ b/src/main/java/eu/siacs/conversations/crypto/sasl/DigestMd5.java @@ -39,7 +39,7 @@ public class DigestMd5 extends SaslMechanism { final Tokenizer tokenizer = new Tokenizer(Base64.decode(challenge, Base64.DEFAULT)); String nonce = ""; for (final String token : tokenizer) { - final String[] parts = token.split("="); + final String[] parts = token.split("=", 2); if (parts[0].equals("nonce")) { nonce = parts[1].replace("\"", ""); } else if (parts[0].equals("rspauth")) { @@ -79,6 +79,10 @@ public class DigestMd5 extends SaslMechanism { case RESPONSE_SENT: state = State.VALID_SERVER_RESPONSE; break; + case VALID_SERVER_RESPONSE: + if (challenge==null) { + return null; //everything is fine + } default: throw new InvalidStateException(state); } diff --git a/src/main/java/eu/siacs/conversations/crypto/sasl/Tokenizer.java b/src/main/java/eu/siacs/conversations/crypto/sasl/Tokenizer.java index 39be0224..e37e0fa7 100644 --- a/src/main/java/eu/siacs/conversations/crypto/sasl/Tokenizer.java +++ b/src/main/java/eu/siacs/conversations/crypto/sasl/Tokenizer.java @@ -16,6 +16,10 @@ public final class Tokenizer implements Iterator<String>, Iterable<String> { public Tokenizer(final byte[] challenge) { final String challengeString = new String(challenge); parts = new ArrayList<>(Arrays.asList(challengeString.split(","))); + // Trim parts. + for (int i = 0; i < parts.size(); i++) { + parts.set(i, parts.get(i).trim()); + } index = 0; } diff --git a/src/main/java/eu/siacs/conversations/entities/Account.java b/src/main/java/eu/siacs/conversations/entities/Account.java index 1d0a025f..538d0ec2 100644 --- a/src/main/java/eu/siacs/conversations/entities/Account.java +++ b/src/main/java/eu/siacs/conversations/entities/Account.java @@ -372,8 +372,9 @@ public class Account extends AbstractEntity { } public boolean hasBookmarkFor(final Jid conferenceJid) { - for (Bookmark bmark : this.bookmarks) { - if (bmark.getJid().equals(conferenceJid.toBareJid())) { + for (Bookmark bookmark : this.bookmarks) { + final Jid jid = bookmark.getJid(); + if (jid != null && jid.equals(conferenceJid.toBareJid())) { return true; } } diff --git a/src/main/java/eu/siacs/conversations/entities/Bookmark.java b/src/main/java/eu/siacs/conversations/entities/Bookmark.java index 91dc25be..559e2f2d 100644 --- a/src/main/java/eu/siacs/conversations/entities/Bookmark.java +++ b/src/main/java/eu/siacs/conversations/entities/Bookmark.java @@ -128,7 +128,8 @@ public class Bookmark extends Element implements ListItem { return true; } needle = needle.toLowerCase(Locale.US); - return getJid().toString().contains(needle) || + final Jid jid = getJid(); + return (jid != null && jid.toString().contains(needle)) || getDisplayName().toLowerCase(Locale.US).contains(needle) || matchInTag(needle); } diff --git a/src/main/java/eu/siacs/conversations/entities/Conversation.java b/src/main/java/eu/siacs/conversations/entities/Conversation.java index ed42ac77..a7da0bc2 100644 --- a/src/main/java/eu/siacs/conversations/entities/Conversation.java +++ b/src/main/java/eu/siacs/conversations/entities/Conversation.java @@ -458,6 +458,18 @@ public class Conversation extends AbstractEntity { return false; } + public Message findSentMessageWithBody(String body) { + synchronized (this.messages) { + for (int i = this.getMessages().size() - 1; i >= 0; --i) { + Message message = this.messages.get(i); + if ((message.getStatus() == Message.STATUS_UNSEND || message.getStatus() == Message.STATUS_SEND) && message.getBody() != null && message.getBody().equals(body)) { + return message; + } + } + return null; + } + } + public void setMutedTill(long value) { this.setAttribute(ATTRIBUTE_MUTED_TILL, String.valueOf(value)); } diff --git a/src/main/java/eu/siacs/conversations/entities/Message.java b/src/main/java/eu/siacs/conversations/entities/Message.java index 16635f7c..47861d06 100644 --- a/src/main/java/eu/siacs/conversations/entities/Message.java +++ b/src/main/java/eu/siacs/conversations/entities/Message.java @@ -73,14 +73,21 @@ public class Message extends AbstractEntity { } public Message(Conversation conversation, String body, int encryption, int status) { - this(java.util.UUID.randomUUID().toString(), conversation.getUuid(), - conversation.getContactJid().toBareJid(), null, body, System - .currentTimeMillis(), encryption, - status, TYPE_TEXT, null, null); + this(java.util.UUID.randomUUID().toString(), + conversation.getUuid(), + conversation.getContactJid() == null ? null : conversation.getContactJid().toBareJid(), + null, + body, + System.currentTimeMillis(), + encryption, + status, + TYPE_TEXT, + null, + null); this.conversation = conversation; } - public Message(final String uuid, final String conversationUUid, final Jid counterpart, + private Message(final String uuid, final String conversationUUid, final Jid counterpart, final Jid trueCounterpart, final String body, final long timeSent, final int encryption, final int status, final int type, final String remoteMsgId, final String relativeFilePath) { this.uuid = uuid; diff --git a/src/main/java/eu/siacs/conversations/entities/MucOptions.java b/src/main/java/eu/siacs/conversations/entities/MucOptions.java index 065b6ee4..c8706fc9 100644 --- a/src/main/java/eu/siacs/conversations/entities/MucOptions.java +++ b/src/main/java/eu/siacs/conversations/entities/MucOptions.java @@ -179,7 +179,7 @@ public class MucOptions { user.setAffiliation(item.getAttribute("affiliation")); user.setRole(item.getAttribute("role")); user.setJid(item.getAttributeAsJid("jid")); - if (codes.contains(STATUS_CODE_SELF_PRESENCE)) { + if (codes.contains(STATUS_CODE_SELF_PRESENCE) || packet.getFrom().equals(this.conversation.getContactJid())) { this.isOnline = true; this.error = ERROR_NO_ERROR; self = user; @@ -279,14 +279,13 @@ public class MucOptions { public String getProposedNick() { if (conversation.getBookmark() != null - && conversation.getBookmark().getNick() != null) { + && conversation.getBookmark().getNick() != null + && !conversation.getBookmark().getNick().isEmpty()) { return conversation.getBookmark().getNick(); + } else if (!conversation.getContactJid().isBareJid()) { + return conversation.getContactJid().getResourcepart(); } else { - if (!conversation.getContactJid().isBareJid()) { - return conversation.getContactJid().getResourcepart(); - } else { - return account.getUsername(); - } + return account.getUsername(); } } diff --git a/src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java b/src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java index 419964ea..f46e7ba4 100644 --- a/src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java +++ b/src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java @@ -20,7 +20,7 @@ public abstract class AbstractGenerator { "http://jabber.org/protocol/disco#info", "urn:xmpp:avatar:metadata+notify", "urn:xmpp:ping"}; - public final String IDENTITY_NAME = "Conversations 0.9-alpha"; + public final String IDENTITY_NAME = "Conversations 0.9.3"; public final String IDENTITY_TYPE = "phone"; protected XmppConnectionService mXmppConnectionService; diff --git a/src/main/java/eu/siacs/conversations/parser/IqParser.java b/src/main/java/eu/siacs/conversations/parser/IqParser.java index b38cdc72..aeec56d0 100644 --- a/src/main/java/eu/siacs/conversations/parser/IqParser.java +++ b/src/main/java/eu/siacs/conversations/parser/IqParser.java @@ -25,14 +25,11 @@ public class IqParser extends AbstractParser implements OnIqPacketReceived { } for (Element item : query.getChildren()) { if (item.getName().equals("item")) { - Jid jid; - try { - jid = Jid.fromString(item.getAttribute("jid")); - } catch (final InvalidJidException e) { - // TODO: Handle this? - jid = null; - } - String name = item.getAttribute("name"); + final Jid jid = item.getAttributeAsJid("jid"); + if (jid == null) { + break; + } + String name = item.getAttribute("name"); String subscription = item.getAttribute("subscription"); Contact contact = account.getRoster().getContact(jid); if (!contact.getOption(Contact.Options.DIRTY_PUSH)) { diff --git a/src/main/java/eu/siacs/conversations/parser/MessageParser.java b/src/main/java/eu/siacs/conversations/parser/MessageParser.java index ce2103dc..782675da 100644 --- a/src/main/java/eu/siacs/conversations/parser/MessageParser.java +++ b/src/main/java/eu/siacs/conversations/parser/MessageParser.java @@ -27,8 +27,10 @@ public class MessageParser extends AbstractParser implements private Message parseChat(MessagePacket packet, Account account) { final Jid jid = packet.getFrom(); - Conversation conversation = mXmppConnectionService - .findOrCreateConversation(account, jid.toBareJid(), false); + if (jid == null) { + return null; + } + Conversation conversation = mXmppConnectionService.findOrCreateConversation(account, jid.toBareJid(), false); updateLastseen(packet, account, true); String pgpBody = getPgpBody(packet); Message finishedMessage; @@ -61,6 +63,9 @@ public class MessageParser extends AbstractParser implements boolean properlyAddressed = (!packet.getTo().isBareJid()) || (account.countPresences() == 1); final Jid from = packet.getFrom(); + if (from == null) { + return null; + } Conversation conversation = mXmppConnectionService .findOrCreateConversation(account, from.toBareJid(), false); String presence; @@ -153,6 +158,14 @@ public class MessageParser extends AbstractParser implements if (mXmppConnectionService.markMessage(conversation, packet.getId(), Message.STATUS_SEND)) { return null; + } else if (packet.getId() == null) { + Message message = conversation.findSentMessageWithBody(packet.getBody()); + if (message != null) { + mXmppConnectionService.markMessage(message,Message.STATUS_SEND_RECEIVED); + return null; + } else { + status = Message.STATUS_SEND; + } } else { status = Message.STATUS_SEND; } @@ -319,12 +332,7 @@ public class MessageParser extends AbstractParser implements } } else if (packet.hasChild("x", "jabber:x:conference")) { Element x = packet.findChild("x", "jabber:x:conference"); - Jid jid; - try { - jid = Jid.fromString(x.getAttribute("jid")); - } catch (InvalidJidException e) { - jid = null; - } + Jid jid = x.getAttributeAsJid("jid"); String password = x.getAttribute("password"); if (jid != null) { Conversation conversation = mXmppConnectionService diff --git a/src/main/java/eu/siacs/conversations/parser/PresenceParser.java b/src/main/java/eu/siacs/conversations/parser/PresenceParser.java index 12167a1e..43c8fa8d 100644 --- a/src/main/java/eu/siacs/conversations/parser/PresenceParser.java +++ b/src/main/java/eu/siacs/conversations/parser/PresenceParser.java @@ -31,6 +31,8 @@ public class PresenceParser extends AbstractParser implements mXmppConnectionService.getAvatarService().clear(conversation); if (before != mucOptions.online() || (mucOptions.online() && count != mucOptions.getUsers().size())) { mXmppConnectionService.updateConversationUi(); + } else if (mucOptions.online()) { + mXmppConnectionService.updateMucRosterUi(); } } } diff --git a/src/main/java/eu/siacs/conversations/services/AvatarService.java b/src/main/java/eu/siacs/conversations/services/AvatarService.java index 1125859c..3ac4462d 100644 --- a/src/main/java/eu/siacs/conversations/services/AvatarService.java +++ b/src/main/java/eu/siacs/conversations/services/AvatarService.java @@ -113,7 +113,7 @@ public class AvatarService { if (bitmap != null) { return bitmap; } - List<MucOptions.User> users = mucOptions.getUsers(); + final List<MucOptions.User> users = new ArrayList<>(mucOptions.getUsers()); int count = users.size(); bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); @@ -121,8 +121,8 @@ public class AvatarService { if (count == 0) { String name = mucOptions.getConversation().getName(); - String letter = name.substring(0, 1); - int color = UIHelper.getColorForName(name); + final String letter = name.isEmpty() ? "X" : name.substring(0,1); + final int color = UIHelper.getColorForName(name); drawTile(canvas, letter, color, 0, 0, size, size); } else if (count == 1) { drawTile(canvas, users.get(0), 0, 0, size, size); @@ -212,15 +212,8 @@ public class AvatarService { } bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); - String letter; - int color; - if (name.length() > 0) { - letter = name.substring(0, 1); - color = UIHelper.getColorForName(name); - } else { - letter = "X"; - color = PLACEHOLDER_COLOR; - } + final String letter = name.isEmpty() ? "X" : name.substring(0,1); + final int color = UIHelper.getColorForName(name); drawTile(canvas, letter, color, 0, 0, size, size); mXmppConnectionService.getBitmapCache().put(KEY, bitmap); return bitmap; @@ -275,15 +268,8 @@ public class AvatarService { } } String name = contact != null ? contact.getDisplayName() : user.getName(); - String letter; - int color; - if (name.length() > 0) { - letter = name.substring(0, 1); - color = UIHelper.getColorForName(name); - } else { - letter = "X"; - color = PLACEHOLDER_COLOR; - } + final String letter = name.isEmpty() ? "X" : name.substring(0,1); + final int color = UIHelper.getColorForName(name); drawTile(canvas, letter, color, left, top, right, bottom); } diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 6958a062..41a40224 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -209,9 +209,11 @@ public class XmppConnectionService extends Service { getNotificationService().updateErrorNotification(); } }; - private Integer accountChangedListenerCount = 0; + private int accountChangedListenerCount = 0; private OnRosterUpdate mOnRosterUpdate = null; - private Integer rosterChangedListenerCount = 0; + private int rosterChangedListenerCount = 0; + private OnMucRosterUpdate mOnMucRosterUpdate = null; + private int mucRosterChangedListenerCount = 0; private SecureRandom mRandom; private FileObserver fileObserver = new FileObserver( FileBackend.getConversationsImageDirectory()) { @@ -781,7 +783,7 @@ public class XmppConnectionService extends Service { @Override public void onIqPacketReceived(final Account account, - IqPacket packet) { + IqPacket packet) { Element query = packet.findChild("query"); if (query != null) { account.getRoster().markAllAsNotInRoster(); @@ -811,13 +813,11 @@ public class XmppConnectionService extends Service { Conversation conversation = find(bookmark); if (conversation != null) { conversation.setBookmark(bookmark); - } else { - if (bookmark.autojoin()) { - conversation = findOrCreateConversation( - account, bookmark.getJid(), true); - conversation.setBookmark(bookmark); - joinMuc(conversation); - } + } else if (bookmark.autojoin() && bookmark.getJid() != null) { + conversation = findOrCreateConversation( + account, bookmark.getJid(), true); + conversation.setBookmark(bookmark); + joinMuc(conversation); } } } @@ -978,6 +978,9 @@ public class XmppConnectionService extends Service { public Conversation find(final List<Conversation> haystack, final Account account, final Jid jid) { + if (jid == null ) { + return null; + } for (Conversation conversation : haystack) { if ((account == null || conversation.getAccount() == account) && (conversation.getContactJid().toBareJid().equals(jid.toBareJid()))) { @@ -1092,65 +1095,21 @@ public class XmppConnectionService extends Service { } } - private void removeStaleListeners() { - boolean removedListener = false; - synchronized (this.convChangedListenerCount) { - if (this.mOnConversationUpdate != null) { - this.mOnConversationUpdate = null; - this.convChangedListenerCount = 0; - this.mNotificationService.setIsInForeground(false); - removedListener = true; - } - } - synchronized (this.accountChangedListenerCount) { - if (this.mOnAccountUpdate != null) { - this.mOnAccountUpdate = null; - this.accountChangedListenerCount = 0; - removedListener = true; - } - } - synchronized (this.rosterChangedListenerCount) { - if (this.mOnRosterUpdate != null) { - this.mOnRosterUpdate = null; - this.rosterChangedListenerCount = 0; - removedListener = true; - } - } - if (removedListener) { - final String msg = "removed stale listeners"; - Log.d(Config.LOGTAG, msg); - checkListeners(); - try { - OutputStream os = openFileOutput("stacktrace.txt", MODE_PRIVATE); - os.write(msg.getBytes()); - os.flush(); - os.close(); - } catch (final FileNotFoundException ignored) { - - } catch (final IOException ignored) { - } - } - } - - public void setOnConversationListChangedListener( - OnConversationUpdate listener) { - /*if (!isScreenOn()) { - Log.d(Config.LOGTAG, - "ignoring setOnConversationListChangedListener"); - return; - }*/ - synchronized (this.convChangedListenerCount) { + public void setOnConversationListChangedListener(OnConversationUpdate listener) { + synchronized (this) { if (checkListeners()) { switchToForeground(); } this.mOnConversationUpdate = listener; this.mNotificationService.setIsInForeground(true); - this.convChangedListenerCount++; - } + if (this.convChangedListenerCount < 2) { + this.convChangedListenerCount++; } + } + } public void removeOnConversationListChangedListener() { - synchronized (this.convChangedListenerCount) { + synchronized (this) { this.convChangedListenerCount--; if (this.convChangedListenerCount <= 0) { this.convChangedListenerCount = 0; @@ -1164,21 +1123,19 @@ public class XmppConnectionService extends Service { } public void setOnAccountListChangedListener(OnAccountUpdate listener) { - /*if (!isScreenOn()) { - Log.d(Config.LOGTAG, "ignoring setOnAccountListChangedListener"); - return; - }*/ - synchronized (this.accountChangedListenerCount) { + synchronized (this) { if (checkListeners()) { switchToForeground(); } this.mOnAccountUpdate = listener; - this.accountChangedListenerCount++; + if (this.accountChangedListenerCount < 2) { + this.accountChangedListenerCount++; + } } } public void removeOnAccountListChangedListener() { - synchronized (this.accountChangedListenerCount) { + synchronized (this) { this.accountChangedListenerCount--; if (this.accountChangedListenerCount <= 0) { this.mOnAccountUpdate = null; @@ -1191,21 +1148,19 @@ public class XmppConnectionService extends Service { } public void setOnRosterUpdateListener(OnRosterUpdate listener) { - /*if (!isScreenOn()) { - Log.d(Config.LOGTAG, "ignoring setOnRosterUpdateListener"); - return; - }*/ - synchronized (this.rosterChangedListenerCount) { + synchronized (this) { if (checkListeners()) { switchToForeground(); } this.mOnRosterUpdate = listener; - this.rosterChangedListenerCount++; + if (this.rosterChangedListenerCount < 2) { + this.rosterChangedListenerCount++; + } } } public void removeOnRosterUpdateListener() { - synchronized (this.rosterChangedListenerCount) { + synchronized (this) { this.rosterChangedListenerCount--; if (this.rosterChangedListenerCount <= 0) { this.rosterChangedListenerCount = 0; @@ -1217,6 +1172,31 @@ public class XmppConnectionService extends Service { } } + public void setOnMucRosterUpdateListener(OnMucRosterUpdate listener) { + synchronized (this) { + if (checkListeners()) { + switchToForeground(); + } + this.mOnMucRosterUpdate = listener; + if (this.mucRosterChangedListenerCount < 2) { + this.mucRosterChangedListenerCount++; + } + } + } + + public void removeOnMucRosterUpdateListener() { + synchronized (this) { + this.mucRosterChangedListenerCount--; + if (this.mucRosterChangedListenerCount <= 0) { + this.mucRosterChangedListenerCount = 0; + this.mOnMucRosterUpdate = null; + if (checkListeners()) { + switchToBackground(); + } + } + } + } + private boolean checkListeners() { return (this.mOnAccountUpdate == null && this.mOnConversationUpdate == null && this.mOnRosterUpdate == null); @@ -1247,12 +1227,6 @@ public class XmppConnectionService extends Service { Log.d(Config.LOGTAG, "app switched into background"); } - private boolean isScreenOn() { - PowerManager pm = (PowerManager) this - .getSystemService(Context.POWER_SERVICE); - return pm.isScreenOn(); - } - public void connectMultiModeConversations(Account account) { List<Conversation> conversations = getConversations(); for (Conversation conversation : conversations) { @@ -1268,10 +1242,12 @@ public class XmppConnectionService extends Service { account.pendingConferenceJoins.remove(conversation); account.pendingConferenceLeaves.remove(conversation); if (account.getStatus() == Account.State.ONLINE) { - Log.d(Config.LOGTAG, - "joining conversation " + conversation.getContactJid()); - String nick = conversation.getMucOptions().getProposedNick(); - Jid joinJid = conversation.getMucOptions().createJoinJid(nick); + final String nick = conversation.getMucOptions().getProposedNick(); + final Jid joinJid = conversation.getMucOptions().createJoinJid(nick); + if (joinJid == null) { + return; //safety net + } + Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": joining conversation " + joinJid.toString()); PresencePacket packet = new PresencePacket(); packet.setFrom(conversation.getAccount().getJid()); packet.setTo(joinJid); @@ -1703,7 +1679,7 @@ public class XmppConnectionService extends Service { @Override public void onIqPacketReceived(Account account, IqPacket result) { final String ERROR = account.getJid().toBareJid() - + ": fetching avatar for " + avatar.owner + " failed "; + + ": fetching avatar for " + avatar.owner + " failed "; if (result.getType() == IqPacket.TYPE_RESULT) { avatar.image = mIqParser.avatarData(result); if (avatar.image != null) { @@ -1717,7 +1693,7 @@ public class XmppConnectionService extends Service { updateAccountUi(); } else { Contact contact = account.getRoster() - .getContact(avatar.owner); + .getContact(avatar.owner); contact.setAvatar(avatar.getFilename()); getAvatarService().clear(contact); updateConversationUi(); @@ -1928,6 +1904,12 @@ public class XmppConnectionService extends Service { } } + public void updateMucRosterUi() { + if (mOnMucRosterUpdate != null) { + mOnMucRosterUpdate.onMucRosterUpdate(); + } + } + public Account findAccountByJid(final Jid accountJid) { for (Account account : this.accounts) { if (account.getJid().toBareJid().equals(accountJid.toBareJid())) { @@ -2125,6 +2107,10 @@ public class XmppConnectionService extends Service { public void onRosterUpdate(); } + public interface OnMucRosterUpdate { + public void onMucRosterUpdate(); + } + private interface OnConferenceOptionsPushed { public void onPushSucceeded(); public void onPushFailed(); diff --git a/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java b/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java index 290842fb..2e36c545 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java @@ -27,13 +27,16 @@ import java.util.List; import eu.siacs.conversations.R; import eu.siacs.conversations.crypto.PgpEngine; +import eu.siacs.conversations.entities.Account; +import eu.siacs.conversations.entities.Bookmark; import eu.siacs.conversations.entities.Contact; import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.entities.MucOptions.User; +import eu.siacs.conversations.services.XmppConnectionService.OnMucRosterUpdate; import eu.siacs.conversations.services.XmppConnectionService.OnConversationUpdate; import eu.siacs.conversations.xmpp.stanzas.MessagePacket; -public class ConferenceDetailsActivity extends XmppActivity implements OnConversationUpdate { +public class ConferenceDetailsActivity extends XmppActivity implements OnConversationUpdate, OnMucRosterUpdate { public static final String ACTION_VIEW_MUC = "view_muc"; private Conversation mConversation; private OnClickListener inviteListener = new OnClickListener() { @@ -97,6 +100,17 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers } @Override + public void onMucRosterUpdate() { + runOnUiThread(new Runnable() { + + @Override + public void run() { + populateView(); + } + }); + } + + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_muc_details); @@ -110,8 +124,10 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers mMoreDetails.setVisibility(View.GONE); mInviteButton = (Button) findViewById(R.id.invite); mInviteButton.setOnClickListener(inviteListener); - getActionBar().setHomeButtonEnabled(true); - getActionBar().setDisplayHomeAsUpEnabled(true); + if (getActionBar() != null) { + getActionBar().setHomeButtonEnabled(true); + getActionBar().setDisplayHomeAsUpEnabled(true); + } mEditNickButton.setOnClickListener(new OnClickListener() { @Override @@ -149,6 +165,12 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers }); } break; + case R.id.action_save_as_bookmark: + saveAsBookmark(); + break; + case R.id.action_delete_bookmark: + deleteBookmark(); + break; } return super.onOptionsItemSelected(menuItem); } @@ -176,6 +198,21 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers } @Override + public boolean onPrepareOptionsMenu(Menu menu) { + MenuItem menuItemSaveBookmark = menu.findItem(R.id.action_save_as_bookmark); + MenuItem menuItemDeleteBookmark = menu.findItem(R.id.action_delete_bookmark); + Account account = mConversation.getAccount(); + if (account.hasBookmarkFor(mConversation.getContactJid().toBareJid())) { + menuItemSaveBookmark.setVisible(false); + menuItemDeleteBookmark.setVisible(true); + } else { + menuItemDeleteBookmark.setVisible(false); + menuItemSaveBookmark.setVisible(true); + } + return true; + } + + @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.muc_details, menu); return true; @@ -219,11 +256,31 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers protected void startConversation(User user) { if (user.getJid() != null) { - Conversation conversation = xmppConnectionService.findOrCreateConversation(this.mConversation.getAccount(),user.getJid(),false); + Conversation conversation = xmppConnectionService.findOrCreateConversation(this.mConversation.getAccount(),user.getJid().toBareJid(),false); switchToConversation(conversation); } } + protected void saveAsBookmark() { + Account account = mConversation.getAccount(); + Bookmark bookmark = new Bookmark(account, mConversation.getContactJid().toBareJid()); + if (!mConversation.getContactJid().isBareJid()) { + bookmark.setNick(mConversation.getContactJid().getResourcepart()); + } + bookmark.setAutojoin(true); + account.getBookmarks().add(bookmark); + xmppConnectionService.pushBookmarks(account); + mConversation.setBookmark(bookmark); + } + + protected void deleteBookmark() { + Account account = mConversation.getAccount(); + Bookmark bookmark = mConversation.getBookmark(); + bookmark.unregisterConversation(); + account.getBookmarks().remove(bookmark); + xmppConnectionService.pushBookmarks(account); + } + @Override void onBackendConnected() { if (getIntent().getAction().equals(ACTION_VIEW_MUC)) { @@ -313,6 +370,7 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers } } + @SuppressWarnings("deprecation") @TargetApi(Build.VERSION_CODES.JELLY_BEAN) private void setListItemBackgroundOnView(View view) { int sdk = android.os.Build.VERSION.SDK_INT; @@ -332,7 +390,7 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers try { startIntentSenderForResult(intent.getIntentSender(), 0, null, 0, 0, 0); - } catch (SendIntentException e) { + } catch (SendIntentException ignored) { } } diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java index 0277f155..5b0fa562 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java @@ -235,15 +235,16 @@ public class ConversationActivity extends XmppActivity implements } private void updateActionBarTitle(boolean titleShouldBeName) { - ActionBar ab = getActionBar(); + final ActionBar ab = getActionBar(); + final Conversation conversation = getSelectedConversation(); if (ab != null) { - if (titleShouldBeName) { + if (titleShouldBeName && conversation != null) { ab.setDisplayHomeAsUpEnabled(true); ab.setHomeButtonEnabled(true); - if (getSelectedConversation().getMode() == Conversation.MODE_SINGLE || useSubjectToIdentifyConference()) { - ab.setTitle(getSelectedConversation().getName()); + if (conversation.getMode() == Conversation.MODE_SINGLE || useSubjectToIdentifyConference()) { + ab.setTitle(conversation.getName()); } else { - ab.setTitle(getSelectedConversation().getContactJid().toBareJid().toString()); + ab.setTitle(conversation.getContactJid().toBareJid().toString()); } } else { ab.setDisplayHomeAsUpEnabled(false); @@ -770,12 +771,8 @@ public class ConversationActivity extends XmppActivity implements super.onActivityResult(requestCode, resultCode, data); if (resultCode == RESULT_OK) { if (requestCode == REQUEST_DECRYPT_PGP) { - ConversationFragment selectedFragment = (ConversationFragment) getFragmentManager() - .findFragmentByTag("conversation"); - if (selectedFragment != null) { - selectedFragment.hideSnackbar(); - selectedFragment.updateMessages(); - } + mConversationFragment.hideSnackbar(); + mConversationFragment.updateMessages(); } else if (requestCode == REQUEST_ATTACH_IMAGE_DIALOG) { mPendingImageUri = data.getData(); if (xmppConnectionServiceBound) { diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java index 287d1636..0edc6b6f 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java @@ -35,6 +35,7 @@ import net.java.otr4j.session.SessionStatus; import java.util.ArrayList; import java.util.List; +import java.util.NoSuchElementException; import java.util.concurrent.ConcurrentLinkedQueue; import eu.siacs.conversations.R; @@ -503,6 +504,8 @@ public class ConversationFragment extends Fragment { } this.activity = (ConversationActivity) getActivity(); this.conversation = conversation; + this.mDecryptJobRunning = false; + this.mEncryptedMessages.clear(); if (this.conversation.getMode() == Conversation.MODE_MULTI) { this.conversation.setNextCounterpart(null); } @@ -577,23 +580,23 @@ public class ConversationFragment extends Fragment { break; } } - for (Message message : this.conversation.getMessages()) { - if (message.getEncryption() == Message.ENCRYPTION_PGP - && (message.getStatus() == Message.STATUS_RECEIVED || message - .getStatus() >= Message.STATUS_SEND) - && message.getDownloadable() == null) { - if (!mEncryptedMessages.contains(message)) { - mEncryptedMessages.add(message); - } - } - } - decryptNext(); this.messageList.clear(); if (this.conversation.getMessages().size() == 0) { messagesLoaded = false; } else { this.messageList.addAll(this.conversation.getMessages()); messagesLoaded = true; + for (Message message : this.messageList) { + if (message.getEncryption() == Message.ENCRYPTION_PGP + && (message.getStatus() == Message.STATUS_RECEIVED || message + .getStatus() >= Message.STATUS_SEND) + && message.getDownloadable() == null) { + if (!mEncryptedMessages.contains(message)) { + mEncryptedMessages.add(message); + } + } + } + decryptNext(); updateStatusMessages(); } this.messageListAdapter.notifyDataSetChanged(); @@ -626,7 +629,11 @@ public class ConversationFragment extends Fragment { @Override public void success(Message message) { mDecryptJobRunning = false; - mEncryptedMessages.remove(); + try { + mEncryptedMessages.remove(); + } catch (final NoSuchElementException ignored) { + + } activity.xmppConnectionService.updateMessage(message); } @@ -634,7 +641,11 @@ public class ConversationFragment extends Fragment { public void error(int error, Message message) { message.setEncryption(Message.ENCRYPTION_DECRYPTION_FAILED); mDecryptJobRunning = false; - mEncryptedMessages.remove(); + try { + mEncryptedMessages.remove(); + } catch (final NoSuchElementException ignored) { + + } activity.xmppConnectionService.updateConversationUi(); } }); diff --git a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java index 22507483..8fad66cf 100644 --- a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java @@ -74,14 +74,15 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate return; } boolean registerNewAccount = mRegisterNew.isChecked(); - final Jid jid; - try { - jid = Jid.fromString(mAccountJid.getText().toString()); - } catch (final InvalidJidException e) { - // TODO: Handle this error? - return; - } - String password = mPassword.getText().toString(); + final Jid jid; + try { + jid = Jid.fromString(mAccountJid.getText().toString()); + } catch (final InvalidJidException e) { + mAccountJid.setError(getString(R.string.invalid_jid)); + mAccountJid.requestFocus(); + return; + } + String password = mPassword.getText().toString(); String passwordConfirm = mPasswordConfirm.getText().toString(); if (registerNewAccount) { if (!password.equals(passwordConfirm)) { diff --git a/src/main/java/eu/siacs/conversations/ui/SettingsFragment.java b/src/main/java/eu/siacs/conversations/ui/SettingsFragment.java index 7e1c3698..e4185abc 100644 --- a/src/main/java/eu/siacs/conversations/ui/SettingsFragment.java +++ b/src/main/java/eu/siacs/conversations/ui/SettingsFragment.java @@ -1,10 +1,51 @@ package eu.siacs.conversations.ui; -import eu.siacs.conversations.R; +import android.app.Dialog; import android.os.Bundle; +import android.preference.Preference; import android.preference.PreferenceFragment; +import android.preference.PreferenceScreen; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewParent; +import android.widget.FrameLayout; +import android.widget.LinearLayout; + +import eu.siacs.conversations.R; public class SettingsFragment extends PreferenceFragment { + + //http://stackoverflow.com/questions/16374820/action-bar-home-button-not-functional-with-nested-preferencescreen/16800527#16800527 + private void initializeActionBar(PreferenceScreen preferenceScreen) { + final Dialog dialog = preferenceScreen.getDialog(); + + if (dialog != null) { + View homeBtn = dialog.findViewById(android.R.id.home); + + if (homeBtn != null) { + View.OnClickListener dismissDialogClickListener = new View.OnClickListener() { + @Override + public void onClick(View v) { + dialog.dismiss(); + } + }; + + ViewParent homeBtnContainer = homeBtn.getParent(); + + if (homeBtnContainer instanceof FrameLayout) { + ViewGroup containerParent = (ViewGroup) homeBtnContainer.getParent(); + if (containerParent instanceof LinearLayout) { + ((LinearLayout) containerParent).setOnClickListener(dismissDialogClickListener); + } else { + ((FrameLayout) homeBtnContainer).setOnClickListener(dismissDialogClickListener); + } + } else { + homeBtn.setOnClickListener(dismissDialogClickListener); + } + } + } + } + @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -12,4 +53,13 @@ public class SettingsFragment extends PreferenceFragment { // Load the preferences from an XML resource addPreferencesFromResource(R.xml.preferences); } + + @Override + public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) { + super.onPreferenceTreeClick(preferenceScreen, preference); + if (preference instanceof PreferenceScreen) { + initializeActionBar((PreferenceScreen) preference); + } + return false; + } } diff --git a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java index ddc57c2e..5fba1664 100644 --- a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java @@ -241,6 +241,9 @@ public abstract class XmppActivity extends Activity { if (this instanceof XmppConnectionService.OnRosterUpdate) { this.xmppConnectionService.setOnRosterUpdateListener((XmppConnectionService.OnRosterUpdate) this); } + if (this instanceof XmppConnectionService.OnMucRosterUpdate) { + this.xmppConnectionService.setOnMucRosterUpdateListener((XmppConnectionService.OnMucRosterUpdate) this); + } } protected void unregisterListeners() { @@ -253,6 +256,9 @@ public abstract class XmppActivity extends Activity { if (this instanceof XmppConnectionService.OnRosterUpdate) { this.xmppConnectionService.removeOnRosterUpdateListener(); } + if (this instanceof XmppConnectionService.OnMucRosterUpdate) { + this.xmppConnectionService.removeOnMucRosterUpdateListener(); + } } public boolean onOptionsItemSelected(MenuItem item) { diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java index b81544e6..f728e800 100644 --- a/src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java +++ b/src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java @@ -2,7 +2,6 @@ package eu.siacs.conversations.ui.adapter; import java.util.List; -import eu.siacs.conversations.Config; import eu.siacs.conversations.R; import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.entities.Downloadable; @@ -139,10 +138,7 @@ public class ConversationAdapter extends ArrayAdapter<Conversation> { } else { if ((message.getEncryption() != Message.ENCRYPTION_PGP) && (message.getEncryption() != Message.ENCRYPTION_DECRYPTION_FAILED)) { - String body = Config.PARSE_EMOTICONS ? UIHelper - .transformAsciiEmoticons(message.getBody()) : message - .getBody(); - mLastMessage.setText(body); + mLastMessage.setText(message.getBody()); } else { mLastMessage.setText(R.string.encrypted_message_received); } diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/KnownHostsAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/KnownHostsAdapter.java index 143dfda1..0993735f 100644 --- a/src/main/java/eu/siacs/conversations/ui/adapter/KnownHostsAdapter.java +++ b/src/main/java/eu/siacs/conversations/ui/adapter/KnownHostsAdapter.java @@ -60,11 +60,8 @@ public class KnownHostsAdapter extends ArrayAdapter<String> { public KnownHostsAdapter(Context context, int viewResourceId, List<String> mKnownHosts) { - super(context, viewResourceId, mKnownHosts); - domains = new ArrayList<String>(mKnownHosts.size()); - for (String domain : mKnownHosts) { - domains.add(new String(domain)); - } + super(context, viewResourceId, new ArrayList<String>()); + domains = new ArrayList<String>(mKnownHosts); } @Override diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/ListItemAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/ListItemAdapter.java index 250a69c3..0865d1aa 100644 --- a/src/main/java/eu/siacs/conversations/ui/adapter/ListItemAdapter.java +++ b/src/main/java/eu/siacs/conversations/ui/adapter/ListItemAdapter.java @@ -5,6 +5,8 @@ import java.util.List; import eu.siacs.conversations.R; import eu.siacs.conversations.entities.ListItem; import eu.siacs.conversations.ui.XmppActivity; +import eu.siacs.conversations.xmpp.jid.Jid; + import android.content.Context; import android.content.SharedPreferences; import android.preference.PreferenceManager; @@ -36,8 +38,8 @@ public class ListItemAdapter extends ArrayAdapter<ListItem> { if (view == null) { view = inflater.inflate(R.layout.contact, parent, false); } - TextView name = (TextView) view.findViewById(R.id.contact_display_name); - TextView jid = (TextView) view.findViewById(R.id.contact_jid); + TextView tvName = (TextView) view.findViewById(R.id.contact_display_name); + TextView tvJid = (TextView) view.findViewById(R.id.contact_jid); ImageView picture = (ImageView) view.findViewById(R.id.contact_photo); LinearLayout tagLayout = (LinearLayout) view.findViewById(R.id.tags); @@ -54,9 +56,13 @@ public class ListItemAdapter extends ArrayAdapter<ListItem> { tagLayout.addView(tv); } } - - jid.setText(item.getJid().toString()); - name.setText(item.getDisplayName()); + final Jid jid = item.getJid(); + if (jid != null) { + tvJid.setText(jid.toString()); + } else { + tvJid.setText(""); + } + tvName.setText(item.getDisplayName()); picture.setImageBitmap(activity.avatarService().get(item, activity.getPixel(48))); return view; diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java index e14af11f..32062699 100644 --- a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java +++ b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java @@ -23,8 +23,8 @@ import android.widget.Toast; import java.util.List; -import eu.siacs.conversations.Config; import eu.siacs.conversations.R; +import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Contact; import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.entities.Downloadable; @@ -224,10 +224,7 @@ public class MessageAdapter extends ArrayAdapter<Message> { viewHolder.messageBody.setVisibility(View.VISIBLE); if (message.getBody() != null) { if (message.getType() != Message.TYPE_PRIVATE) { - String body = Config.PARSE_EMOTICONS ? UIHelper - .transformAsciiEmoticons(message.getMergedBody()) - : message.getMergedBody(); - viewHolder.messageBody.setText(body); + viewHolder.messageBody.setText(message.getMergedBody()); } else { String privateMarker; if (message.getStatus() <= Message.STATUS_RECEIVED) { @@ -339,8 +336,10 @@ public class MessageAdapter extends ArrayAdapter<Message> { @Override public View getView(int position, View view, ViewGroup parent) { - final Message item = getItem(position); - int type = getItemViewType(position); + final Message message = getItem(position); + final Conversation conversation = message.getConversation(); + final Account account = conversation.getAccount(); + final int type = getItemViewType(position); ViewHolder viewHolder; if (view == null) { viewHolder = new ViewHolder(); @@ -368,7 +367,6 @@ public class MessageAdapter extends ArrayAdapter<Message> { .findViewById(R.id.message_time); viewHolder.indicatorReceived = (ImageView) view .findViewById(R.id.indicator_received); - view.setTag(viewHolder); break; case RECEIVED: view = activity.getLayoutInflater().inflate( @@ -389,28 +387,29 @@ public class MessageAdapter extends ArrayAdapter<Message> { .findViewById(R.id.message_time); viewHolder.indicatorReceived = (ImageView) view .findViewById(R.id.indicator_received); - view.setTag(viewHolder); break; case STATUS: view = activity.getLayoutInflater().inflate( R.layout.message_status, parent, false); viewHolder.contact_picture = (ImageView) view .findViewById(R.id.message_photo); - view.setTag(viewHolder); break; default: viewHolder = null; break; } + view.setTag(viewHolder); } else { viewHolder = (ViewHolder) view.getTag(); + if (viewHolder == null) { + return view; + } } if (type == STATUS) { - if (item.getConversation().getMode() == Conversation.MODE_SINGLE) { + if (conversation.getMode() == Conversation.MODE_SINGLE) { viewHolder.contact_picture.setImageBitmap(activity - .avatarService().get( - item.getConversation().getContact(), + .avatarService().get(conversation.getContact(), activity.getPixel(32))); viewHolder.contact_picture.setAlpha(0.5f); viewHolder.contact_picture @@ -418,8 +417,7 @@ public class MessageAdapter extends ArrayAdapter<Message> { @Override public void onClick(View v) { - String name = item.getConversation() - .getName(); + String name = conversation.getName(); String read = getContext() .getString( R.string.contact_has_read_up_to_this_point, @@ -441,15 +439,15 @@ public class MessageAdapter extends ArrayAdapter<Message> { view.setLayoutParams(view.getLayoutParams()); return view; } else if (type == RECEIVED) { - Contact contact = item.getContact(); + Contact contact = message.getContact(); if (contact != null) { viewHolder.contact_picture.setImageBitmap(activity.avatarService().get(contact, activity.getPixel(48))); - } else if (item.getConversation().getMode() == Conversation.MODE_MULTI) { - viewHolder.contact_picture.setImageBitmap(activity.avatarService().get(getDisplayedMucCounterpart(item.getCounterpart()), + } else if (conversation.getMode() == Conversation.MODE_MULTI) { + viewHolder.contact_picture.setImageBitmap(activity.avatarService().get(getDisplayedMucCounterpart(message.getCounterpart()), activity.getPixel(48))); } - } else if (type == SENT) { - viewHolder.contact_picture.setImageBitmap(activity.avatarService().get(item.getConversation().getAccount(), activity.getPixel(48))); + } else if (type == SENT && viewHolder.contact_picture != null) { + viewHolder.contact_picture.setImageBitmap(activity.avatarService().get(account, activity.getPixel(48))); } if (viewHolder != null && viewHolder.contact_picture != null) { @@ -460,7 +458,7 @@ public class MessageAdapter extends ArrayAdapter<Message> { public void onClick(View v) { if (MessageAdapter.this.mOnContactPictureClickedListener != null) { MessageAdapter.this.mOnContactPictureClickedListener - .onContactPictureClicked(item); + .onContactPictureClicked(message); } } @@ -472,7 +470,7 @@ public class MessageAdapter extends ArrayAdapter<Message> { public boolean onLongClick(View v) { if (MessageAdapter.this.mOnContactPictureLongClickedListener != null) { MessageAdapter.this.mOnContactPictureLongClickedListener - .onContactPictureLongClicked(item); + .onContactPictureLongClicked(message); return true; } else { return false; @@ -481,10 +479,10 @@ public class MessageAdapter extends ArrayAdapter<Message> { }); } - if (item.getDownloadable() != null && item.getDownloadable().getStatus() != Downloadable.STATUS_UPLOADING) { - Downloadable d = item.getDownloadable(); + if (message.getDownloadable() != null && message.getDownloadable().getStatus() != Downloadable.STATUS_UPLOADING) { + Downloadable d = message.getDownloadable(); if (d.getStatus() == Downloadable.STATUS_DOWNLOADING) { - if (item.getType() == Message.TYPE_FILE) { + if (message.getType() == Message.TYPE_FILE) { displayInfoMessage(viewHolder,activity.getString(R.string.receiving_file,d.getMimeType(),d.getProgress())); } else { displayInfoMessage(viewHolder,activity.getString(R.string.receiving_image,d.getProgress())); @@ -492,35 +490,35 @@ public class MessageAdapter extends ArrayAdapter<Message> { } else if (d.getStatus() == Downloadable.STATUS_CHECKING) { displayInfoMessage(viewHolder,activity.getString(R.string.checking_image)); } else if (d.getStatus() == Downloadable.STATUS_DELETED) { - if (item.getType() == Message.TYPE_FILE) { + if (message.getType() == Message.TYPE_FILE) { displayInfoMessage(viewHolder, activity.getString(R.string.file_deleted)); } else { displayInfoMessage(viewHolder, activity.getString(R.string.image_file_deleted)); } } else if (d.getStatus() == Downloadable.STATUS_OFFER) { - if (item.getType() == Message.TYPE_FILE) { - displayDownloadableMessage(viewHolder,item,activity.getString(R.string.download_file,d.getMimeType())); + if (message.getType() == Message.TYPE_FILE) { + displayDownloadableMessage(viewHolder,message,activity.getString(R.string.download_file,d.getMimeType())); } else { - displayDownloadableMessage(viewHolder, item,activity.getString(R.string.download_image)); + displayDownloadableMessage(viewHolder, message,activity.getString(R.string.download_image)); } } else if (d.getStatus() == Downloadable.STATUS_OFFER_CHECK_FILESIZE) { - displayDownloadableMessage(viewHolder, item,activity.getString(R.string.check_image_filesize)); + displayDownloadableMessage(viewHolder, message,activity.getString(R.string.check_image_filesize)); } else if (d.getStatus() == Downloadable.STATUS_FAILED) { - if (item.getType() == Message.TYPE_FILE) { + if (message.getType() == Message.TYPE_FILE) { displayInfoMessage(viewHolder, activity.getString(R.string.file_transmission_failed)); } else { displayInfoMessage(viewHolder, activity.getString(R.string.image_transmission_failed)); } } - } else if (item.getType() == Message.TYPE_IMAGE && item.getEncryption() != Message.ENCRYPTION_PGP && item.getEncryption() != Message.ENCRYPTION_DECRYPTION_FAILED) { - displayImageMessage(viewHolder, item); - } else if (item.getType() == Message.TYPE_FILE && item.getEncryption() != Message.ENCRYPTION_PGP && item.getEncryption() != Message.ENCRYPTION_DECRYPTION_FAILED) { - if (item.getImageParams().width > 0) { - displayImageMessage(viewHolder,item); + } else if (message.getType() == Message.TYPE_IMAGE && message.getEncryption() != Message.ENCRYPTION_PGP && message.getEncryption() != Message.ENCRYPTION_DECRYPTION_FAILED) { + displayImageMessage(viewHolder, message); + } else if (message.getType() == Message.TYPE_FILE && message.getEncryption() != Message.ENCRYPTION_PGP && message.getEncryption() != Message.ENCRYPTION_DECRYPTION_FAILED) { + if (message.getImageParams().width > 0) { + displayImageMessage(viewHolder,message); } else { - displayOpenableMessage(viewHolder, item); + displayOpenableMessage(viewHolder, message); } - } else if (item.getEncryption() == Message.ENCRYPTION_PGP) { + } else if (message.getEncryption() == Message.ENCRYPTION_PGP) { if (activity.hasPgp()) { displayInfoMessage(viewHolder,activity.getString(R.string.encrypted_message)); } else { @@ -537,13 +535,13 @@ public class MessageAdapter extends ArrayAdapter<Message> { }); } } - } else if (item.getEncryption() == Message.ENCRYPTION_DECRYPTION_FAILED) { + } else if (message.getEncryption() == Message.ENCRYPTION_DECRYPTION_FAILED) { displayDecryptionFailed(viewHolder); } else { - displayTextMessage(viewHolder, item); + displayTextMessage(viewHolder, message); } - displayStatus(viewHolder, item); + displayStatus(viewHolder, message); return view; } diff --git a/src/main/java/eu/siacs/conversations/utils/PhoneHelper.java b/src/main/java/eu/siacs/conversations/utils/PhoneHelper.java index 5becc7e7..87973159 100644 --- a/src/main/java/eu/siacs/conversations/utils/PhoneHelper.java +++ b/src/main/java/eu/siacs/conversations/utils/PhoneHelper.java @@ -64,6 +64,7 @@ public class PhoneHelper { if (listener != null) { listener.onPhoneContactsLoaded(phoneContacts); } + cursor.close(); } }); try { @@ -85,6 +86,7 @@ public class PhoneHelper { } else { mProfileCursor.moveToFirst(); String uri = mProfileCursor.getString(1); + mProfileCursor.close(); if (uri == null) { return null; } else { diff --git a/src/main/java/eu/siacs/conversations/utils/UIHelper.java b/src/main/java/eu/siacs/conversations/utils/UIHelper.java index 341b3d77..2f1383b8 100644 --- a/src/main/java/eu/siacs/conversations/utils/UIHelper.java +++ b/src/main/java/eu/siacs/conversations/utils/UIHelper.java @@ -2,7 +2,6 @@ package eu.siacs.conversations.utils; import java.util.Calendar; import java.util.Date; -import java.util.regex.Pattern; import eu.siacs.conversations.R; import android.content.Context; @@ -86,48 +85,10 @@ public class UIHelper { } } - private final static class EmoticonPattern { - Pattern pattern; - String replacement; - - EmoticonPattern(String ascii, int unicode) { - this.pattern = Pattern.compile("(?<=(^|\\s))" + ascii - + "(?=(\\s|$))"); - this.replacement = new String(new int[] { unicode, }, 0, 1); - } - - String replaceAll(String body) { - return pattern.matcher(body).replaceAll(replacement); - } - } - - private static final EmoticonPattern[] patterns = new EmoticonPattern[] { - new EmoticonPattern(":-?D", 0x1f600), - new EmoticonPattern("\\^\\^", 0x1f601), - new EmoticonPattern(":'D", 0x1f602), - new EmoticonPattern("\\]-?D", 0x1f608), - new EmoticonPattern(";-?\\)", 0x1f609), - new EmoticonPattern(":-?\\)", 0x1f60a), - new EmoticonPattern("[B8]-?\\)", 0x1f60e), - new EmoticonPattern(":-?\\|", 0x1f610), - new EmoticonPattern(":-?[/\\\\]", 0x1f615), - new EmoticonPattern(":-?\\*", 0x1f617), - new EmoticonPattern(":-?[Ppb]", 0x1f61b), - new EmoticonPattern(":-?\\(", 0x1f61e), - new EmoticonPattern(":-?[0Oo]", 0x1f62e), - new EmoticonPattern("\\\\o/", 0x1F631), }; - - public static String transformAsciiEmoticons(String body) { - if (body != null) { - for (EmoticonPattern p : patterns) { - body = p.replaceAll(body); - } - body = body.trim(); - } - return body; - } - public static int getColorForName(String name) { + if (name.isEmpty()) { + return 0xFF202020; + } int colors[] = {0xFFe91e63, 0xFF9c27b0, 0xFF673ab7, 0xFF3f51b5, 0xFF5677fc, 0xFF03a9f4, 0xFF00bcd4, 0xFF009688, 0xFFff5722, 0xFF795548, 0xFF607d8b}; diff --git a/src/main/java/eu/siacs/conversations/utils/zlib/ZLibInputStream.java b/src/main/java/eu/siacs/conversations/utils/zlib/ZLibInputStream.java deleted file mode 100644 index b777c10c..00000000 --- a/src/main/java/eu/siacs/conversations/utils/zlib/ZLibInputStream.java +++ /dev/null @@ -1,54 +0,0 @@ -package eu.siacs.conversations.utils.zlib; - -import java.io.IOException; -import java.io.InputStream; -import java.util.zip.Inflater; -import java.util.zip.InflaterInputStream; - -/** - * ZLibInputStream is a zlib and input stream compatible version of an - * InflaterInputStream. This class solves the incompatibility between - * {@link InputStream#available()} and {@link InflaterInputStream#available()}. - */ -public class ZLibInputStream extends InflaterInputStream { - - /** - * Construct a ZLibInputStream, reading data from the underlying stream. - * - * @param is - * The {@code InputStream} to read data from. - * @throws IOException - * If an {@code IOException} occurs. - */ - public ZLibInputStream(InputStream is) throws IOException { - super(is, new Inflater(), 512); - } - - /** - * Provide a more InputStream compatible version of available. A return - * value of 1 means that it is likly to read one byte without blocking, 0 - * means that the system is known to block for more input. - * - * @return 0 if no data is available, 1 otherwise - * @throws IOException - */ - @Override - public int available() throws IOException { - /* - * This is one of the funny code blocks. InflaterInputStream.available - * violates the contract of InputStream.available, which breaks kXML2. - * - * I'm not sure who's to blame, oracle/sun for a broken api or the - * google guys for mixing a sun bug with a xml reader that can't handle - * it.... - * - * Anyway, this simple if breaks suns distorted reality, but helps to - * use the api as intended. - */ - if (inf.needsInput()) { - return 0; - } - return super.available(); - } - -} diff --git a/src/main/java/eu/siacs/conversations/utils/zlib/ZLibOutputStream.java b/src/main/java/eu/siacs/conversations/utils/zlib/ZLibOutputStream.java deleted file mode 100644 index 8b3f5e68..00000000 --- a/src/main/java/eu/siacs/conversations/utils/zlib/ZLibOutputStream.java +++ /dev/null @@ -1,95 +0,0 @@ -package eu.siacs.conversations.utils.zlib; - -import java.io.IOException; -import java.io.OutputStream; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.security.NoSuchAlgorithmException; -import java.util.zip.Deflater; -import java.util.zip.DeflaterOutputStream; - -/** - * <p> - * Android 2.2 includes Java7 FLUSH_SYNC option, which will be used by this - * Implementation, preferable via reflection. The @hide was remove in API level - * 19. This class might thus go away in the future. - * </p> - * <p> - * Please use {@link ZLibOutputStream#SUPPORTED} to check for flush - * compatibility. - * </p> - */ -public class ZLibOutputStream extends DeflaterOutputStream { - - /** - * The reflection based flush method. - */ - - private final static Method method; - /** - * SUPPORTED is true if a flush compatible method exists. - */ - public final static boolean SUPPORTED; - - /** - * Static block to initialize {@link #SUPPORTED} and {@link #method}. - */ - static { - Method m = null; - try { - m = Deflater.class.getMethod("deflate", byte[].class, int.class, - int.class, int.class); - } catch (SecurityException e) { - } catch (NoSuchMethodException e) { - } - method = m; - SUPPORTED = (method != null); - } - - /** - * Create a new ZLib compatible output stream wrapping the given low level - * stream. ZLib compatiblity means we will send a zlib header. - * - * @param os - * OutputStream The underlying stream. - * @throws IOException - * In case of a lowlevel transfer problem. - * @throws NoSuchAlgorithmException - * In case of a {@link Deflater} error. - */ - public ZLibOutputStream(OutputStream os) throws IOException, - NoSuchAlgorithmException { - super(os, new Deflater(Deflater.BEST_COMPRESSION)); - } - - /** - * Flush the given stream, preferring Java7 FLUSH_SYNC if available. - * - * @throws IOException - * In case of a lowlevel exception. - */ - @Override - public void flush() throws IOException { - if (!SUPPORTED) { - super.flush(); - return; - } - try { - int count = 0; - do { - count = (Integer) method.invoke(def, buf, 0, buf.length, 3); - if (count > 0) { - out.write(buf, 0, count); - } - } while (count > 0); - } catch (IllegalArgumentException e) { - throw new IOException("Can't flush"); - } catch (IllegalAccessException e) { - throw new IOException("Can't flush"); - } catch (InvocationTargetException e) { - throw new IOException("Can't flush"); - } - super.flush(); - } - -} diff --git a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java index 2f5994c4..adb96fa2 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java @@ -50,8 +50,6 @@ import eu.siacs.conversations.crypto.sasl.ScramSha1; import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.utils.DNSHelper; -import eu.siacs.conversations.utils.zlib.ZLibInputStream; -import eu.siacs.conversations.utils.zlib.ZLibOutputStream; import eu.siacs.conversations.xml.Element; import eu.siacs.conversations.xml.Tag; import eu.siacs.conversations.xml.TagWriter; @@ -92,7 +90,6 @@ public class XmppConnection implements Runnable { private int smVersion = 3; private SparseArray<String> messageReceipts = new SparseArray<>(); - private boolean enabledCompression = false; private boolean enabledEncryption = false; private boolean enabledCarbons = false; @@ -144,7 +141,6 @@ public class XmppConnection implements Runnable { protected void connect() { Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": connecting"); - enabledCompression = false; enabledEncryption = false; lastConnect = SystemClock.elapsedRealtime(); lastPingSent = SystemClock.elapsedRealtime(); @@ -261,8 +257,6 @@ public class XmppConnection implements Runnable { processStreamFeatures(nextTag); } else if (nextTag.isStart("proceed")) { switchOverToTls(nextTag); - } else if (nextTag.isStart("compressed")) { - switchOverToZLib(nextTag); } else if (nextTag.isStart("success")) { final String challenge = tagReader.readElement(nextTag).getContent(); try { @@ -498,28 +492,6 @@ public class XmppConnection implements Runnable { } } - private void sendCompressionZlib() throws IOException { - Element compress = new Element("compress"); - compress.setAttribute("xmlns", "http://jabber.org/protocol/compress"); - compress.addChild("method").setContent("zlib"); - tagWriter.writeElement(compress); - } - - private void switchOverToZLib(final Tag currentTag) - throws XmlPullParserException, IOException, - NoSuchAlgorithmException { - tagReader.readTag(); // read tag close - tagWriter.setOutputStream(new ZLibOutputStream(tagWriter - .getOutputStream())); - tagReader - .setInputStream(new ZLibInputStream(tagReader.getInputStream())); - - sendStartStream(); - Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": compression enabled"); - enabledCompression = true; - processStream(tagReader.readTag()); - } - private void sendStartTLS() throws IOException { Tag startTLS = Tag.empty("starttls"); startTLS.setAttribute("xmlns", "urn:ietf:params:xml:ns:xmpp-tls"); @@ -601,8 +573,6 @@ public class XmppConnection implements Runnable { this.streamFeatures = tagReader.readElement(currentTag); if (this.streamFeatures.hasChild("starttls") && !enabledEncryption) { sendStartTLS(); - } else if (compressionAvailable()) { - sendCompressionZlib(); } else if (this.streamFeatures.hasChild("register") && account.isOptionSet(Account.OPTION_REGISTER) && enabledEncryption) { @@ -658,28 +628,6 @@ public class XmppConnection implements Runnable { } } - private boolean compressionAvailable() { - if (!this.streamFeatures.hasChild("compression", - "http://jabber.org/features/compress")) - return false; - if (!ZLibOutputStream.SUPPORTED) - return false; - if (!account.isOptionSet(Account.OPTION_USECOMPRESSION)) - return false; - - Element compression = this.streamFeatures.findChild("compression", - "http://jabber.org/features/compress"); - for (Element child : compression.getChildren()) { - if (!"method".equals(child.getName())) - continue; - - if ("zlib".equalsIgnoreCase(child.getContent())) { - return true; - } - } - return false; - } - private List<String> extractMechanisms(Element stream) { ArrayList<String> mechanisms = new ArrayList<>(stream .getChildren().size()); @@ -848,11 +796,9 @@ public class XmppConnection implements Runnable { List<Element> elements = packet.query().getChildren(); for (Element element : elements) { if (element.getName().equals("item")) { - final String jid = element.getAttribute("jid"); - try { - sendServiceDiscoveryInfo(Jid.fromString(jid).toDomainJid()); - } catch (final InvalidJidException ignored) { - // TODO: Handle the case where an external JID is technically invalid? + final Jid jid = element.getAttributeAsJid("jid"); + if (jid != null && !jid.equals(account.getServer())) { + sendServiceDiscoveryInfo(jid); } } } @@ -1149,9 +1095,5 @@ public class XmppConnection implements Runnable { return connection .findDiscoItemByFeature("http://jabber.org/protocol/bytestreams") != null; } - - public boolean compression() { - return connection.enabledCompression; - } } } diff --git a/src/main/java/eu/siacs/conversations/xmpp/jid/Jid.java b/src/main/java/eu/siacs/conversations/xmpp/jid/Jid.java index ebf8a6ed..c40fa0b6 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jid/Jid.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jid/Jid.java @@ -12,25 +12,25 @@ import gnu.inet.encoding.StringprepException; */ public final class Jid { - private final String localpart; - private final String domainpart; - private final String resourcepart; + private final String localpart; + private final String domainpart; + private final String resourcepart; - // It's much more efficient to store the ful JID as well as the parts instead of figuring them - // all out every time (since some characters are displayed but aren't used for comparisons). - private final String displayjid; + // It's much more efficient to store the ful JID as well as the parts instead of figuring them + // all out every time (since some characters are displayed but aren't used for comparisons). + private final String displayjid; - public String getLocalpart() { - return localpart; - } + public String getLocalpart() { + return localpart; + } - public String getDomainpart() { - return IDN.toUnicode(domainpart); - } + public String getDomainpart() { + return IDN.toUnicode(domainpart); + } - public String getResourcepart() { - return resourcepart; - } + public String getResourcepart() { + return resourcepart; + } public static Jid fromSessionID(SessionID id) throws InvalidJidException{ if (id.getUserID().isEmpty()) { @@ -40,152 +40,154 @@ public final class Jid { } } - public static Jid fromString(final String jid) throws InvalidJidException { - return new Jid(jid); - } - - public static Jid fromParts(final String localpart, - final String domainpart, - final String resourcepart) throws InvalidJidException { - String out; - if (localpart == null || localpart.isEmpty()) { - out = domainpart; - } else { - out = localpart + "@" + domainpart; - } - if (resourcepart != null && !resourcepart.isEmpty()) { - out = out + "/" + resourcepart; - } - return new Jid(out); - } - - private Jid(final String jid) throws InvalidJidException { - // Hackish Android way to count the number of chars in a string... should work everywhere. - final int atCount = jid.length() - jid.replace("@", "").length(); - final int slashCount = jid.length() - jid.replace("/", "").length(); - - // Throw an error if there's anything obvious wrong with the JID... - if (jid.isEmpty() || jid.length() > 3071) { - throw new InvalidJidException(InvalidJidException.INVALID_LENGTH); - } - if (atCount > 1 || slashCount > 1 || - jid.startsWith("@") || jid.endsWith("@") || - jid.startsWith("/") || jid.endsWith("/")) { - throw new InvalidJidException(InvalidJidException.INVALID_CHARACTER); - } - - String finaljid; - - final int domainpartStart; - if (atCount == 1) { - final int atLoc = jid.indexOf("@"); - final String lp = jid.substring(0, atLoc); - try { - localpart = Stringprep.nodeprep(lp); - } catch (final StringprepException e) { - throw new InvalidJidException(InvalidJidException.STRINGPREP_FAIL, e); - } - if (localpart.isEmpty() || localpart.length() > 1023) { - throw new InvalidJidException(InvalidJidException.INVALID_PART_LENGTH); - } - domainpartStart = atLoc + 1; - finaljid = lp + "@"; - } else { - localpart = ""; - finaljid = ""; - domainpartStart = 0; - } - - final String dp; - if (slashCount == 1) { - final int slashLoc = jid.indexOf("/"); - final String rp = jid.substring(slashLoc + 1, jid.length()); - try { - resourcepart = Stringprep.resourceprep(rp); - } catch (final StringprepException e) { - throw new InvalidJidException(InvalidJidException.STRINGPREP_FAIL, e); - } - if (resourcepart.isEmpty() || resourcepart.length() > 1023) { - throw new InvalidJidException(InvalidJidException.INVALID_PART_LENGTH); - } - dp = IDN.toUnicode(jid.substring(domainpartStart, slashLoc), IDN.USE_STD3_ASCII_RULES); - finaljid = finaljid + dp + "/" + rp; - } else { - resourcepart = ""; - dp = IDN.toUnicode(jid.substring(domainpartStart, jid.length()), - IDN.USE_STD3_ASCII_RULES); - finaljid = finaljid + dp; - } - - // Remove trailing "." before storing the domain part. - if (dp.endsWith(".")) { - try { - domainpart = IDN.toASCII(dp.substring(0, dp.length() - 1), IDN.USE_STD3_ASCII_RULES); - } catch (final IllegalArgumentException e) { - throw new InvalidJidException(e); - } - } else { - try { - domainpart = IDN.toASCII(dp, IDN.USE_STD3_ASCII_RULES); - } catch (final IllegalArgumentException e) { - throw new InvalidJidException(e); - } - } - - // TODO: Find a proper domain validation library; validate individual parts, separators, etc. - if (domainpart.isEmpty() || domainpart.length() > 1023) { - throw new InvalidJidException(InvalidJidException.INVALID_PART_LENGTH); - } - - this.displayjid = finaljid; - } - - public Jid toBareJid() { - try { - return resourcepart.isEmpty() ? this : fromParts(localpart, domainpart, ""); - } catch (final InvalidJidException e) { - // This should never happen. - return null; - } - } - - public Jid toDomainJid() { - try { - return resourcepart.isEmpty() && localpart.isEmpty() ? this : fromString(getDomainpart()); - } catch (final InvalidJidException e) { - // This should never happen. - return null; - } - } - - @Override - public String toString() { - return displayjid; - } - - @Override - public boolean equals(final Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - final Jid jid = (Jid) o; - - return jid.hashCode() == this.hashCode(); - } - - @Override - public int hashCode() { - int result = localpart.hashCode(); - result = 31 * result + domainpart.hashCode(); - result = 31 * result + resourcepart.hashCode(); - return result; - } - - public boolean hasLocalpart() { - return !localpart.isEmpty(); - } - - public boolean isBareJid() { - return this.resourcepart.isEmpty(); - } + public static Jid fromString(final String jid) throws InvalidJidException { + return new Jid(jid); + } + + public static Jid fromParts(final String localpart, + final String domainpart, + final String resourcepart) throws InvalidJidException { + String out; + if (localpart == null || localpart.isEmpty()) { + out = domainpart; + } else { + out = localpart + "@" + domainpart; + } + if (resourcepart != null && !resourcepart.isEmpty()) { + out = out + "/" + resourcepart; + } + return new Jid(out); + } + + private Jid(final String jid) throws InvalidJidException { + // Hackish Android way to count the number of chars in a string... should work everywhere. + final int atCount = jid.length() - jid.replace("@", "").length(); + final int slashCount = jid.length() - jid.replace("/", "").length(); + + // Throw an error if there's anything obvious wrong with the JID... + if (jid.isEmpty() || jid.length() > 3071) { + throw new InvalidJidException(InvalidJidException.INVALID_LENGTH); + } + + // Go ahead and check if the localpart or resourcepart is empty. + if (jid.startsWith("@") || (jid.endsWith("@") && slashCount == 0) || jid.startsWith("/") || (jid.endsWith("/") && slashCount < 2)) { + throw new InvalidJidException(InvalidJidException.INVALID_CHARACTER); + } + + String finaljid; + + final int domainpartStart; + final int atLoc = jid.indexOf("@"); + final int slashLoc = jid.indexOf("/"); + // If there is no "@" in the JID (eg. "example.net" or "example.net/resource") + // or there are one or more "@" signs but they're all in the resourcepart (eg. "example.net/@/rp@"): + if (atCount == 0 || (atCount > 0 && slashLoc != -1 && atLoc > slashLoc)) { + localpart = ""; + finaljid = ""; + domainpartStart = 0; + } else { + final String lp = jid.substring(0, atLoc); + try { + localpart = Stringprep.nodeprep(lp); + } catch (final StringprepException e) { + throw new InvalidJidException(InvalidJidException.STRINGPREP_FAIL, e); + } + if (localpart.isEmpty() || localpart.length() > 1023) { + throw new InvalidJidException(InvalidJidException.INVALID_PART_LENGTH); + } + domainpartStart = atLoc + 1; + finaljid = lp + "@"; + } + + final String dp; + if (slashCount > 0) { + final String rp = jid.substring(slashLoc + 1, jid.length()); + try { + resourcepart = Stringprep.resourceprep(rp); + } catch (final StringprepException e) { + throw new InvalidJidException(InvalidJidException.STRINGPREP_FAIL, e); + } + if (resourcepart.isEmpty() || resourcepart.length() > 1023) { + throw new InvalidJidException(InvalidJidException.INVALID_PART_LENGTH); + } + dp = IDN.toUnicode(jid.substring(domainpartStart, slashLoc), IDN.USE_STD3_ASCII_RULES); + finaljid = finaljid + dp + "/" + rp; + } else { + resourcepart = ""; + dp = IDN.toUnicode(jid.substring(domainpartStart, jid.length()), + IDN.USE_STD3_ASCII_RULES); + finaljid = finaljid + dp; + } + + // Remove trailing "." before storing the domain part. + if (dp.endsWith(".")) { + try { + domainpart = IDN.toASCII(dp.substring(0, dp.length() - 1), IDN.USE_STD3_ASCII_RULES); + } catch (final IllegalArgumentException e) { + throw new InvalidJidException(e); + } + } else { + try { + domainpart = IDN.toASCII(dp, IDN.USE_STD3_ASCII_RULES); + } catch (final IllegalArgumentException e) { + throw new InvalidJidException(e); + } + } + + // TODO: Find a proper domain validation library; validate individual parts, separators, etc. + if (domainpart.isEmpty() || domainpart.length() > 1023) { + throw new InvalidJidException(InvalidJidException.INVALID_PART_LENGTH); + } + + this.displayjid = finaljid; + } + + public Jid toBareJid() { + try { + return resourcepart.isEmpty() ? this : fromParts(localpart, domainpart, ""); + } catch (final InvalidJidException e) { + // This should never happen. + return null; + } + } + + public Jid toDomainJid() { + try { + return resourcepart.isEmpty() && localpart.isEmpty() ? this : fromString(getDomainpart()); + } catch (final InvalidJidException e) { + // This should never happen. + return null; + } + } + + @Override + public String toString() { + return displayjid; + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final Jid jid = (Jid) o; + + return jid.hashCode() == this.hashCode(); + } + + @Override + public int hashCode() { + int result = localpart.hashCode(); + result = 31 * result + domainpart.hashCode(); + result = 31 * result + resourcepart.hashCode(); + return result; + } + + public boolean hasLocalpart() { + return !localpart.isEmpty(); + } + + public boolean isBareJid() { + return this.resourcepart.isEmpty(); + } } diff --git a/src/main/res/layout/account_row.xml b/src/main/res/layout/account_row.xml index 2d1190a3..60b69090 100644 --- a/src/main/res/layout/account_row.xml +++ b/src/main/res/layout/account_row.xml @@ -10,7 +10,8 @@ android:layout_width="48dp" android:layout_height="48dp" android:layout_alignParentLeft="true" - android:src="@drawable/ic_profile" > + android:src="@drawable/ic_profile" + android:contentDescription="@string/account_image_description"> </ImageView> <LinearLayout diff --git a/src/main/res/layout/activity_edit_account.xml b/src/main/res/layout/activity_edit_account.xml index fa39ed5e..ed83cb9a 100644 --- a/src/main/res/layout/activity_edit_account.xml +++ b/src/main/res/layout/activity_edit_account.xml @@ -27,7 +27,8 @@ android:layout_width="72dp" android:layout_height="72dp" android:layout_alignParentTop="true" - android:layout_marginRight="16dp"/> + android:layout_marginRight="16dp" + android:contentDescription="@string/account_image_description"/> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" @@ -236,7 +237,8 @@ android:background="?android:selectableItemBackground" android:padding="8dp" android:src="@drawable/ic_action_copy" - android:visibility="visible" /> + android:visibility="visible" + android:contentDescription="@string/copy_otr_clipboard_description"/> </RelativeLayout> diff --git a/src/main/res/menu/muc_details.xml b/src/main/res/menu/muc_details.xml index 84b90e17..341d438a 100644 --- a/src/main/res/menu/muc_details.xml +++ b/src/main/res/menu/muc_details.xml @@ -12,6 +12,16 @@ android:title="@string/show_qr_code" android:showAsAction="never" /> <item + android:id="@+id/action_save_as_bookmark" + android:title="@string/save_as_bookmark" + android:orderInCategory="80" + android:showAsAction="never" /> + <item + android:id="@+id/action_delete_bookmark" + android:title="@string/delete_bookmark" + android:orderInCategory="80" + android:showAsAction="never" /> + <item android:id="@+id/action_accounts" android:orderInCategory="90" android:showAsAction="never" diff --git a/src/main/res/values-cs/strings.xml b/src/main/res/values-cs/strings.xml index 6c68fe75..0078b740 100644 --- a/src/main/res/values-cs/strings.xml +++ b/src/main/res/values-cs/strings.xml @@ -22,11 +22,11 @@ <string name="title_activity_start_conversation">Začít konverzaci</string> <string name="title_activity_choose_contact">Vybrat kontakt</string> <string name="just_now">právě teď</string> - <string name="minute_ago">před 1 minutou</string> + <string name="minute_ago">před minutou</string> <string name="minutes_ago">před %d minutami</string> <string name="unread_conversations">nepřečtené konverzace</string> - <string name="sending">odesílám…</string> - <string name="encrypted_message">Dešifruji zprávu. Chvíli strpení…</string> + <string name="sending">odesílám…</string> + <string name="encrypted_message">Dešifruji zprávu. Chvíli strpení…</string> <string name="nick_in_use">Přezdívka se již používá</string> <string name="admin">Administrátor</string> <string name="owner">Vlastník</string> @@ -52,13 +52,13 @@ <string name="send_never">Již se neptat</string> <string name="problem_connecting_to_account">Připojení k účtu se nezdařilo</string> <string name="problem_connecting_to_accounts">Připojení k několika účtům se nezdařilo</string> - <string name="touch_to_fix">Pro nastavení účtů tapni zde</string> + <string name="touch_to_fix">Pro nastavení účtů ťukni sem</string> <string name="attach_file">Přiložit soubor</string> <string name="not_in_roster">Kontakt není v seznamu. Chcete ho přidat?</string> <string name="add_contact">Přidat kontakt</string> <string name="send_failed">doručení selhalo</string> <string name="send_rejected">zamítnuto</string> - <string name="receiving_image">Přijímám obrázek. Chvíli strpení…</string> + <string name="receiving_image">Přijímám obrázek. Chvíli strpení…</string> <string name="preparing_image">Připravuji obrázek na přenos</string> <string name="action_clear_history">Smazat historii</string> <string name="clear_conversation_history">Smaže historii konverzací</string> @@ -78,20 +78,20 @@ <string name="openkeychain_required_long">Konverzace využívá aplikaci třetí strany, <b>OpenKeychain</b>, k šifrování a dešifrování zpráv a ke správě veřejných klíčů.\n\nOpenKeychain je licencován pod GPLv3 a dostupný na F-Droid a Google Play.\n\n<small>(Po instalaci prosím restartujte aplikaci Konverzace.)</small></string> <string name="restart">Restartovat</string> <string name="install">Instalovat</string> - <string name="offering">nabízí…</string> - <string name="waiting">čekám…</string> + <string name="offering">nabízí…</string> + <string name="waiting">čekám…</string> <string name="no_pgp_key">Nebyl nalezen žádný OpenPGP klíč</string> <string name="contact_has_no_pgp_key">Není možné zašifrovat zprávu v aplikaci Konverzace, protože druhá strana neoznamuje svůj veřejný klíč.\n\n<small>Požádejte svůj kontakt ať si nastaví OpenPGP.</small></string> <string name="no_pgp_keys">Nebyly nalezeny žádné OpenPGP klíče</string> <string name="contacts_have_no_pgp_keys">Není možné zašifrovat zprávy v aplikaci Konverzace, protože kontakty neoznamují svůj veřejný klíč.\n\n<small>Požádejte své kontakty ať si nastaví OpenPGP.</small></string> - <string name="encrypted_message_received"><i>Byla přijata šifrovaná zpráva. Tapni pro dešifrování a přečtení.</i></string> - <string name="encrypted_image_received"><i>Byl přijat šifrovaný obrázek. Tapni pro dešifrování a prohlédnutí.</i></string> - <string name="image_file"><i>Byl přijat obrázek. Tapni pro prohlédnutí</i></string> + <string name="encrypted_message_received"><i>Byla přijata šifrovaná zpráva. Ťukni pro dešifrování a přečtení.</i></string> + <string name="encrypted_image_received"><i>Byl přijat šifrovaný obrázek. Ťukni pro dešifrování a prohlédnutí.</i></string> + <string name="image_file"><i>Byl přijat obrázek. Ťukni pro prohlédnutí</i></string> <string name="pref_general">Obecné</string> <string name="pref_xmpp_resource">XMPP zdroj</string> <string name="pref_xmpp_resource_summary">Jméno se kterým se tento klient identifikuje</string> <string name="pref_accept_files">Přijímat soubory</string> - <string name="pref_accept_files_summary">Automaticky přijímat soubory menší než…</string> + <string name="pref_accept_files_summary">Automaticky přijímat soubory menší než…</string> <string name="pref_notification_settings">Nastavení upozornění</string> <string name="pref_notifications">Upozornění</string> <string name="pref_notifications_summary">Upozornit při přijetí nové zprávy</string> @@ -123,7 +123,7 @@ <string name="ask_for_presence_updates">Zažádat o změny stavu</string> <string name="attach_choose_picture">Vybrat obrázek</string> <string name="attach_take_picture">Vyfotit obrázek</string> - <string name="preemptively_grant">Aktivně povolovat vyžádání změnu stavu</string> + <string name="preemptively_grant">Aktivně povolovat vyžádání změn stavu</string> <string name="error_not_an_image_file">Vybraný soubor není obrázek</string> <string name="error_compressing_image">Chyba při konverzi obrázkového souboru</string> <string name="error_file_not_found">Soubor nenalezen</string> @@ -141,6 +141,8 @@ <string name="account_status_regis_conflict">Uživatelské jméno se již používá</string> <string name="account_status_regis_success">Registrace dokončena</string> <string name="account_status_regis_not_sup">Server nepodporuje registrace</string> + <string name="account_status_security_error">Bezpečnostní chyba</string> + <string name="account_status_incompatible_server">Nekompatibilní server</string> <string name="encryption_choice_none">Čistý text</string> <string name="encryption_choice_otr">OTR</string> <string name="encryption_choice_pgp">OpenPGP</string> @@ -213,11 +215,11 @@ <string name="leave">Odejít</string> <string name="contact_added_you">Kontakt přidán do seznamu</string> <string name="add_back">Opět přidat</string> - <string name="contact_has_read_up_to_this_point">%s dočetl až sem</string> + <string name="contact_has_read_up_to_this_point">%s dočetl(a) až sem</string> <string name="publish">Zveřejnit</string> - <string name="touch_to_choose_picture">Tapnout na avatar a vybrat obrázek z galerie</string> + <string name="touch_to_choose_picture">Ťuknout na avatar a vybrat obrázek z galerie</string> <string name="publish_avatar_explanation">Pozor: Každý s povolením vidět změny stavu uvidí tento obrázek.</string> - <string name="publishing">Zveřejňuji…</string> + <string name="publishing">Zveřejňuji…</string> <string name="error_publish_avatar_server_reject">Server odmítl toto zveřejnění</string> <string name="error_publish_avatar_converting">Při konverzi obrázku se něco nezdařilo</string> <string name="error_saving_avatar">Nepodařilo se uložit avatar na disk</string> @@ -227,7 +229,7 @@ <string name="private_message_to">pro %s</string> <string name="send_private_message_to">Zaslat soukromou zprávu pro %s</string> <string name="connect">Připojit</string> - <string name="account_already_exists">Tentou účet již existuje</string> + <string name="account_already_exists">Tento účet již existuje</string> <string name="next">Další</string> <string name="server_info_session_established">Současné sezení vytvořeno</string> <string name="additional_information">Dodatečné informace</string> @@ -238,8 +240,8 @@ <string name="enable">Povolit</string> <string name="conference_requires_password">Konference vyžaduje heslo</string> <string name="enter_password">Vložit heslo</string> - <string name="missing_presence_updates">Kontakt nezasílá informace o změně stavu</string> - <string name="request_presence_updates">Nejdříve si prosím vyžádejte povolení o zasílání změn stavu kontatku.\n\n<small>To bude poté použito pro zjištění jakou aplikaci tento kontakt používá.</small></string> + <string name="missing_presence_updates">Chybí informace o změnách stavu kontaktu</string> + <string name="request_presence_updates">Nejdříve si prosím vyžádejte povolení o zasílání změn stavu kontaktu.\n\n<small>To bude poté použito pro zjištění jakou aplikaci tento kontakt používá.</small></string> <string name="request_now">Ihned vyžádat</string> <string name="delete_fingerprint">Smazat identifikátor</string> <string name="sure_delete_fingerprint">Chcete opravdu smazat tento identifikátor?</string> @@ -250,16 +252,88 @@ <string name="pref_force_encryption_summary">Vždy zasílat šifrované zprávy (mimo konference)</string> <string name="pref_dont_save_encrypted">Neukládat šifrované zprávy</string> <string name="pref_dont_save_encrypted_summary">Varování: Toto může vést ke ztrátě zpráv</string> + <string name="pref_enable_legacy_ssl">Povolit zastaralé SSL</string> + <string name="pref_enable_legacy_ssl_summary">Povolí SSLv3 podporu pro zastaralé servery. Varování: SSLv3 není již považováno za bezpečné.</string> <string name="pref_expert_options">Expertní nastavení</string> <string name="pref_expert_options_summary">S tímto zacházejte velmi opatrně</string> - <string name="pref_use_larger_font">Zvětšit velikost písma</string> - <string name="pref_use_larger_font_summary">Použít větší písmo v celé aplikaci</string> + <string name="title_activity_about">O aplikaci Conversations</string> + <string name="pref_about_conversations_summary">Informace o sestavení a licenci</string> + <string name="pref_use_larger_font">Zvětšit písmo</string> + <string name="pref_use_larger_font_summary">Používat v celé aplikaci větší velikost písma</string> <string name="pref_use_send_button_to_indicate_status">Tlačítko pro odeslání zobrazuje stav</string> <string name="pref_use_indicate_received">Požadovat oznámení o přijetí</string> - <string name="pref_use_indicate_received_summary">Přijaté zprávy budou označeny zeleně. Toto nemusí vždy plně fungovat.</string> - <string name="pref_use_send_button_to_indicate_status_summary">Obarvit tlačítko pro odeslání barvou stavu kontaktu</string> + <string name="pref_use_indicate_received_summary">Přijaté zprávy budou označeny zeleně, pokud je funkce podporována</string> + <string name="pref_use_send_button_to_indicate_status_summary">Obarvit tlačítko odesílání barvou indikující stavu kontaktu</string> <string name="pref_expert_options_other">Další</string> <string name="pref_conference_name">Jméno konference</string> <string name="pref_conference_name_summary">Pro identifikaci konferencí použít téma místnosti místo jejího JID</string> - + <string name="toast_message_otr_fingerprint">OTR otisk zkopírován do schránky!</string> + <string name="conference_banned">Vstup do konference byl zakázán</string> + <string name="conference_members_only">Tato konference je pouze pro členy</string> + <string name="conference_kicked">Vykopli tě z této konference</string> + <string name="using_account">za použití účtu %s</string> + <string name="checking_image">Ověřuji obrázek na HTTP hostiteli</string> + <string name="image_file_deleted">Obrázek byl smazán</string> + <string name="not_connected_try_again">Bez připojení. Zkus znovu později</string> + <string name="check_image_filesize">Ověřit velikost obrázku</string> + <string name="message_options">Možnosti zpráv</string> + <string name="copy_text">Zkopírovat text</string> + <string name="share_image">Sdílet obrázek</string> + <string name="copy_original_url">Kopírovat originální URL</string> + <string name="send_again">Poslat znovu</string> + <string name="image_url">URL obrázku</string> + <string name="message_text">Text zprávy</string> + <string name="url_copied_to_clipboard">URL zkopírováno do schránky</string> + <string name="message_copied_to_clipboard">Zpráva zkopírována do schránky</string> + <string name="image_transmission_failed">Přenos obrázku selhal</string> + <string name="scan_qr_code">Skenovat QR kód</string> + <string name="show_qr_code">Zobrazit QR kód</string> + <string name="account_details">Detaily účtu</string> + <string name="verify_otr">Ověřit OTR</string> + <string name="remote_fingerprint">Vzdálený otisk</string> + <string name="scan">skenovat</string> + <string name="or_touch_phones">(nebo dotykové telefony)</string> + <string name="smp">Socialist Millionaire Protocol</string> + <string name="shared_secret_hint">Nápověda nebo Otázka</string> + <string name="shared_secret_secret">Sdílené tajemství</string> + <string name="confirm">Potvrdit</string> + <string name="in_progress">Probíhá</string> + <string name="respond">Odpovědět</string> + <string name="failed">Selhalo</string> + <string name="secrets_do_not_match">Tajemství se neshodují</string> + <string name="try_again">Zkusit znovu</string> + <string name="finish">Dokončit</string> + <string name="verified">Ověřeno!</string> + <string name="smp_requested">Kontakt zažádal o ověření SMP</string> + <string name="no_otr_session_found">Nebylo nalezeno platné OTR sezení!</string> + <string name="conversations_foreground_service">Conversations</string> + <string name="touch_to_disable">Ťukni pro vypnutí služby v popředí</string> + <string name="pref_keep_foreground_service">Ponechat službu v popředí</string> + <string name="pref_keep_foreground_service_summary">Zamezit operačnímu systému v ukončení připojení</string> + <string name="choose_file">Vybrat soubor</string> + <string name="receiving_file">Přijímám %1$s soubor (%2$d%% přeneseno)</string> + <string name="download_file">Stáhnout %s soubor</string> + <string name="open_file">Otevřít %s soubor</string> + <string name="sending_file">odesílám (%1$d%% přeneseno)</string> + <string name="preparing_file">Příprava souboru na přenos</string> + <string name="file_offered_for_download">Soubor nabídnut ke stažení</string> + <string name="file">%s soubor</string> + <string name="cancel_transmission">Zrušit přenos</string> + <string name="file_transmission_failed">přenos souboru selhal</string> + <string name="file_deleted">Soubor byl smazán</string> + <string name="no_application_found_to_open_file">Nebyla nalezena aplikace umožňující otevření souboru</string> + <string name="could_not_verify_fingerprint">Ověření otisku se nezdařilo</string> + <string name="manually_verify">Ruční ověření</string> + <string name="are_you_sure_verify_fingerprint">Opravdu si přejete ověřit OTR otisk kontaktu?</string> + <string name="pref_show_dynamic_tags">Zobrazit dynamické tagy</string> + <string name="pref_show_dynamic_tags_summary">Zobrazit tagy pro čtení pod kontakty</string> + <string name="enable_notifications">Povolit upozornění</string> + <string name="conference_with">Vytvořit konferenci s…</string> + <string name="no_conference_server_found">Nebyl nalezen konferenční server</string> + <string name="conference_creation_failed">Vytvoření konference selhalo!</string> + <string name="conference_created">Konference vytvořena!</string> + <string name="secret_accepted">Tajemství souhlasí!</string> + <string name="reset">Reset</string> + <string name="account_image_description">Avatar účtu</string> + <string name="copy_otr_clipboard_description">Zkopírovat otisk OTR do schránky</string> </resources> diff --git a/src/main/res/values-de/strings.xml b/src/main/res/values-de/strings.xml index 91a2030d..cade782a 100644 --- a/src/main/res/values-de/strings.xml +++ b/src/main/res/values-de/strings.xml @@ -58,7 +58,7 @@ <string name="add_contact">Kontakt hinzufügen</string> <string name="send_failed">Zustellung nicht erfolgreich</string> <string name="send_rejected">abgelehnt</string> - <string name="receiving_image">Empfange Bild. Bitte warten…</string> + <string name="receiving_image">Empfange Bild (%1$d%% heruntergeladen)</string> <string name="preparing_image">Bereite Bild für die Übertragung vor</string> <string name="action_clear_history">Verlauf löschen</string> <string name="clear_conversation_history">Unterhaltungsverlauf löschen</string> @@ -324,12 +324,16 @@ <string name="no_application_found_to_open_file">Keine Anwendung zum Öffnen der Datei gefunden</string> <string name="could_not_verify_fingerprint">Kann Fingerabdruck nicht überprüfen</string> <string name="manually_verify">Manuell überprüfen</string> - <string name="are_you_sure_verify_fingerprint">Bist du sicher, dass du die OTR Fingerabdrücke des Kontakts überprüfen willst?</string> + <string name="are_you_sure_verify_fingerprint">Bist du sicher, dass du die OTR-Fingerabdrücke des Kontakts überprüfen willst?</string> <string name="pref_show_dynamic_tags">Dynamische Tags anzeigen</string> - <string name="pref_show_dynamic_tags_summary">Zeige schreibgeschützte Tags Unterhalb der Kontakte</string> + <string name="pref_show_dynamic_tags_summary">Zeige schreibgeschützte Tags unterhalb der Kontakte</string> <string name="enable_notifications">Aktiviere Benachrichtigungen</string> <string name="conference_with">Starte Konferenze mit…</string> <string name="no_conference_server_found">Konferenz-Server kann nicht gefunden werden</string> <string name="conference_creation_failed">Starten der Konferenz fehlgeschlagen!</string> <string name="conference_created">Konferenz erstellt!</string> + <string name="secret_accepted">Schlüssel akzeptiert!</string> + <string name="reset">Zurücksetzen</string> + <string name="account_image_description">Konto-Avatar</string> + <string name="copy_otr_clipboard_description">OTR-Fingerabdruck in Zwischenablage kopieren</string> </resources> diff --git a/src/main/res/values-es/strings.xml b/src/main/res/values-es/strings.xml index 96dec637..792f7671 100644 --- a/src/main/res/values-es/strings.xml +++ b/src/main/res/values-es/strings.xml @@ -188,11 +188,11 @@ <string name="last_seen_days">Visto última vez hace %d días</string> <string name="never_seen">Nunca visto</string> <string name="install_openkeychain">Mensaje encriptado. Por favor instala OpenKeychain para desencriptar.</string> - <string name="unknown_otr_fingerprint">Clave OTR desconocida</string> + <string name="unknown_otr_fingerprint">Huella digital OTR desconocida</string> <string name="openpgp_messages_found">Encontrado mensaje encriptado con OpenPGP</string> <string name="reception_failed">Error al recibir</string> - <string name="your_fingerprint">Tu clave</string> - <string name="otr_fingerprint">Clave OTR</string> + <string name="your_fingerprint">Tu huella digital</string> + <string name="otr_fingerprint">Huella digital OTR</string> <string name="verify">Verificar</string> <string name="decrypt">Desencriptar</string> <string name="conferences">Conferencias</string> @@ -243,8 +243,8 @@ <string name="missing_presence_updates">Suscripción de actualizaciones de presencia del contacto perdida</string> <string name="request_presence_updates">Por favor, solicita la suscripción de presencia a tu contacto primero.\n\n<small>Esto será usado para determinar qué cliente(s) está usando tu contacto.</small></string> <string name="request_now">Solicitar ahora</string> - <string name="delete_fingerprint">Eliminar Clave OTR</string> - <string name="sure_delete_fingerprint">¿Estás seguro que quieres eliminar la clave OTR?</string> + <string name="delete_fingerprint">Eliminar huella digital OTR</string> + <string name="sure_delete_fingerprint">¿Estás seguro que quieres eliminar esta huella digital OTR?</string> <string name="ignore">Ignorar</string> <string name="without_mutual_presence_updates"><b>Aviso:</b> Enviando esto sin suscripción de presencia por ambas partes podría causar problemas inesperados.\n\n<small>Verficia la suscripción de presencia en detalles del contacto.</small></string> <string name="pref_encryption_settings">Ajustes de encriptación</string> @@ -267,7 +267,7 @@ <string name="pref_expert_options_other">Otros</string> <string name="pref_conference_name">Nombre de conferencia</string> <string name="pref_conference_name_summary">Usar el asunto de la conferencia en lugar del identificador jabber como nombre de conferencia</string> - <string name="toast_message_otr_fingerprint">¡Clave OTR copiada en el portapapeles!</string> + <string name="toast_message_otr_fingerprint">¡Huella digital OTR copiada al portapapeles!</string> <string name="conference_banned">Tu entrada a esta conferencia ha sido prohibida</string> <string name="conference_members_only">Esta conferencia es solo para miembros</string> <string name="conference_kicked">Has sido expulsado de esta conferencia</string> @@ -290,7 +290,7 @@ <string name="show_qr_code">Mostrar código QR</string> <string name="account_details">Detalles de la cuenta</string> <string name="verify_otr">Verificar OTR</string> - <string name="remote_fingerprint">Clave OTR remota</string> + <string name="remote_fingerprint">Huella digital remota</string> <string name="scan">escanear</string> <string name="or_touch_phones">(o une los teléfonos)</string> <string name="smp">Protocolo del Socialista Millonario</string> @@ -307,8 +307,8 @@ <string name="smp_requested">El contacto solicita verificación SMP</string> <string name="no_otr_session_found">¡No se ha encontrado una sesión OTR válida!</string> <string name="conversations_foreground_service">Conversations</string> - <string name="touch_to_disable">Pulsa para deshabilitar servicio en segundo plano</string> - <string name="pref_keep_foreground_service">Mantener servicio en segundo plano</string> + <string name="touch_to_disable">Pulsa para deshabilitar servicio en primer plano</string> + <string name="pref_keep_foreground_service">Mantener servicio en primer plano</string> <string name="pref_keep_foreground_service_summary">Previene que el sistema cierre la conexión</string> <string name="choose_file">Seleccionar archivo</string> <string name="receiving_file">Recibiendo archivo %1$s (%2$d%% completedo)</string> @@ -334,4 +334,6 @@ <string name="conference_created">¡Conferencia creada!</string> <string name="secret_accepted">¡Secreto aceptado!</string> <string name="reset">Reinicializar</string> + <string name="account_image_description">Imagen de perfil</string> + <string name="copy_otr_clipboard_description">Copiar huella digital OTR al portapapeles</string> </resources> diff --git a/src/main/res/values-eu/strings.xml b/src/main/res/values-eu/strings.xml index 75452741..41f3793b 100644 --- a/src/main/res/values-eu/strings.xml +++ b/src/main/res/values-eu/strings.xml @@ -328,5 +328,11 @@ <string name="pref_show_dynamic_tags">Etiketa dinamikoak erakutsi</string> <string name="pref_show_dynamic_tags_summary">Irakurtzeko soilik diren etiketak erakutsi kontaktuen azpian</string> <string name="enable_notifications">Jakinarazpenak gaitu</string> + <string name="conference_with">Konferentzia sortu honekin…</string> + <string name="no_conference_server_found">Ez da konferentzia zerbitzaririk aurkitu</string> + <string name="conference_creation_failed">Konferentzia sortzeak huts egin du!</string> + <string name="conference_created">Konferentzia sortu da!</string> + <string name="secret_accepted">Sekretua onartu da!</string> + <string name="reset">Berrezarri</string> </resources> diff --git a/src/main/res/values-it/arrays.xml b/src/main/res/values-it/arrays.xml index 491c4438..60c0b04f 100644 --- a/src/main/res/values-it/arrays.xml +++ b/src/main/res/values-it/arrays.xml @@ -25,7 +25,7 @@ <item>un\'ora</item> <item>2 ore</item> <item>8 ore</item> - <item>fino avviso ulteriore</item> + <item>fino a nuovo avviso</item> </string-array> <integer-array name="mute_options_durations"> diff --git a/src/main/res/values-it/strings.xml b/src/main/res/values-it/strings.xml index 3b613e9d..dab7471d 100644 --- a/src/main/res/values-it/strings.xml +++ b/src/main/res/values-it/strings.xml @@ -40,18 +40,18 @@ <string name="start_conversation">Inizia Conversazione</string> <string name="invite_contact">Invita Contatto</string> <string name="contacts">Contatti</string> - <string name="cancel">Cancella</string> + <string name="cancel">Annulla</string> <string name="add">Aggiungi</string> <string name="edit">Modifica</string> <string name="delete">Elimina</string> <string name="save">Salva</string> <string name="ok">OK</string> - <string name="crash_report_title">Conversations è crashato</string> + <string name="crash_report_title">Errore di Conversations</string> <string name="crash_report_message">Se scegli di inviare una segnalazione dell\'errore aiuterai lo sviluppo di Conversations\n<b>Attenzione:</b> Questo utilizzerà il tuo account XMPP per inviare la segnalazione agli sviluppatori.</string> <string name="send_now">Invia adesso</string> <string name="send_never">Non chiedere mai più</string> - <string name="problem_connecting_to_account">Impossibile collegarsi all\'utente</string> - <string name="problem_connecting_to_accounts">Impossibile collegarsi a più utenti</string> + <string name="problem_connecting_to_account">Impossibile collegarsi tramite questo utente</string> + <string name="problem_connecting_to_accounts">Impossibile collegarsi tramite più utenti</string> <string name="touch_to_fix">Tocca qui per gestire i tuoi utenti</string> <string name="attach_file">Allega file</string> <string name="not_in_roster">Il contatto non è nella tua lista. Vuoi aggiungerlo?</string> @@ -66,10 +66,10 @@ <string name="delete_messages">Elimina messaggi</string> <string name="also_end_conversation">Termina questa conversazione in seguito</string> <string name="choose_presence">Choose presence to contact</string> - <string name="send_plain_text_message">Invia messaggio di testo semplice</string> - <string name="send_otr_message">Invia messaggio cifrato con OTR</string> - <string name="send_pgp_message">Invia messaggio cifrato con OpenPGP</string> - <string name="your_nick_has_been_changed">Il tuo nome utente èstato cambiato</string> + <string name="send_plain_text_message">Messaggio non cifrato</string> + <string name="send_otr_message">Messaggio OTR</string> + <string name="send_pgp_message">Messaggio OpenPGP</string> + <string name="your_nick_has_been_changed">Il tuo nome utente è stato cambiato</string> <string name="download_image">Scarica Immagine</string> <string name="image_offered_for_download"><i>Immagine disponibile per il download</i></string> <string name="send_unencrypted">Invia non cifrato</string> @@ -141,6 +141,8 @@ <string name="account_status_regis_conflict">Nome utente già in uso</string> <string name="account_status_regis_success">Registrazione completata</string> <string name="account_status_regis_not_sup">Il Server non supporta la registrazione</string> + <string name="account_status_security_error">Errore di sicurezza</string> + <string name="account_status_incompatible_server">Server non compatibile</string> <string name="encryption_choice_none">Testo semplice</string> <string name="encryption_choice_otr">OTR</string> <string name="encryption_choice_pgp">OpenPGP</string> @@ -250,11 +252,88 @@ <string name="pref_force_encryption_summary">Manda sempre messaggi cifrati (ad eccezione delle conferenze)</string> <string name="pref_dont_save_encrypted">Non salvare i messaggi cifrati</string> <string name="pref_dont_save_encrypted_summary">Attenzione: Questo potrebbe comportare la perdita di messaggi</string> + <string name="pref_enable_legacy_ssl">Abilita il vecchio SSL</string> + <string name="pref_enable_legacy_ssl_summary">Abilita il supporto per i server SSLv3. Attenzione: SSLv3 è considerato insicuro.</string> <string name="pref_expert_options">Opzioni da Esperto</string> <string name="pref_expert_options_summary">Fai attenzione con queste impostazioni</string> + <string name="title_activity_about">Info su Conversations</string> + <string name="pref_about_conversations_summary">Informazioni sulla licenza</string> <string name="pref_use_larger_font">Aumenta la dimensione dei font</string> <string name="pref_use_larger_font_summary">Usa font più grandi in tutta l\'app</string> <string name="pref_use_send_button_to_indicate_status">Il pulsante di invio indica lo stato</string> <string name="pref_use_send_button_to_indicate_status_summary">Colora il pulsante di invio per indicare lo stato di un contatto</string> - + <string name="pref_use_indicate_received">Richiedi la ricevuta di ritorno</string> + <string name="pref_use_indicate_received_summary">I messaggi ricevuti verranno contrassegnati con una spunta verde se supportato</string> + <string name="pref_expert_options_other">Altro</string> + <string name="pref_conference_name">Nome della conferenza</string> + <string name="pref_conference_name_summary">Usa il soggetto della stanza al posto del JID per identificare le conferenze</string> + <string name="toast_message_otr_fingerprint">Impronta OTR copiata!</string> + <string name="conference_banned">Sei stato bandito da questa conferenza</string> + <string name="conference_members_only">Questa conferenza è solo per membri</string> + <string name="conference_kicked">Sei stato buttato fuori dalla conferenza</string> + <string name="using_account">usando l\'utente %s</string> + <string name="checking_image">Controlla immagine su HTTP</string> + <string name="image_file_deleted">Il file dell\'immagine è stato cancellato</string> + <string name="not_connected_try_again">Non sei connesso. Riprova più tardi</string> + <string name="check_image_filesize">Controlla le dimensioni dell\'immagine</string> + <string name="message_options">Opzioni del messaggio</string> + <string name="copy_text">Copia testo</string> + <string name="share_image">Condividi immagine</string> + <string name="copy_original_url">Copia URL originale</string> + <string name="send_again">Invia di nuovo</string> + <string name="image_url">URL immagine</string> + <string name="message_text">Messaggio di testo</string> + <string name="url_copied_to_clipboard">URL copiato</string> + <string name="message_copied_to_clipboard">Messaggio copiato</string> + <string name="image_transmission_failed">Trasmissione dell\'immagine fallita</string> + <string name="scan_qr_code">Scansiona codice QR</string> + <string name="show_qr_code">Mostra codice QR</string> + <string name="account_details">Dettagli utente</string> + <string name="verify_otr">Verifica OTR</string> + <string name="remote_fingerprint">Impronta remota</string> + <string name="scan">scan</string> + <string name="or_touch_phones">(o fai toccare i dispositivi)</string> + <string name="smp">Socialist Millionaire Protocol</string> + <string name="shared_secret_hint">Suggerimento o Domanda</string> + <string name="shared_secret_secret">Segreto condiviso</string> + <string name="confirm">Conferma</string> + <string name="in_progress">In corso</string> + <string name="respond">Rispondi</string> + <string name="failed">Fallito</string> + <string name="secrets_do_not_match">I segreti non corrispondono</string> + <string name="try_again">Prova di nuovo</string> + <string name="finish">Fine</string> + <string name="verified">Verificato!</string> + <string name="smp_requested">Il contatto ha richiesto la verifica SMP</string> + <string name="no_otr_session_found">Non è stata trovata nessuna sessione OTR valida!</string> + <string name="conversations_foreground_service">Conversations</string> + <string name="touch_to_disable">Tocca per disabilitare il servizio in primo piano</string> + <string name="pref_keep_foreground_service">Mantieni il servizio in primo piano</string> + <string name="pref_keep_foreground_service_summary">Evita che il sistema operativo chiuda la connessione</string> + <string name="choose_file">Scegli file</string> + <string name="receiving_file">Ricezione di %1$s file (%2$d%% completato)</string> + <string name="download_file">Scarica %s file</string> + <string name="open_file">Apri %s file</string> + <string name="sending_file">invio (%1$d%% completato)</string> + <string name="preparing_file">Preparazione alla trasmissione del file</string> + <string name="file_offered_for_download">Offerto un file da scaricare</string> + <string name="file">%s file</string> + <string name="cancel_transmission">Annulla trasmissione</string> + <string name="file_transmission_failed">trasmissione del file fallita</string> + <string name="file_deleted">Il file è stato eliminato</string> + <string name="no_application_found_to_open_file">Nessuna applicazione trovata per aprire il file</string> + <string name="could_not_verify_fingerprint">Impronta non verificata</string> + <string name="manually_verify">Verifica manuale</string> + <string name="are_you_sure_verify_fingerprint">Sei sicuro di voler verificare l\'impronta OTR del contatto?</string> + <string name="pref_show_dynamic_tags">Mostra tag dinamici</string> + <string name="pref_show_dynamic_tags_summary">Mostra tag in sola lettura sotto i contatti</string> + <string name="enable_notifications">Abilita le notifiche</string> + <string name="conference_with">Crea conferenza con…</string> + <string name="no_conference_server_found">Nessun server per conferenza trovato</string> + <string name="conference_creation_failed">Creazione della conferenza fallita!</string> + <string name="conference_created">Conferenza creata!</string> + <string name="secret_accepted">Segreto accettato!</string> + <string name="reset">Reset</string> + <string name="account_image_description">Avatar utente</string> + <string name="copy_otr_clipboard_description">Copia impronta OTR</string> </resources> diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index 7e235f68..6b639452 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -358,4 +358,6 @@ <string name="conference_created">Conference created!</string> <string name="secret_accepted">Secret accepted!</string> <string name="reset">Reset</string> + <string name="account_image_description">Account avatar</string> + <string name="copy_otr_clipboard_description">Copy OTR fingerprint to clipboard</string> </resources> |