diff options
Diffstat (limited to 'src/main/java/eu/siacs')
13 files changed, 203 insertions, 145 deletions
diff --git a/src/main/java/eu/siacs/conversations/crypto/OtrEngine.java b/src/main/java/eu/siacs/conversations/crypto/OtrEngine.java index 263f6089..0dc7c37e 100644 --- a/src/main/java/eu/siacs/conversations/crypto/OtrEngine.java +++ b/src/main/java/eu/siacs/conversations/crypto/OtrEngine.java @@ -182,7 +182,7 @@ public class OtrEngine extends OtrCryptoEngineImpl implements OtrEngineHost { packet.setBody(body); packet.addChild("private", "urn:xmpp:carbons:2"); packet.addChild("no-copy", "urn:xmpp:hints"); - packet.addChild("no-store", "urn:xmpp:hints"); + packet.addChild("no-permanent-store", "urn:xmpp:hints"); try { Jid jid = Jid.fromSessionID(session); diff --git a/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java b/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java index a60c5613..474a3e1d 100644 --- a/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java +++ b/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java @@ -71,6 +71,7 @@ public class MessageGenerator extends AbstractGenerator { MessagePacket packet = preparePacket(message, addDelay); packet.addChild("private", "urn:xmpp:carbons:2"); packet.addChild("no-copy", "urn:xmpp:hints"); + packet.addChild("no-permanent-store", "urn:xmpp:hints"); try { packet.setBody(otrSession.transformSending(message.getBody())[0]); return packet; diff --git a/src/main/java/eu/siacs/conversations/parser/MessageParser.java b/src/main/java/eu/siacs/conversations/parser/MessageParser.java index 8ae9b642..76d01468 100644 --- a/src/main/java/eu/siacs/conversations/parser/MessageParser.java +++ b/src/main/java/eu/siacs/conversations/parser/MessageParser.java @@ -391,15 +391,17 @@ public class MessageParser extends AbstractParser implements private void parseNonMessage(Element packet, Account account) { final Jid from = packet.getAttributeAsJid("from"); + if (account.getJid().equals(from)) { + return; + } if (extractChatState(from == null ? null : mXmppConnectionService.find(account,from), packet)) { mXmppConnectionService.updateConversationUi(); } - Element invite = extractInvite(packet); - if (invite != null) { - Conversation conversation = mXmppConnectionService.findOrCreateConversation(account, from, true); + Invite invite = extractInvite(packet); + if (invite != null && invite.jid != null) { + Conversation conversation = mXmppConnectionService.findOrCreateConversation(account, invite.jid, true); if (!conversation.getMucOptions().online()) { - Element password = invite.findChild("password"); - conversation.getMucOptions().setPassword(password == null ? null : password.getContent()); + conversation.getMucOptions().setPassword(invite.password); mXmppConnectionService.databaseBackend.updateConversation(conversation); mXmppConnectionService.joinMuc(conversation); mXmppConnectionService.updateConversationUi(); @@ -439,16 +441,30 @@ public class MessageParser extends AbstractParser implements } } - private Element extractInvite(Element message) { - Element x = message.findChild("x","http://jabber.org/protocol/muc#user"); - if (x == null) { - x = message.findChild("x","jabber:x:conference"); + private class Invite { + Jid jid; + String password; + Invite(Jid jid, String password) { + this.jid = jid; + this.password = password; } - if (x != null && x.hasChild("invite")) { - return x; + } + + private Invite extractInvite(Element message) { + Element x = message.findChild("x","http://jabber.org/protocol/muc#user"); + if (x != null) { + Element invite = x.findChild("invite"); + if (invite != null) { + Element pw = x.findChild("password"); + return new Invite(message.getAttributeAsJid("from"), pw != null ? pw.getContent(): null); + } } else { - return null; + x = message.findChild("x","jabber:x:conference"); + if (x != null) { + return new Invite(x.getAttributeAsJid("jid"),x.getAttribute("password")); + } } + return null; } private void parseEvent(final Element event, final Jid from, final Account account) { diff --git a/src/main/java/eu/siacs/conversations/persistance/FileBackend.java b/src/main/java/eu/siacs/conversations/persistance/FileBackend.java index c499d499..cb79b0e9 100644 --- a/src/main/java/eu/siacs/conversations/persistance/FileBackend.java +++ b/src/main/java/eu/siacs/conversations/persistance/FileBackend.java @@ -1,6 +1,7 @@ package eu.siacs.conversations.persistance; import java.io.ByteArrayOutputStream; +import java.io.Closeable; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; @@ -42,8 +43,7 @@ public class FileBackend { private static int IMAGE_SIZE = 1920; - private SimpleDateFormat imageDateFormat = new SimpleDateFormat( - "yyyyMMdd_HHmmssSSS", Locale.US); + private final SimpleDateFormat imageDateFormat = new SimpleDateFormat("yyyyMMdd_HHmmssSSS", Locale.US); private XmppConnectionService mXmppConnectionService; @@ -110,9 +110,7 @@ public class FileBackend { scalledW = size; scalledH = (int) (h / ((double) w / size)); } - Bitmap scalledBitmap = Bitmap.createScaledBitmap(originalBitmap, - scalledW, scalledH, true); - return scalledBitmap; + return Bitmap.createScaledBitmap(originalBitmap, scalledW, scalledH, true); } else { return originalBitmap; } @@ -148,31 +146,34 @@ public class FileBackend { } public DownloadableFile copyFileToPrivateStorage(Message message, Uri uri) throws FileCopyException { + Log.d(Config.LOGTAG, "copy " + uri.toString() + " to private storage"); + String mime = mXmppConnectionService.getContentResolver().getType(uri); + String extension = MimeTypeMap.getSingleton().getExtensionFromMimeType(mime); + message.setRelativeFilePath(message.getUuid() + "." + extension); + DownloadableFile file = mXmppConnectionService.getFileBackend().getFile(message); + file.getParentFile().mkdirs(); + OutputStream os = null; + InputStream is = null; try { - Log.d(Config.LOGTAG, "copy " + uri.toString() + " to private storage"); - String mime = mXmppConnectionService.getContentResolver().getType(uri); - String extension = MimeTypeMap.getSingleton().getExtensionFromMimeType(mime); - message.setRelativeFilePath(message.getUuid() + "." + extension); - DownloadableFile file = mXmppConnectionService.getFileBackend().getFile(message); - file.getParentFile().mkdirs(); - file.createNewFile(); - OutputStream os = new FileOutputStream(file); - InputStream is = mXmppConnectionService.getContentResolver().openInputStream(uri); + if (!file.createNewFile()) { + throw new FileCopyException(R.string.error_io_exception); + } + os = new FileOutputStream(file); + is = mXmppConnectionService.getContentResolver().openInputStream(uri); byte[] buffer = new byte[1024]; - int length; - while ((length = is.read(buffer)) > 0) { + int length; + while ((length = is.read(buffer)) > 0) { os.write(buffer, 0, length); - } + } os.flush(); - os.close(); - is.close(); - Log.d(Config.LOGTAG, "output file name " + mXmppConnectionService.getFileBackend().getFile(message)); - return file; - } catch (FileNotFoundException e) { - throw new FileCopyException(R.string.error_file_not_found); } catch (IOException e) { throw new FileCopyException(R.string.error_io_exception); + } finally { + close(os); + close(is); } + Log.d(Config.LOGTAG, "output file name " + mXmppConnectionService.getFileBackend().getFile(message)); + return file; } public DownloadableFile copyImageToPrivateStorage(Message message, Uri image) @@ -182,40 +183,41 @@ public class FileBackend { private DownloadableFile copyImageToPrivateStorage(Message message, Uri image, int sampleSize) throws FileCopyException { + DownloadableFile file = getFile(message); + file.getParentFile().mkdirs(); + InputStream is = null; + OutputStream os = null; try { - InputStream is = mXmppConnectionService.getContentResolver() - .openInputStream(image); - DownloadableFile file = getFile(message); - file.getParentFile().mkdirs(); - file.createNewFile(); + if (!file.createNewFile()) { + throw new FileCopyException(R.string.error_io_exception); + } + is = mXmppConnectionService.getContentResolver().openInputStream(image); + os = new FileOutputStream(file); + Bitmap originalBitmap; BitmapFactory.Options options = new BitmapFactory.Options(); int inSampleSize = (int) Math.pow(2, sampleSize); - Log.d(Config.LOGTAG, "reading bitmap with sample size " - + inSampleSize); + Log.d(Config.LOGTAG, "reading bitmap with sample size " + inSampleSize); options.inSampleSize = inSampleSize; originalBitmap = BitmapFactory.decodeStream(is, null, options); is.close(); if (originalBitmap == null) { throw new FileCopyException(R.string.error_not_an_image_file); } - Bitmap scalledBitmap = resize(originalBitmap, IMAGE_SIZE); - originalBitmap = null; + Bitmap scaledBitmap = resize(originalBitmap, IMAGE_SIZE); int rotation = getRotation(image); if (rotation > 0) { - scalledBitmap = rotate(scalledBitmap, rotation); + scaledBitmap = rotate(scaledBitmap, rotation); } - OutputStream os = new FileOutputStream(file); - boolean success = scalledBitmap.compress( - Bitmap.CompressFormat.WEBP, 75, os); + + boolean success = scaledBitmap.compress(Bitmap.CompressFormat.WEBP, 75, os); if (!success) { throw new FileCopyException(R.string.error_compressing_image); } os.flush(); - os.close(); long size = file.getSize(); - int width = scalledBitmap.getWidth(); - int height = scalledBitmap.getHeight(); + int width = scaledBitmap.getWidth(); + int height = scaledBitmap.getHeight(); message.setBody(Long.toString(size) + ',' + width + ',' + height); return file; } catch (FileNotFoundException e) { @@ -223,8 +225,7 @@ public class FileBackend { } catch (IOException e) { throw new FileCopyException(R.string.error_io_exception); } catch (SecurityException e) { - throw new FileCopyException( - R.string.error_security_exception_during_image_copy); + throw new FileCopyException(R.string.error_security_exception_during_image_copy); } catch (OutOfMemoryError e) { ++sampleSize; if (sampleSize <= 3) { @@ -232,23 +233,24 @@ public class FileBackend { } else { throw new FileCopyException(R.string.error_out_of_memory); } + } finally { + close(os); + close(is); } } private int getRotation(Uri image) { + InputStream is = null; try { - InputStream is = mXmppConnectionService.getContentResolver() - .openInputStream(image); + is = mXmppConnectionService.getContentResolver().openInputStream(image); return ExifHelper.getOrientation(is); } catch (FileNotFoundException e) { return 0; + } finally { + close(is); } } - public Bitmap getImageFromMessage(Message message) { - return BitmapFactory.decodeFile(getFile(message).getAbsolutePath()); - } - public Bitmap getThumbnail(Message message, int size, boolean cacheOnly) throws FileNotFoundException { Bitmap thumbnail = mXmppConnectionService.getBitmapCache().get( @@ -257,8 +259,7 @@ public class FileBackend { File file = getFile(message); BitmapFactory.Options options = new BitmapFactory.Options(); options.inSampleSize = calcSampleSize(file, size); - Bitmap fullsize = BitmapFactory.decodeFile(file.getAbsolutePath(), - options); + Bitmap fullsize = BitmapFactory.decodeFile(file.getAbsolutePath(),options); if (fullsize == null) { throw new FileNotFoundException(); } @@ -271,13 +272,11 @@ public class FileBackend { public Uri getTakePhotoUri() { StringBuilder pathBuilder = new StringBuilder(); - pathBuilder.append(Environment - .getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM)); + pathBuilder.append(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM)); pathBuilder.append('/'); pathBuilder.append("Camera"); pathBuilder.append('/'); - pathBuilder.append("IMG_" + this.imageDateFormat.format(new Date()) - + ".jpg"); + pathBuilder.append("IMG_" + this.imageDateFormat.format(new Date()) + ".jpg"); Uri uri = Uri.parse("file://" + pathBuilder.toString()); File file = new File(uri.toString()); file.getParentFile().mkdirs(); @@ -325,13 +324,13 @@ public class FileBackend { String filename = getAvatarPath(avatar.getFilename()); file = new File(filename + ".tmp"); file.getParentFile().mkdirs(); + OutputStream os = null; try { file.createNewFile(); - FileOutputStream mFileOutputStream = new FileOutputStream(file); + os = new FileOutputStream(file); MessageDigest digest = MessageDigest.getInstance("SHA-1"); digest.reset(); - DigestOutputStream mDigestOutputStream = new DigestOutputStream( - mFileOutputStream, digest); + DigestOutputStream mDigestOutputStream = new DigestOutputStream(os, digest); mDigestOutputStream.write(avatar.getImageAsBytes()); mDigestOutputStream.flush(); mDigestOutputStream.close(); @@ -349,6 +348,8 @@ public class FileBackend { return false; } catch (NoSuchAlgorithmException e) { return false; + } finally { + close(os); } } avatar.size = file.length(); @@ -356,8 +357,7 @@ public class FileBackend { } public String getAvatarPath(String avatar) { - return mXmppConnectionService.getFilesDir().getAbsolutePath() - + "/avatars/" + avatar; + return mXmppConnectionService.getFilesDir().getAbsolutePath()+ "/avatars/" + avatar; } public Uri getAvatarUri(String avatar) { @@ -368,10 +368,11 @@ public class FileBackend { if (image == null) { return null; } + InputStream is = null; try { BitmapFactory.Options options = new BitmapFactory.Options(); options.inSampleSize = calcSampleSize(image, size); - InputStream is = mXmppConnectionService.getContentResolver().openInputStream(image); + is = mXmppConnectionService.getContentResolver().openInputStream(image); Bitmap input = BitmapFactory.decodeStream(is, null, options); if (input == null) { return null; @@ -384,6 +385,8 @@ public class FileBackend { } } catch (FileNotFoundException e) { return null; + } finally { + close(is); } } @@ -391,10 +394,11 @@ public class FileBackend { if (image == null) { return null; } + InputStream is = null; try { BitmapFactory.Options options = new BitmapFactory.Options(); options.inSampleSize = calcSampleSize(image,Math.max(newHeight, newWidth)); - InputStream is = mXmppConnectionService.getContentResolver().openInputStream(image); + is = mXmppConnectionService.getContentResolver().openInputStream(image); Bitmap source = BitmapFactory.decodeStream(is, null, options); int sourceWidth = source.getWidth(); @@ -414,8 +418,11 @@ public class FileBackend { return dest; } catch (FileNotFoundException e) { return null; + } catch (IOException e) { + return null; + } finally { + close(is); } - } public Bitmap cropCenterSquare(Bitmap input, int size) { @@ -522,4 +529,13 @@ public class FileBackend { public boolean isFileAvailable(Message message) { return getFile(message).exists(); } + + public static void close(Closeable stream) { + if (stream != null) { + try { + stream.close(); + } catch (IOException e) { + } + } + } } diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 3e8ce65f..ec0b3f92 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -36,6 +36,7 @@ import org.openintents.openpgp.util.OpenPgpServiceConnection; import java.math.BigInteger; import java.security.SecureRandom; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; @@ -174,13 +175,22 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa public void onContactStatusChanged(Contact contact, boolean online) { Conversation conversation = find(getConversations(), contact); if (conversation != null) { - if (online && contact.getPresences().size() > 1) { + if (online) { conversation.endOtrIfNeeded(); + if (contact.getPresences().size() == 1) { + sendUnsentMessages(conversation); + } } else { - conversation.resetOtrSession(); - } - if (online && (contact.getPresences().size() == 1)) { - sendUnsentMessages(conversation); + if (contact.getPresences().size() >= 1) { + if (conversation.hasValidOtrSession()) { + String otrResource = conversation.getOtrSession().getSessionID().getUserID(); + if (!(Arrays.asList(contact.getPresences().asStringArray()).contains(otrResource))) { + conversation.endOtrIfNeeded(); + } + } + } else { + conversation.endOtrIfNeeded(); + } } } } @@ -1537,6 +1547,9 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa for (Jid invite : jids) { invite(conversation, invite); } + if (account.countPresences() > 1) { + directInvite(conversation, account.getJid().toBareJid()); + } if (callback != null) { callback.success(conversation); } @@ -2022,6 +2035,11 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa sendMessagePacket(conversation.getAccount(), packet); } + public void directInvite(Conversation conversation, Jid jid) { + MessagePacket packet = mMessageGenerator.directInvite(conversation,jid); + sendMessagePacket(conversation.getAccount(),packet); + } + public void resetSendingToWaiting(Account account) { for (Conversation conversation : getConversations()) { if (conversation.getAccount() == account) { diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java index a44311b4..e5389dd6 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java @@ -929,10 +929,10 @@ public class ConversationActivity extends XmppActivity } private void handleViewConversationIntent(final Intent intent) { - final String uuid = (String) intent.getExtras().get(CONVERSATION); - final String downloadUuid = (String) intent.getExtras().get(MESSAGE); - final String text = intent.getExtras().getString(TEXT, ""); - final String nick = intent.getExtras().getString(NICK, null); + final String uuid = intent.getStringExtra(CONVERSATION); + final String downloadUuid = intent.getStringExtra(MESSAGE); + final String text = intent.getStringExtra(TEXT); + final String nick = intent.getStringExtra(NICK); if (selectConversationByUuid(uuid)) { this.mConversationFragment.reInit(getSelectedConversation()); if (nick != null) { diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java index a3a02b27..5b1e9b4d 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java @@ -8,7 +8,6 @@ import android.content.DialogInterface; import android.content.Intent; import android.content.IntentSender; import android.content.IntentSender.SendIntentException; -import android.net.Uri; import android.os.Bundle; import android.text.InputType; import android.view.ContextMenu; @@ -315,8 +314,8 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa @Override public View onCreateView(final LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - final View view = inflater.inflate(R.layout.fragment_conversation, - container, false); + final View view = inflater.inflate(R.layout.fragment_conversation,container, false); + view.setOnClickListener(null); mEditMessage = (EditMessage) view.findViewById(R.id.textinput); setupIme(); mEditMessage.setOnClickListener(new OnClickListener() { @@ -719,21 +718,6 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa final ConversationActivity activity = (ConversationActivity) getActivity(); if (this.conversation != null) { updateSnackBar(this.conversation); - final Contact contact = this.conversation.getContact(); - if (this.conversation.isBlocked()) { - - } else if (!contact.showInRoster() - && contact - .getOption(Contact.Options.PENDING_SUBSCRIPTION_REQUEST)) { - - } else if (conversation.getMode() == Conversation.MODE_SINGLE) { - makeFingerprintWarning(); - } else if (!conversation.getMucOptions().online() - && conversation.getAccount().getStatus() == Account.State.ONLINE) { - - } else if (this.conversation.isMuted()) { - - } conversation.populateWithMessages(ConversationFragment.this.messageList); for (final Message message : this.messageList) { if (message.getEncryption() == Message.ENCRYPTION_PGP @@ -780,6 +764,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa } catch (final NoSuchElementException ignored) { } + askForPassphraseIntent = null; activity.xmppConnectionService.updateMessage(message); } @@ -879,10 +864,6 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa } } - protected void makeFingerprintWarning() { - - } - protected void showSnackbar(final int message, final int action, final OnClickListener clickListener) { snackbar.setVisibility(View.VISIBLE); @@ -1019,6 +1000,9 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa } public void appendText(String text) { + if (text == null) { + return; + } String previous = this.mEditMessage.getText().toString(); if (previous.length() != 0 && !previous.endsWith(" ")) { text = " " + text; diff --git a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java index dbad9e00..7aa7b1c2 100644 --- a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java @@ -468,7 +468,7 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate } else { this.mServerInfoSm.setText(R.string.server_info_unavailable); } - if (features.pubsub()) { + if (features.pep()) { this.mServerInfoPep.setText(R.string.server_info_available); } else { this.mServerInfoPep.setText(R.string.server_info_unavailable); diff --git a/src/main/java/eu/siacs/conversations/ui/PublishProfilePictureActivity.java b/src/main/java/eu/siacs/conversations/ui/PublishProfilePictureActivity.java index 3f72b723..e8ab8dae 100644 --- a/src/main/java/eu/siacs/conversations/ui/PublishProfilePictureActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/PublishProfilePictureActivity.java @@ -163,8 +163,7 @@ public class PublishProfilePictureActivity extends XmppActivity { if (jid != null) { this.account = xmppConnectionService.findAccountByJid(jid); if (this.account.getXmppConnection() != null) { - this.support = this.account.getXmppConnection() - .getFeatures().pubsub(); + this.support = this.account.getXmppConnection().getFeatures().pep(); } if (this.avatarUri == null) { if (this.account.getAvatar() != null diff --git a/src/main/java/eu/siacs/conversations/utils/CryptoHelper.java b/src/main/java/eu/siacs/conversations/utils/CryptoHelper.java index eb7e2c3c..466bc409 100644 --- a/src/main/java/eu/siacs/conversations/utils/CryptoHelper.java +++ b/src/main/java/eu/siacs/conversations/utils/CryptoHelper.java @@ -91,6 +91,9 @@ public final class CryptoHelper { } public static String prettifyFingerprint(String fingerprint) { + if (fingerprint.length() < 40) { + return fingerprint; + } StringBuilder builder = new StringBuilder(fingerprint); builder.insert(8, " "); builder.insert(17, " "); diff --git a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java index 1351226b..cf580df1 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java @@ -90,7 +90,7 @@ public class XmppConnection implements Runnable { private boolean shouldBind = true; private boolean shouldAuthenticate = true; private Element streamFeatures; - private final HashMap<String, List<String>> disco = new HashMap<>(); + private final HashMap<Jid, Info> disco = new HashMap<>(); private String streamId = null; private int smVersion = 3; @@ -334,6 +334,7 @@ public class XmppConnection implements Runnable { } catch (final NumberFormatException ignored) { } sendServiceDiscoveryInfo(account.getServer()); + sendServiceDiscoveryInfo(account.getJid().toBareJid()); sendServiceDiscoveryItems(account.getServer()); sendInitialPing(); } else if (nextTag.isStart("r")) { @@ -734,6 +735,7 @@ public class XmppConnection implements Runnable { features.blockListRequested = false; disco.clear(); sendServiceDiscoveryInfo(account.getServer()); + sendServiceDiscoveryInfo(account.getJid().toBareJid()); sendServiceDiscoveryItems(account.getServer()); if (bindListener != null) { bindListener.onBind(account); @@ -741,34 +743,35 @@ public class XmppConnection implements Runnable { sendInitialPing(); } - private void sendServiceDiscoveryInfo(final Jid server) { - if (disco.containsKey(server.toDomainJid().toString())) { - if (account.getServer().equals(server.toDomainJid())) { + private void sendServiceDiscoveryInfo(final Jid jid) { + if (disco.containsKey(jid)) { + if (account.getServer().equals(jid)) { enableAdvancedStreamFeatures(); } } else { final IqPacket iq = new IqPacket(IqPacket.TYPE.GET); - iq.setTo(server.toDomainJid()); + iq.setTo(jid); iq.query("http://jabber.org/protocol/disco#info"); this.sendIqPacket(iq, new OnIqPacketReceived() { @Override public void onIqPacketReceived(final Account account, final IqPacket packet) { final List<Element> elements = packet.query().getChildren(); - final List<String> features = new ArrayList<>(); + final Info info = new Info(); for (final Element element : elements) { if (element.getName().equals("identity")) { - if ("irc".equals(element.getAttribute("type"))) { - //add fake feature to not confuse irc and real muc - features.add("siacs:no:muc"); + String type = element.getAttribute("type"); + String category = element.getAttribute("category"); + if (type != null && category != null) { + info.identities.add(new Pair<>(category,type)); } } else if (element.getName().equals("feature")) { - features.add(element.getAttribute("var")); + info.features.add(element.getAttribute("var")); } } - disco.put(server.toDomainJid().toString(), features); + disco.put(jid, info); - if (account.getServer().equals(server.toDomainJid())) { + if (account.getServer().equals(jid)) { enableAdvancedStreamFeatures(); for (final OnAdvancedStreamFeaturesLoaded listener : advancedStreamFeaturesLoadedListeners) { listener.onAdvancedStreamFeaturesAvailable(account); @@ -987,9 +990,9 @@ public class XmppConnection implements Runnable { public List<String> findDiscoItemsByFeature(final String feature) { final List<String> items = new ArrayList<>(); - for (final Entry<String, List<String>> cursor : disco.entrySet()) { - if (cursor.getValue().contains(feature)) { - items.add(cursor.getKey()); + for (final Entry<Jid, Info> cursor : disco.entrySet()) { + if (cursor.getValue().features.contains(feature)) { + items.add(cursor.getKey().toString()); } } return items; @@ -1008,10 +1011,12 @@ public class XmppConnection implements Runnable { } public String getMucServer() { - for (final Entry<String, List<String>> cursor : disco.entrySet()) { - final List<String> value = cursor.getValue(); - if (value.contains("http://jabber.org/protocol/muc") && !value.contains("jabber:iq:gateway") && !value.contains("siacs:no:muc")) { - return cursor.getKey(); + for (final Entry<Jid, Info> cursor : disco.entrySet()) { + final Info value = cursor.getValue(); + if (value.features.contains("http://jabber.org/protocol/muc") + && !value.features.contains("jabber:iq:gateway") + && !value.identities.contains(new Pair<>("conference","irc"))) { + return cursor.getKey().toString(); } } return null; @@ -1066,6 +1071,11 @@ public class XmppConnection implements Runnable { this.lastConnect = 0; } + private class Info { + public final ArrayList<String> features = new ArrayList<>(); + public final ArrayList<Pair<String,String>> identities = new ArrayList<>(); + } + public class Features { XmppConnection connection; private boolean carbonsEnabled = false; @@ -1077,8 +1087,8 @@ public class XmppConnection implements Runnable { } private boolean hasDiscoFeature(final Jid server, final String feature) { - return connection.disco.containsKey(server.toDomainJid().toString()) && - connection.disco.get(server.toDomainJid().toString()).contains(feature); + return connection.disco.containsKey(server) && + connection.disco.get(server).features.contains(feature); } public boolean carbons() { @@ -1094,24 +1104,35 @@ public class XmppConnection implements Runnable { } public boolean sm() { - return streamId != null; + return streamId != null + || (connection.streamFeatures != null && connection.streamFeatures.hasChild("sm")); } public boolean csi() { return connection.streamFeatures != null && connection.streamFeatures.hasChild("csi", "urn:xmpp:csi:0"); } - public boolean pubsub() { - return hasDiscoFeature(account.getServer(), - "http://jabber.org/protocol/pubsub#publish"); + public boolean pep() { + final Pair<String,String> needle = new Pair<>("pubsub","pep"); + Info info = disco.get(account.getServer()); + if (info != null && info.identities.contains(needle)) { + return true; + } else { + info = disco.get(account.getJid().toBareJid()); + return info != null && info.identities.contains(needle); + } } public boolean mam() { - return hasDiscoFeature(account.getServer(), "urn:xmpp:mam:0"); + if (hasDiscoFeature(account.getJid().toBareJid(), "urn:xmpp:mam:0")) { + return true; + } else { + return hasDiscoFeature(account.getServer(), "urn:xmpp:mam:0"); + } } public boolean advancedStreamFeaturesLoaded() { - return disco.containsKey(account.getServer().toString()); + return disco.containsKey(account.getServer()); } public boolean rosterVersioning() { diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleInbandTransport.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleInbandTransport.java index 3677bf4f..9866af03 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleInbandTransport.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleInbandTransport.java @@ -11,6 +11,7 @@ import android.util.Base64; import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.DownloadableFile; +import eu.siacs.conversations.persistance.FileBackend; import eu.siacs.conversations.utils.CryptoHelper; import eu.siacs.conversations.xml.Element; import eu.siacs.conversations.xmpp.OnIqPacketReceived; @@ -172,6 +173,7 @@ public class JingleInbandTransport extends JingleTransport { connection.updateProgress((int) ((((double) (this.fileSize - this.remainingSize)) / this.fileSize) * 100)); } } catch (IOException e) { + FileBackend.close(fileInputStream); this.onFileTransmissionStatusChanged.onFileTransferAborted(); } } @@ -198,6 +200,7 @@ public class JingleInbandTransport extends JingleTransport { connection.updateProgress((int) ((((double) (this.fileSize - this.remainingSize)) / this.fileSize) * 100)); } } catch (IOException e) { + FileBackend.close(fileOutputStream); this.onFileTransmissionStatusChanged.onFileTransferAborted(); } } diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java index c3419580..72015a05 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java @@ -11,6 +11,7 @@ import java.security.NoSuchAlgorithmException; import java.util.Arrays; import eu.siacs.conversations.entities.DownloadableFile; +import eu.siacs.conversations.persistance.FileBackend; import eu.siacs.conversations.utils.CryptoHelper; public class JingleSocks5Transport extends JingleTransport { @@ -126,25 +127,19 @@ public class JingleSocks5Transport extends JingleTransport { } catch (NoSuchAlgorithmException e) { callback.onFileTransferAborted(); } finally { - try { - if (fileInputStream != null) { - fileInputStream.close(); - } - } catch (IOException e) { - callback.onFileTransferAborted(); - } + FileBackend.close(fileInputStream); } } }).start(); } - public void receive(final DownloadableFile file, - final OnFileTransmissionStatusChanged callback) { + public void receive(final DownloadableFile file, final OnFileTransmissionStatusChanged callback) { new Thread(new Runnable() { @Override public void run() { + OutputStream fileOutputStream = null; try { MessageDigest digest = MessageDigest.getInstance("SHA-1"); digest.reset(); @@ -152,7 +147,7 @@ public class JingleSocks5Transport extends JingleTransport { socket.setSoTimeout(30000); file.getParentFile().mkdirs(); file.createNewFile(); - OutputStream fileOutputStream = file.createOutputStream(); + fileOutputStream = file.createOutputStream(); if (fileOutputStream == null) { callback.onFileTransferAborted(); return; @@ -183,6 +178,8 @@ public class JingleSocks5Transport extends JingleTransport { callback.onFileTransferAborted(); } catch (NoSuchAlgorithmException e) { callback.onFileTransferAborted(); + } finally { + FileBackend.close(fileOutputStream); } } }).start(); |