diff options
Diffstat (limited to 'src/main')
25 files changed, 410 insertions, 97 deletions
diff --git a/src/main/java/eu/siacs/conversations/crypto/OtrService.java b/src/main/java/eu/siacs/conversations/crypto/OtrService.java index 1804704eb..af11756f6 100644 --- a/src/main/java/eu/siacs/conversations/crypto/OtrService.java +++ b/src/main/java/eu/siacs/conversations/crypto/OtrService.java @@ -122,7 +122,7 @@ public class OtrService extends OtrCryptoEngineImpl implements OtrEngineHost { @Override public String getFallbackMessage(SessionID arg0) { - return "I would like to start a private (OTR encrypted) conversation but your client doesn’t seem to support that"; + return MessageGenerator.OTR_FALLBACK_MESSAGE; } @Override diff --git a/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java b/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java index aac814433..9e54c0c7d 100644 --- a/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java +++ b/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java @@ -75,7 +75,9 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded { @Override public void onAdvancedStreamFeaturesAvailable(Account account) { - if (account.getXmppConnection() != null && account.getXmppConnection().getFeatures().pep()) { + if (Config.supportOmemo() + && account.getXmppConnection() != null + && account.getXmppConnection().getFeatures().pep()) { publishBundlesIfNeeded(true, false); } else { Log.d(Config.LOGTAG,account.getJid().toBareJid()+": skipping OMEMO initialization"); diff --git a/src/main/java/eu/siacs/conversations/entities/Account.java b/src/main/java/eu/siacs/conversations/entities/Account.java index a708b0ce8..2f573c896 100644 --- a/src/main/java/eu/siacs/conversations/entities/Account.java +++ b/src/main/java/eu/siacs/conversations/entities/Account.java @@ -99,7 +99,8 @@ public class Account extends AbstractEntity { INCOMPATIBLE_SERVER(true), TOR_NOT_AVAILABLE(true), BIND_FAILURE(true), - HOST_UNKNOWN(true); + HOST_UNKNOWN(true), + REGISTRATION_PLEASE_WAIT(true); private final boolean isError; @@ -149,6 +150,8 @@ public class Account extends AbstractEntity { return R.string.account_status_bind_failure; case HOST_UNKNOWN: return R.string.account_status_host_unknown; + case REGISTRATION_PLEASE_WAIT: + return R.string.registration_please_wait; default: return R.string.account_status_unknown; } diff --git a/src/main/java/eu/siacs/conversations/entities/Bookmark.java b/src/main/java/eu/siacs/conversations/entities/Bookmark.java index fd6a5dab9..c5c4ff5dd 100644 --- a/src/main/java/eu/siacs/conversations/entities/Bookmark.java +++ b/src/main/java/eu/siacs/conversations/entities/Bookmark.java @@ -50,9 +50,8 @@ public class Bookmark extends Element implements ListItem { @Override public String getDisplayName() { - if (this.mJoinedConversation != null - && (this.mJoinedConversation.getMucOptions().getSubject() != null)) { - return this.mJoinedConversation.getMucOptions().getSubject(); + if (this.mJoinedConversation != null) { + return this.mJoinedConversation.getName(); } else if (getBookmarkName() != null) { return getBookmarkName(); } else { diff --git a/src/main/java/eu/siacs/conversations/entities/MucOptions.java b/src/main/java/eu/siacs/conversations/entities/MucOptions.java index d4a15ea7a..5ec527ef2 100644 --- a/src/main/java/eu/siacs/conversations/entities/MucOptions.java +++ b/src/main/java/eu/siacs/conversations/entities/MucOptions.java @@ -18,6 +18,8 @@ import eu.siacs.conversations.xmpp.pep.Avatar; @SuppressLint("DefaultLocale") public class MucOptions { + private boolean mAutoPushConfiguration = true; + public Account getAccount() { return this.conversation.getAccount(); } @@ -39,6 +41,14 @@ public class MucOptions { } } + public void flagNoAutoPushConfiguration() { + mAutoPushConfiguration = false; + } + + public boolean autoPushConfiguration() { + return mAutoPushConfiguration; + } + public enum Affiliation { OWNER("owner", 4, R.string.owner), ADMIN("admin", 3, R.string.admin), @@ -118,6 +128,7 @@ public class MucOptions { public static final String STATUS_CODE_ROOM_CONFIG_CHANGED = "104"; public static final String STATUS_CODE_SELF_PRESENCE = "110"; + public static final String STATUS_CODE_ROOM_CREATED = "201"; public static final String STATUS_CODE_BANNED = "301"; public static final String STATUS_CODE_CHANGED_NICK = "303"; public static final String STATUS_CODE_KICKED = "307"; diff --git a/src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java b/src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java index cc974e5fb..b80a0be19 100644 --- a/src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java +++ b/src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java @@ -12,6 +12,7 @@ import java.util.List; import java.util.Locale; import java.util.TimeZone; +import eu.siacs.conversations.Config; import eu.siacs.conversations.crypto.axolotl.AxolotlService; import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.utils.PhoneHelper; @@ -32,8 +33,7 @@ public abstract class AbstractGenerator { "http://jabber.org/protocol/nick+notify", "urn:xmpp:ping", "jabber:iq:version", - "http://jabber.org/protocol/chatstates", - AxolotlService.PEP_DEVICE_LIST_NOTIFY}; + "http://jabber.org/protocol/chatstates"}; private final String[] MESSAGE_CONFIRMATION_FEATURES = { "urn:xmpp:chat-markers:0", "urn:xmpp:receipts" @@ -105,6 +105,9 @@ public abstract class AbstractGenerator { if (mXmppConnectionService.allowMessageCorrection()) { features.addAll(Arrays.asList(MESSAGE_CORRECTION_FEATURES)); } + if (Config.supportOmemo()) { + features.add(AxolotlService.PEP_DEVICE_LIST_NOTIFY); + } Collections.sort(features); return features; } diff --git a/src/main/java/eu/siacs/conversations/generator/IqGenerator.java b/src/main/java/eu/siacs/conversations/generator/IqGenerator.java index 4962135e3..16af338c6 100644 --- a/src/main/java/eu/siacs/conversations/generator/IqGenerator.java +++ b/src/main/java/eu/siacs/conversations/generator/IqGenerator.java @@ -1,6 +1,7 @@ package eu.siacs.conversations.generator; +import android.os.Bundle; import android.util.Base64; import android.util.Log; @@ -344,4 +345,13 @@ public class IqGenerator extends AbstractGenerator { packet.query("http://jabber.org/protocol/muc#admin").addChild("item").setAttribute("affiliation",affiliation); return packet; } + + public static Bundle defaultRoomConfiguration() { + Bundle options = new Bundle(); + options.putString("muc#roomconfig_persistentroom", "1"); + options.putString("muc#roomconfig_membersonly", "1"); + options.putString("muc#roomconfig_publicroom", "0"); + options.putString("muc#roomconfig_whois", "anyone"); + return options; + } } diff --git a/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java b/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java index 0e7a8ce6e..823af397a 100644 --- a/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java +++ b/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java @@ -9,6 +9,7 @@ import java.util.Date; import java.util.Locale; import java.util.TimeZone; +import eu.siacs.conversations.crypto.axolotl.AxolotlService; import eu.siacs.conversations.crypto.axolotl.XmppAxolotlMessage; import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Conversation; @@ -20,6 +21,10 @@ import eu.siacs.conversations.xmpp.jid.Jid; import eu.siacs.conversations.xmpp.stanzas.MessagePacket; public class MessageGenerator extends AbstractGenerator { + public static final String OTR_FALLBACK_MESSAGE = "I would like to start a private (OTR encrypted) conversation but your client doesn’t seem to support that"; + private static final String OMEMO_FALLBACK_MESSAGE = "I sent you an OMEMO encrypted message but your client doesn’t seem to support that. Find more information on https://conversations.im/omemo"; + private static final String PGP_FALLBACK_MESSAGE = "I sent you a PGP encrypted message but your client doesn’t seem to support that."; + public MessageGenerator(XmppConnectionService service) { super(service); } @@ -67,11 +72,18 @@ public class MessageGenerator extends AbstractGenerator { if (axolotlMessage == null) { return null; } + if (!recipientSupportsOmemo(message)) { + packet.setBody(OMEMO_FALLBACK_MESSAGE); + } packet.setAxolotlMessage(axolotlMessage.toElement()); packet.addChild("store", "urn:xmpp:hints"); return packet; } + private static boolean recipientSupportsOmemo(Message message) { + return message.getContact().getPresences().allOrNonSupport(AxolotlService.PEP_DEVICE_LIST_NOTIFY); + } + public static void addMessageHints(MessagePacket packet) { packet.addChild("private", "urn:xmpp:carbons:2"); packet.addChild("no-copy", "urn:xmpp:hints"); @@ -116,7 +128,7 @@ public class MessageGenerator extends AbstractGenerator { public MessagePacket generatePgpChat(Message message) { MessagePacket packet = preparePacket(message); - packet.setBody("This is an XEP-0027 encrypted message"); + packet.setBody(PGP_FALLBACK_MESSAGE); if (message.getEncryption() == Message.ENCRYPTION_DECRYPTED) { packet.addChild("x", "jabber:x:encrypted").setContent(message.getEncryptedBody()); } else if (message.getEncryption() == Message.ENCRYPTION_PGP) { diff --git a/src/main/java/eu/siacs/conversations/parser/MessageParser.java b/src/main/java/eu/siacs/conversations/parser/MessageParser.java index aac8ee45a..d2f4bf9f5 100644 --- a/src/main/java/eu/siacs/conversations/parser/MessageParser.java +++ b/src/main/java/eu/siacs/conversations/parser/MessageParser.java @@ -369,6 +369,7 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece if ((body != null || pgpEncrypted != null || axolotlEncrypted != null) && !isMucStatusMessage) { Conversation conversation = mXmppConnectionService.findOrCreateConversation(account, counterpart.toBareJid(), isTypeGroupChat, query); + final boolean conversationMultiMode = conversation.getMode() == Conversation.MODE_MULTI; if (isTypeGroupChat) { if (counterpart.getResourcepart().equals(conversation.getMucOptions().getActualNick())) { status = Message.STATUS_SEND_RECEIVED; @@ -388,7 +389,7 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece } Message message; if (body != null && body.startsWith("?OTR") && Config.supportOtr()) { - if (!isForwarded && !isTypeGroupChat && isProperlyAddressed) { + if (!isForwarded && !isTypeGroupChat && isProperlyAddressed && !conversationMultiMode) { message = parseOtrChat(body, from, remoteMsgId, conversation); if (message == null) { return; @@ -401,7 +402,7 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece message = new Message(conversation, pgpEncrypted, Message.ENCRYPTION_PGP, status); } else if (axolotlEncrypted != null && Config.supportOmemo()) { Jid origin; - if (conversation.getMode() == Conversation.MODE_MULTI) { + if (conversationMultiMode) { origin = conversation.getMucOptions().getTrueCounterpart(counterpart); if (origin == null) { Log.d(Config.LOGTAG,"axolotl message in non anonymous conference received"); @@ -429,7 +430,7 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece message.setTime(timestamp); message.setOob(isOob); message.markable = packet.hasChild("markable", "urn:xmpp:chat-markers:0"); - if (conversation.getMode() == Conversation.MODE_MULTI) { + if (conversationMultiMode) { Jid trueCounterpart = conversation.getMucOptions().getTrueCounterpart(counterpart); message.setTrueCounterpart(trueCounterpart); if (trueCounterpart != null) { @@ -452,7 +453,7 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece || replacedMessage.getFingerprint().equals(message.getFingerprint()); final boolean trueCountersMatch = replacedMessage.getTrueCounterpart() != null && replacedMessage.getTrueCounterpart().equals(message.getTrueCounterpart()); - if (fingerprintsMatch && (trueCountersMatch || conversation.getMode() == Conversation.MODE_SINGLE)) { + if (fingerprintsMatch && (trueCountersMatch || !conversationMultiMode)) { Log.d(Config.LOGTAG, "replaced message '" + replacedMessage.getBody() + "' with '" + message.getBody() + "'"); final String uuid = replacedMessage.getUuid(); replacedMessage.setUuid(UUID.randomUUID().toString()); diff --git a/src/main/java/eu/siacs/conversations/parser/PresenceParser.java b/src/main/java/eu/siacs/conversations/parser/PresenceParser.java index ae5d576a6..8a2d444a7 100644 --- a/src/main/java/eu/siacs/conversations/parser/PresenceParser.java +++ b/src/main/java/eu/siacs/conversations/parser/PresenceParser.java @@ -14,6 +14,7 @@ import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.entities.Message; import eu.siacs.conversations.entities.MucOptions; import eu.siacs.conversations.entities.Presence; +import eu.siacs.conversations.generator.IqGenerator; import eu.siacs.conversations.generator.PresenceGenerator; import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.xml.Element; @@ -77,6 +78,15 @@ public class PresenceParser extends AbstractParser implements } else { mucOptions.addUser(user); } + if (codes.contains(MucOptions.STATUS_CODE_ROOM_CREATED) && mucOptions.autoPushConfiguration()) { + Log.d(Config.LOGTAG,mucOptions.getAccount().getJid().toBareJid() + +": room '" + +mucOptions.getConversation().getJid().toBareJid() + +"' created. pushing default configuration"); + mXmppConnectionService.pushConferenceConfiguration(mucOptions.getConversation(), + IqGenerator.defaultRoomConfiguration(), + null); + } if (mXmppConnectionService.getPgpEngine() != null) { Element signed = packet.findChild("x", "jabber:x:signed"); if (signed != null) { diff --git a/src/main/java/eu/siacs/conversations/services/AvatarService.java b/src/main/java/eu/siacs/conversations/services/AvatarService.java index 0ab0db2de..88071f500 100644 --- a/src/main/java/eu/siacs/conversations/services/AvatarService.java +++ b/src/main/java/eu/siacs/conversations/services/AvatarService.java @@ -64,7 +64,7 @@ public class AvatarService implements OnAdvancedStreamFeaturesLoaded { public Bitmap get(final MucOptions.User user, final int size, boolean cachedOnly) { Contact c = user.getContact(); - if (c != null && (c.getProfilePhoto() != null || c.getAvatar() != null)) { + if (c != null && (c.getProfilePhoto() != null || c.getAvatar() != null || user.getAvatar() == null)) { return get(c, size, cachedOnly); } else { return getImpl(user, size, cachedOnly); @@ -380,7 +380,7 @@ public class AvatarService implements OnAdvancedStreamFeaturesLoaded { private boolean drawTile(Canvas canvas, String name, int left, int top, int right, int bottom) { if (name != null) { - final String letter = name.isEmpty() ? "X" : name.substring(0, 1); + final String letter = getFirstLetter(name); final int color = UIHelper.getColorForName(name); drawTile(canvas, letter, color, left, top, right, bottom); return true; @@ -388,6 +388,15 @@ public class AvatarService implements OnAdvancedStreamFeaturesLoaded { return false; } + private static String getFirstLetter(String name) { + for(Character c : name.toCharArray()) { + if (Character.isLetterOrDigit(c)) { + return c.toString(); + } + } + return "X"; + } + private boolean drawTile(Canvas canvas, Uri uri, int left, int top, int right, int bottom) { if (uri != null) { Bitmap bitmap = mXmppConnectionService.getFileBackend() diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 67370e3ff..ad45d8e9a 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -26,6 +26,7 @@ import android.os.SystemClock; import android.preference.PreferenceManager; import android.provider.ContactsContract; import android.security.KeyChain; +import android.util.Base64; import android.util.DisplayMetrics; import android.util.Log; import android.util.LruCache; @@ -1827,6 +1828,9 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa account.pendingConferenceLeaves.remove(conversation); if (account.getStatus() == Account.State.ONLINE) { conversation.resetMucOptions(); + if (onConferenceJoined != null) { + conversation.getMucOptions().flagNoAutoPushConfiguration(); + } conversation.setHasMessagesLeftOnServer(false); fetchConferenceConfiguration(conversation, new OnConferenceConfigurationFetched() { @@ -2030,7 +2034,10 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa return null; } - public void createAdhocConference(final Account account, final Iterable<Jid> jids, final UiCallback<Conversation> callback) { + public void createAdhocConference(final Account account, + final String subject, + final Iterable<Jid> jids, + final UiCallback<Conversation> callback) { Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": creating adhoc conference with " + jids.toString()); if (account.getStatus() == Account.State.ONLINE) { try { @@ -2041,26 +2048,24 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa } return; } - String name = new BigInteger(75, getRNG()).toString(32); - Jid jid = Jid.fromParts(name, server, null); + final Jid jid = Jid.fromParts(new BigInteger(64, getRNG()).toString(Character.MAX_RADIX), server, null); final Conversation conversation = findOrCreateConversation(account, jid, true); joinMuc(conversation, new OnConferenceJoined() { @Override public void onConferenceJoined(final Conversation conversation) { - Bundle options = new Bundle(); - options.putString("muc#roomconfig_persistentroom", "1"); - options.putString("muc#roomconfig_membersonly", "1"); - options.putString("muc#roomconfig_publicroom", "0"); - options.putString("muc#roomconfig_whois", "anyone"); - pushConferenceConfiguration(conversation, options, new OnConferenceOptionsPushed() { + pushConferenceConfiguration(conversation, IqGenerator.defaultRoomConfiguration(), new OnConferenceOptionsPushed() { @Override public void onPushSucceeded() { + if (subject != null && !subject.trim().isEmpty()) { + pushSubjectToConference(conversation, subject.trim()); + } for (Jid invite : jids) { invite(conversation, invite); } if (account.countPresences() > 1) { directInvite(conversation, account.getJid().toBareJid()); } + saveConversationAsBookmark(conversation, subject); if (callback != null) { callback.success(conversation); } @@ -2068,6 +2073,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa @Override public void onPushFailed() { + archiveConversation(conversation); if (callback != null) { callback.error(R.string.conference_creation_failed, conversation); } @@ -3301,6 +3307,21 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa return templates; } + public void saveConversationAsBookmark(Conversation conversation, String name) { + Account account = conversation.getAccount(); + Bookmark bookmark = new Bookmark(account, conversation.getJid().toBareJid()); + if (!conversation.getJid().isBareJid()) { + bookmark.setNick(conversation.getJid().getResourcepart()); + } + if (name != null && !name.trim().isEmpty()) { + bookmark.setBookmarkName(name.trim()); + } + bookmark.setAutojoin(getPreferences().getBoolean("autojoin",true)); + account.getBookmarks().add(bookmark); + pushBookmarks(account); + conversation.setBookmark(bookmark); + } + public interface OnMamPreferencesFetched { void onPreferencesFetched(Element prefs); void onPreferencesFetchFailed(); diff --git a/src/main/java/eu/siacs/conversations/ui/ChooseContactActivity.java b/src/main/java/eu/siacs/conversations/ui/ChooseContactActivity.java index 1698343b0..5156fcca4 100644 --- a/src/main/java/eu/siacs/conversations/ui/ChooseContactActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ChooseContactActivity.java @@ -1,8 +1,10 @@ package eu.siacs.conversations.ui; +import android.app.ActionBar; import android.content.Context; import android.content.Intent; import android.os.Bundle; +import android.support.annotation.StringRes; import android.view.ActionMode; import android.view.Menu; import android.view.MenuInflater; @@ -32,6 +34,7 @@ public class ChooseContactActivity extends AbstractSearchableListItemActivity { private Set<Contact> selected; private Set<String> filterContacts; + public static final String EXTRA_TITLE_RES_ID = "extra_title_res_id"; @Override public void onCreate(final Bundle savedInstanceState) { @@ -77,6 +80,8 @@ public class ChooseContactActivity extends AbstractSearchableListItemActivity { String[] selection = getSelectedContactJids(); data.putExtra("contacts", selection); data.putExtra("multiple", true); + data.putExtra(EXTRA_ACCOUNT,request.getStringExtra(EXTRA_ACCOUNT)); + data.putExtra("subject", request.getStringExtra("subject")); setResult(RESULT_OK, data); finish(); return true; @@ -121,6 +126,7 @@ public class ChooseContactActivity extends AbstractSearchableListItemActivity { data.putExtra("conversation", request.getStringExtra("conversation")); data.putExtra("multiple", false); + data.putExtra("subject", request.getStringExtra("subject")); setResult(RESULT_OK, data); finish(); } @@ -129,6 +135,22 @@ public class ChooseContactActivity extends AbstractSearchableListItemActivity { } @Override + public void onStart() { + super.onStart(); + Intent intent = getIntent(); + @StringRes + int res = intent != null ? intent.getIntExtra(EXTRA_TITLE_RES_ID,R.string.title_activity_choose_contact) : R.string.title_activity_choose_contact; + ActionBar bar = getActionBar(); + if (bar != null) { + try { + bar.setTitle(res); + } catch (Exception e) { + bar.setTitle(R.string.title_activity_choose_contact); + } + } + } + + @Override public boolean onCreateOptionsMenu(final Menu menu) { super.onCreateOptionsMenu(menu); final Intent i = getIntent(); @@ -194,6 +216,7 @@ public class ChooseContactActivity extends AbstractSearchableListItemActivity { data.putExtra("conversation", request.getStringExtra("conversation")); data.putExtra("multiple", false); + data.putExtra("subject", request.getStringExtra("subject")); setResult(RESULT_OK, data); finish(); diff --git a/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java b/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java index 808f6e7f9..7e2e3297e 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java @@ -27,7 +27,6 @@ import org.openintents.openpgp.util.OpenPgpUtils; import java.util.ArrayList; import java.util.Collections; -import java.util.Comparator; import java.util.concurrent.atomic.AtomicInteger; import eu.siacs.conversations.Config; @@ -281,7 +280,7 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers case R.id.action_edit_subject: if (mConversation != null) { quickEdit(mConversation.getMucOptions().getSubject(), - R.string.action_edit_subject, + R.string.edit_subject_hint, this.onSubjectEdited); } break; @@ -486,16 +485,8 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers } protected void saveAsBookmark() { - Account account = mConversation.getAccount(); - Bookmark bookmark = new Bookmark(account, mConversation.getJid().toBareJid()); - if (!mConversation.getJid().isBareJid()) { - bookmark.setNick(mConversation.getJid().getResourcepart()); - } - bookmark.setBookmarkName(mConversation.getMucOptions().getSubject()); - bookmark.setAutojoin(getPreferences().getBoolean("autojoin",true)); - account.getBookmarks().add(bookmark); - xmppConnectionService.pushBookmarks(account); - mConversation.setBookmark(bookmark); + xmppConnectionService.saveConversationAsBookmark(mConversation, + mConversation.getMucOptions().getSubject()); } protected void deleteBookmark() { diff --git a/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java b/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java index 8fa0c6296..4f2f5e7b2 100644 --- a/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java @@ -415,35 +415,39 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd keys.removeAllViews(); boolean hasKeys = false; LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); - for(final String otrFingerprint : contact.getOtrFingerprints()) { - hasKeys = true; - View view = inflater.inflate(R.layout.contact_key, keys, false); - TextView key = (TextView) view.findViewById(R.id.key); - TextView keyType = (TextView) view.findViewById(R.id.key_type); - ImageButton removeButton = (ImageButton) view - .findViewById(R.id.button_remove); - removeButton.setVisibility(View.VISIBLE); - keyType.setText("OTR Fingerprint"); - key.setText(CryptoHelper.prettifyFingerprint(otrFingerprint)); - keys.addView(view); - removeButton.setOnClickListener(new OnClickListener() { + if (Config.supportOtr()) { + for (final String otrFingerprint : contact.getOtrFingerprints()) { + hasKeys = true; + View view = inflater.inflate(R.layout.contact_key, keys, false); + TextView key = (TextView) view.findViewById(R.id.key); + TextView keyType = (TextView) view.findViewById(R.id.key_type); + ImageButton removeButton = (ImageButton) view + .findViewById(R.id.button_remove); + removeButton.setVisibility(View.VISIBLE); + keyType.setText("OTR Fingerprint"); + key.setText(CryptoHelper.prettifyFingerprint(otrFingerprint)); + keys.addView(view); + removeButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - confirmToDeleteFingerprint(otrFingerprint); - } - }); + @Override + public void onClick(View v) { + confirmToDeleteFingerprint(otrFingerprint); + } + }); + } } - for (final String fingerprint : contact.getAccount().getAxolotlService().getFingerprintsForContact(contact)) { - boolean highlight = fingerprint.equals(messageFingerprint); - hasKeys |= addFingerprintRow(keys, contact.getAccount(), fingerprint, highlight, new OnClickListener() { - @Override - public void onClick(View v) { - onOmemoKeyClicked(contact.getAccount(), fingerprint); - } - }); + if (Config.supportOmemo()) { + for (final String fingerprint : contact.getAccount().getAxolotlService().getFingerprintsForContact(contact)) { + boolean highlight = fingerprint.equals(messageFingerprint); + hasKeys |= addFingerprintRow(keys, contact.getAccount(), fingerprint, highlight, new OnClickListener() { + @Override + public void onClick(View v) { + onOmemoKeyClicked(contact.getAccount(), fingerprint); + } + }); + } } - if (contact.getPgpKeyId() != 0) { + if (Config.supportOpenPgp() && contact.getPgpKeyId() != 0) { hasKeys = true; View view = inflater.inflate(R.layout.contact_key, keys, false); TextView key = (TextView) view.findViewById(R.id.key); diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java index 9e8c7f6f6..2db0e7c38 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java @@ -1316,6 +1316,8 @@ public class ConversationActivity extends XmppActivity if (mPendingConferenceInvite != null) { mPendingConferenceInvite.execute(this); + mToast = Toast.makeText(this, R.string.creating_conference,Toast.LENGTH_LONG); + mToast.show(); mPendingConferenceInvite = null; } diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java index 014fedd39..3ec484087 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java @@ -400,8 +400,11 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa } else { switch (conversation.getNextEncryption()) { case Message.ENCRYPTION_NONE: - mEditMessage - .setHint(getString(R.string.send_unencrypted_message)); + if (Config.multipleEncryptionChoices()) { + mEditMessage.setHint(getString(R.string.send_unencrypted_message)); + } else { + mEditMessage.setHint(getString(R.string.send_message_to_x,conversation.getName())); + } break; case Message.ENCRYPTION_OTR: mEditMessage.setHint(getString(R.string.send_otr_message)); diff --git a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java index 15701c950..af6b305c0 100644 --- a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java @@ -523,7 +523,7 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate } mamPrefs.setVisible(mAccount.getXmppConnection().getFeatures().mam()); Set<Integer> otherDevices = mAccount.getAxolotlService().getOwnDeviceIds(); - if (otherDevices == null || otherDevices.isEmpty()) { + if (otherDevices == null || otherDevices.isEmpty() || Config.supportOmemo()) { clearDevices.setVisible(false); } changePresence.setVisible(manuallyChangePresence()); @@ -785,7 +785,7 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate this.mServerInfoPush.setText(R.string.server_info_unavailable); } final String otrFingerprint = this.mAccount.getOtrFingerprint(); - if (otrFingerprint != null) { + if (otrFingerprint != null && Config.supportOtr()) { this.mOtrFingerprintBox.setVisibility(View.VISIBLE); this.mOtrFingerprint.setText(CryptoHelper.prettifyFingerprint(otrFingerprint)); this.mOtrFingerprintToClipboardButton @@ -807,10 +807,10 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate } else { this.mOtrFingerprintBox.setVisibility(View.GONE); } - final String axolotlFingerprint = this.mAccount.getAxolotlService().getOwnFingerprint(); - if (axolotlFingerprint != null) { + final String ownAxolotlFingerprint = this.mAccount.getAxolotlService().getOwnFingerprint(); + if (ownAxolotlFingerprint != null && Config.supportOmemo()) { this.mAxolotlFingerprintBox.setVisibility(View.VISIBLE); - this.mAxolotlFingerprint.setText(CryptoHelper.prettifyFingerprint(axolotlFingerprint.substring(2))); + this.mAxolotlFingerprint.setText(CryptoHelper.prettifyFingerprint(ownAxolotlFingerprint.substring(2))); this.mAxolotlFingerprintToClipboardButton .setVisibility(View.VISIBLE); this.mAxolotlFingerprintToClipboardButton @@ -819,7 +819,7 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate @Override public void onClick(final View v) { - if (copyTextToClipboard(axolotlFingerprint.substring(2), R.string.omemo_fingerprint)) { + if (copyTextToClipboard(ownAxolotlFingerprint.substring(2), R.string.omemo_fingerprint)) { Toast.makeText( EditAccountActivity.this, R.string.toast_message_omemo_fingerprint, @@ -842,17 +842,16 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate } else { this.mAxolotlFingerprintBox.setVisibility(View.GONE); } - final String ownFingerprint = mAccount.getAxolotlService().getOwnFingerprint(); boolean hasKeys = false; keys.removeAllViews(); for (final String fingerprint : mAccount.getAxolotlService().getFingerprintsForOwnSessions()) { - if (ownFingerprint.equals(fingerprint)) { + if (ownAxolotlFingerprint.equals(fingerprint)) { continue; } boolean highlight = fingerprint.equals(messageFingerprint); hasKeys |= addFingerprintRow(keys, mAccount, fingerprint, highlight, null); } - if (hasKeys) { + if (hasKeys && Config.supportOmemo()) { keysCard.setVisibility(View.VISIBLE); } else { keysCard.setVisibility(View.GONE); diff --git a/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java index 3ab6d1d2e..9af83edd8 100644 --- a/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java @@ -10,6 +10,7 @@ import android.app.AlertDialog; import android.app.Fragment; import android.app.FragmentTransaction; import android.app.ListFragment; +import android.app.PendingIntent; import android.content.Context; import android.content.DialogInterface; import android.content.DialogInterface.OnClickListener; @@ -27,6 +28,7 @@ import android.support.v4.view.ViewPager; import android.text.Editable; import android.text.TextWatcher; import android.util.Log; +import android.util.Pair; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; import android.view.KeyEvent; @@ -54,6 +56,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.concurrent.RunnableFuture; import java.util.concurrent.atomic.AtomicBoolean; import eu.siacs.conversations.Config; @@ -94,6 +97,7 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU private EditText mSearchEditText; private AtomicBoolean mRequestedContactsPermission = new AtomicBoolean(false); private final int REQUEST_SYNC_CONTACTS = 0x3b28cf; + private final int REQUEST_CREATE_CONFERENCE = 0x3b39da; private MenuItem.OnActionExpandListener mOnActionExpandListener = new MenuItem.OnActionExpandListener() { @@ -201,6 +205,47 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU } }; private String mInitialJid; + private Pair<Integer, Intent> mPostponedActivityResult; + private UiCallback<Conversation> mAdhocConferenceCallback = new UiCallback<Conversation>() { + @Override + public void success(final Conversation conversation) { + runOnUiThread(new Runnable() { + @Override + public void run() { + hideToast(); + switchToConversation(conversation); + } + }); + } + + @Override + public void error(final int errorCode, Conversation object) { + runOnUiThread(new Runnable() { + @Override + public void run() { + replaceToast(getString(errorCode)); + } + }); + } + + @Override + public void userInputRequried(PendingIntent pi, Conversation object) { + + } + }; + private Toast mToast; + + protected void hideToast() { + if (mToast != null) { + mToast.cancel(); + } + } + + protected void replaceToast(String msg) { + hideToast(); + mToast = Toast.makeText(this, msg ,Toast.LENGTH_LONG); + mToast.show(); + } @Override public void onRosterUpdate() { @@ -488,6 +533,37 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU }); } + private void showCreateConferenceDialog() { + final AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle(R.string.create_conference); + final View dialogView = getLayoutInflater().inflate(R.layout.create_conference_dialog, null); + final Spinner spinner = (Spinner) dialogView.findViewById(R.id.account); + final EditText subject = (EditText) dialogView.findViewById(R.id.subject); + populateAccountSpinner(this, mActivatedAccounts, spinner); + builder.setView(dialogView); + builder.setPositiveButton(R.string.choose_participants, new OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + if (!xmppConnectionServiceBound) { + return; + } + final Account account = getSelectedAccount(spinner); + if (account == null) { + return; + } + Intent intent = new Intent(getApplicationContext(), ChooseContactActivity.class); + intent.putExtra("multiple", true); + intent.putExtra("show_enter_jid", true); + intent.putExtra("subject", subject.getText().toString()); + intent.putExtra(EXTRA_ACCOUNT, account.getJid().toBareJid().toString()); + intent.putExtra(ChooseContactActivity.EXTRA_TITLE_RES_ID,R.string.choose_participants); + startActivityForResult(intent, REQUEST_CREATE_CONFERENCE); + } + }); + builder.setNegativeButton(R.string.cancel, null); + builder.create().show(); + } + private Account getSelectedAccount(Spinner spinner) { if (!spinner.isEnabled()) { return null; @@ -532,7 +608,7 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.start_conversation, menu); MenuItem menuCreateContact = menu.findItem(R.id.action_create_contact); - MenuItem menuCreateConference = menu.findItem(R.id.action_join_conference); + MenuItem menuCreateConference = menu.findItem(R.id.action_conference); MenuItem menuHideOffline = menu.findItem(R.id.action_hide_offline); menuHideOffline.setChecked(this.mHideOfflineContacts); mMenuSearchView = menu.findItem(R.id.action_search); @@ -564,6 +640,9 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU case R.id.action_join_conference: showJoinConferenceDialog(null); return true; + case R.id.action_create_conference: + showCreateConferenceDialog(); + return true; case R.id.action_scan_qr_code: new IntentIntegrator(this).initiateScan(); return true; @@ -616,6 +695,39 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU this.mPendingInvite = null; } } + } else if (resultCode == RESULT_OK) { + if (xmppConnectionServiceBound) { + this.mPostponedActivityResult = null; + if (requestCode == REQUEST_CREATE_CONFERENCE) { + Log.d(Config.LOGTAG,"account jid: "+ intent.getStringExtra(EXTRA_ACCOUNT)); + Account account = extractAccount(intent); + final String subject = intent.getStringExtra("subject"); + List<Jid> jids = new ArrayList<>(); + if (intent.getBooleanExtra("multiple", false)) { + String[] toAdd = intent.getStringArrayExtra("contacts"); + for (String item : toAdd) { + try { + jids.add(Jid.fromString(item)); + } catch (InvalidJidException e) { + //ignored + } + } + } else { + try { + jids.add(Jid.fromString(intent.getStringExtra("contact"))); + } catch (Exception e) { + //ignored + } + } + if (account != null && jids.size() > 1) { + xmppConnectionService.createAdhocConference(account, subject, jids, mAdhocConferenceCallback); + mToast = Toast.makeText(this, R.string.creating_conference,Toast.LENGTH_LONG); + mToast.show(); + } + } + } else { + this.mPostponedActivityResult = new Pair<>(requestCode, intent); + } } super.onActivityResult(requestCode, requestCode, intent); } @@ -657,6 +769,10 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU @Override protected void onBackendConnected() { + if (mPostponedActivityResult != null) { + onActivityResult(mPostponedActivityResult.first, RESULT_OK, mPostponedActivityResult.second); + this.mPostponedActivityResult = null; + } this.mActivatedAccounts.clear(); for (Account account : xmppConnectionService.getAccounts()) { if (account.getStatus() != Account.State.DISABLED) { diff --git a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java index 2a6dbf589..faa314752 100644 --- a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java @@ -118,6 +118,20 @@ public abstract class XmppActivity extends Activity { protected int mTheme; protected boolean mUsingEnterKey = false; + protected Toast mToast; + + protected void hideToast() { + if (mToast != null) { + mToast.cancel(); + } + } + + protected void replaceToast(String msg) { + hideToast(); + mToast = Toast.makeText(this, msg ,Toast.LENGTH_LONG); + mToast.show(); + } + protected Runnable onOpenPGPKeyPublished = new Runnable() { @Override public void run() { @@ -948,19 +962,22 @@ public abstract class XmppActivity extends Activity { mPendingConferenceInvite = ConferenceInvite.parse(data); if (xmppConnectionServiceBound && mPendingConferenceInvite != null) { mPendingConferenceInvite.execute(this); + mToast = Toast.makeText(this, R.string.creating_conference,Toast.LENGTH_LONG); + mToast.show(); mPendingConferenceInvite = null; } } } + private UiCallback<Conversation> adhocCallback = new UiCallback<Conversation>() { @Override public void success(final Conversation conversation) { - switchToConversation(conversation); runOnUiThread(new Runnable() { @Override public void run() { - Toast.makeText(XmppActivity.this,R.string.conference_created,Toast.LENGTH_LONG).show(); + switchToConversation(conversation); + hideToast(); } }); } @@ -970,7 +987,7 @@ public abstract class XmppActivity extends Activity { runOnUiThread(new Runnable() { @Override public void run() { - Toast.makeText(XmppActivity.this,errorCode,Toast.LENGTH_LONG).show(); + replaceToast(getString(errorCode)); } }); } @@ -1167,7 +1184,7 @@ public abstract class XmppActivity extends Activity { } } else { jids.add(conversation.getJid().toBareJid()); - service.createAdhocConference(conversation.getAccount(), jids, activity.adhocCallback); + service.createAdhocConference(conversation.getAccount(), null, jids, activity.adhocCallback); } } } diff --git a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java index b42be17b9..a07267e71 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java @@ -184,14 +184,21 @@ public class XmppConnection implements Runnable { account.setOption(Account.OPTION_REGISTER, false); forceCloseSocket(); changeStatus(Account.State.REGISTRATION_SUCCESSFUL); - } else if (packet.hasChild("error") - && (packet.findChild("error").hasChild("conflict"))) { - forceCloseSocket(); - changeStatus(Account.State.REGISTRATION_CONFLICT); } else { - forceCloseSocket(); - changeStatus(Account.State.REGISTRATION_FAILED); - Log.d(Config.LOGTAG, packet.toString()); + Element error = packet.findChild("error"); + if (error != null && error.hasChild("conflict")) { + forceCloseSocket(); + changeStatus(Account.State.REGISTRATION_CONFLICT); + } else if (error != null + && "wait".equals(error.getAttribute("type")) + && error.hasChild("resource-constraint")) { + forceCloseSocket(); + changeStatus(Account.State.REGISTRATION_PLEASE_WAIT); + } else { + forceCloseSocket(); + changeStatus(Account.State.REGISTRATION_FAILED); + Log.d(Config.LOGTAG, packet.toString()); + } } } }; diff --git a/src/main/res/layout/create_conference_dialog.xml b/src/main/res/layout/create_conference_dialog.xml new file mode 100644 index 000000000..cab2ac578 --- /dev/null +++ b/src/main/res/layout/create_conference_dialog.xml @@ -0,0 +1,42 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical" + android:paddingBottom="8dp" + android:paddingLeft="24dp" + android:paddingRight="24dp" + android:paddingTop="16dp"> + + <TextView + android:id="@+id/your_account" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/your_account" + android:textColor="@color/black87" + android:textSize="?attr/TextSizeBody" /> + + <Spinner + android:id="@+id/account" + android:layout_width="fill_parent" + android:layout_height="wrap_content" /> + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:text="@string/conference_subject" + android:textColor="@color/black87" + android:textSize="?attr/TextSizeBody" /> + + <EditText + android:id="@+id/subject" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:hint="@string/edit_subject_hint" + android:inputType="textAutoComplete" + android:textColor="@color/black87" + android:textColorHint="@color/black54" + android:textSize="?attr/TextSizeBody"/> + +</LinearLayout>
\ No newline at end of file diff --git a/src/main/res/menu/start_conversation.xml b/src/main/res/menu/start_conversation.xml index b0472af05..305ffd223 100644 --- a/src/main/res/menu/start_conversation.xml +++ b/src/main/res/menu/start_conversation.xml @@ -13,10 +13,20 @@ android:showAsAction="always" android:title="@string/create_contact" /> <item - android:id="@+id/action_join_conference" + android:id="@+id/action_conference" android:icon="?attr/icon_add_group" android:showAsAction="always" - android:title="@string/join_conference" /> + android:title="@string/join_or_create_conference"> + <menu> + <item + android:id="@+id/action_join_conference" + android:title="@string/join_conference"/> + <item + android:id="@+id/action_create_conference" + android:title="@string/create_conference"/> + + </menu> + </item> <item android:id="@+id/action_scan_qr_code" android:showAsAction="never" diff --git a/src/main/res/values-de/strings.xml b/src/main/res/values-de/strings.xml index 4ff75a9be..83f04e9d8 100644 --- a/src/main/res/values-de/strings.xml +++ b/src/main/res/values-de/strings.xml @@ -155,9 +155,8 @@ <string name="mgmt_account_delete">Löschen</string> <string name="mgmt_account_publish_avatar">Profilbild veröffentlichen</string> <string name="mgmt_account_publish_pgp">Öffentlichen OpenPGP-Schlüssel veröffentlichen</string> - <string name="openpgp_has_been_published">Öffentlicher OpenPGP Schlüssel wurde veröffentlicht.</string> - <string name="republish_pgp_keys">Deine öffentliche OpenPGP Schlüssel müssen veröffentlicht werden!</string> - <string name="mgmt_account_enable">Konto aktivieren </string> + <string name="openpgp_has_been_published">Öffentlicher OpenPGP-Schlüssel wurde veröffentlicht.</string> + <string name="republish_pgp_keys">Deine öffentliche OpenPGP-Schlüssel müssen veröffentlicht werden!</string> <string name="mgmt_account_are_you_sure">Bist du dir sicher?</string> <string name="mgmt_account_delete_confirm_text">Wenn du dein Profil löschst, gehen alle Gesprächsverläufe verloren</string> <string name="attach_record_voice">Sprache aufzeichnen</string> @@ -225,7 +224,7 @@ <string name="delete_bookmark">Von Kontaktliste entfernen</string> <string name="bookmark_already_exists">Die Konferenz befindet sich bereits auf deiner Kontaktliste</string> <string name="action_edit_subject">Konferenz-Thema bearbeiten</string> - <string name="joining_conference">Konferenz wird betreten…</string> + <string name="joining_conference">Konferenz wird beigetreten…</string> <string name="leave">Verlassen</string> <string name="contact_added_you">Der Kontakt hat dich zur Kontaktliste hinzugefügt</string> <string name="add_back">Auch hinzufügen</string> @@ -339,8 +338,9 @@ <string name="enable_notifications">Benachrichtigungen aktivieren</string> <string name="no_conference_server_found">Kein Konferenz-Server gefunden</string> <string name="conference_creation_failed">Erstellen der Konferenz fehlgeschlagen!</string> - <string name="conference_created">Konferenz erstellt!</string> <string name="account_image_description">Profilbild</string> + <string name="secret_accepted">Schlüssel akzeptiert!</string> + <string name="reset">Zurücksetzen</string> <string name="copy_otr_clipboard_description">OTR-Fingerabdruck in Zwischenablage kopieren</string> <string name="copy_omemo_clipboard_description">OMEMO-Fingerabdruck in Zwischenablage kopieren</string> <string name="regenerate_omemo_key">OMEMO-Schlüssel erneuern</string> @@ -448,7 +448,7 @@ <string name="pref_quick_action">Schnell-Tasten</string> <string name="none">keine</string> <string name="recently_used">zuletzt verwendet</string> - <string name="choose_quick_action">wähle Schnell-Taste</string> + <string name="choose_quick_action">Schnell-Taste auswähle</string> <string name="search_for_contacts_or_groups">Nach Kontakten oder Konferenzen suchen</string> <string name="elv_undo">Rückgängig</string> <string name="send_private_message">Private Nachricht senden</string> @@ -490,7 +490,7 @@ <string name="fetching_mam_prefs">Archivierungseinstellungen werden abgerufen. Bitte warten …</string> <string name="unable_to_fetch_mam_prefs">Archivierungseinstellungen konnten nicht abgerufen werden</string> <string name="captcha_required">Captcha erforderlich</string> - <string name="captcha_hint">Gib den Text vom obigen Bild ein</string> + <string name="captcha_hint">Gib den Text von obigem Bild ein</string> <string name="certificate_chain_is_not_trusted">Zertifikat wird nicht vertraut</string> <string name="jid_does_not_match_certificate">Jabber-ID stimmt nicht dem Zertifikat überein</string> <string name="action_renew_certificate">Zertifikat erneuern</string> @@ -589,7 +589,7 @@ <string name="presence_xa">Nicht verfügbar</string> <string name="presence_dnd">Beschäftigt</string> <string name="secure_password_generated">Ein sicheres Passwort wurde erstellt</string> - <string name="device_does_not_support_battery_op">Dein Gerät unterstützt keine Batterieoptimierungen</string> + <string name="device_does_not_support_battery_op">Dein Gerät unterstützt kein Ausschalten der Batterieoptimierung</string> <string name="locating">Lokalisiere…</string> <string name="location_sharing_disabled">GPS ist in den Android-Einstellungen deaktiviert</string> <string name="share">Teilen</string> @@ -600,4 +600,13 @@ <string name="default_resource"></string> <string name="leave_conference_warning">Willst du die Konferenz wirklich verlassen? Du wirst keine neuen Nachrichten mehr bekommen, bis du der Konferenz erneut beitrittst.</string> <string name="show_password">Passwort anzeigen</string> + <string name="choose_participants">Mitglieder auswählen</string> + <string name="conference_subject">Titel</string> + <string name="create_conference">Konferenz erstellen</string> + <string name="creating_conference">Erstelle Konferenz…</string> + <string name="edit_subject_hint">Der Titel dieser Konferenz</string> + <string name="join_or_create_conference">Konferenz beitreten oder erstellen</string> + <string name="mgmt_account_enable"></string> + <string name="registration_please_wait">Registrierung fehlgeschlagen: Bitte später versuchen</string> + <string name="send_message_to_x">Nachricht an %s senden</string> </resources> diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index 5185f37aa..f25918008 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -79,6 +79,7 @@ <string name="also_end_conversation">End this conversation afterwards</string> <string name="choose_presence">Choose presence to contact</string> <string name="send_unencrypted_message">Send unencrypted message</string> + <string name="send_message_to_x">Send message to %s</string> <string name="send_otr_message">Send OTR encrypted message</string> <string name="send_omemo_message">Send OMEMO encrypted message</string> <string name="send_omemo_x509_message">Send v\\OMEMO encrypted message</string> @@ -230,6 +231,7 @@ <string name="delete_bookmark">Delete bookmark</string> <string name="bookmark_already_exists">This bookmark already exists</string> <string name="action_edit_subject">Edit conference subject</string> + <string name="edit_subject_hint">The subject of this conference</string> <string name="joining_conference">Joining conference…</string> <string name="leave">Leave</string> <string name="contact_added_you">Contact added you to contact list</string> @@ -387,8 +389,9 @@ <string name="pref_show_dynamic_tags_summary">Display read-only tags underneath contacts</string> <string name="enable_notifications">Enable notifications</string> <string name="no_conference_server_found">No conference server found</string> - <string name="conference_creation_failed">Conference creation failed!</string> - <string name="conference_created">Conference created!</string> + <string name="conference_creation_failed">Conference creation failed!</string>s + <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> <string name="copy_omemo_clipboard_description">Copy OMEMO fingerprint to clipboard</string> @@ -633,5 +636,11 @@ <string name="action_end_conversation_muc">Leave conference</string> <string name="leave_conference_warning">Do you really want to leave this conference? You will no longer be notified of new messages until joining the conference again.</string> <string name="show_password">Show password</string> + <string name="registration_please_wait">Registration failed: Try again later</string> + <string name="create_conference">Create conference</string> + <string name="join_or_create_conference">Join or create conference</string> + <string name="conference_subject">Subject</string> + <string name="choose_participants">Choose participants</string> + <string name="creating_conference">Creating conference…</string> </resources> |