Search in sources :

Example 1 with Base64

use of android.util.Base64 in project kdeconnect-android by KDE.

the class SmsMmsUtils method sendMessage.

/**
 * Sends SMS or MMS message.
 *
 * @param context       context in which the method is called.
 * @param textMessage   text body of the message to be sent.
 * @param addressList   List of addresses.
 * @param attachedFiles List of attachments. Pass empty list if none.
 * @param subID         Note that here subID is of type int and not long because klinker library requires it as int
 *                      I don't really know the exact reason why they implemented it as int instead of long
 */
public static void sendMessage(Context context, String textMessage, @NonNull List<SMSHelper.Attachment> attachedFiles, List<SMSHelper.Address> addressList, int subID) {
    SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
    boolean longTextAsMms = prefs.getBoolean(context.getString(R.string.set_long_text_as_mms), false);
    boolean groupMessageAsMms = prefs.getBoolean(context.getString(R.string.set_group_message_as_mms), true);
    int sendLongAsMmsAfter = Integer.parseInt(prefs.getString(context.getString(R.string.convert_to_mms_after), context.getString(R.string.convert_to_mms_after_default)));
    TelephonyHelper.LocalPhoneNumber sendingPhoneNumber;
    List<TelephonyHelper.LocalPhoneNumber> allPhoneNumbers = TelephonyHelper.getAllPhoneNumbers(context);
    Optional<TelephonyHelper.LocalPhoneNumber> maybeSendingPhoneNumber = allPhoneNumbers.stream().filter(localPhoneNumber -> localPhoneNumber.subscriptionID == subID).findAny();
    if (maybeSendingPhoneNumber.isPresent()) {
        sendingPhoneNumber = maybeSendingPhoneNumber.get();
    } else {
        if (allPhoneNumbers.isEmpty()) {
            // We were not able to get any phone number for the user's device
            // Use a null "dummy" number instead. This should behave the same as not setting
            // the FromAddress (below) since the default value there is null.
            // The only more-correct thing we could do here is query the user (maybe in a
            // persistent configuration) for their phone number(s).
            sendingPhoneNumber = new TelephonyHelper.LocalPhoneNumber(null, subID);
            Log.w(SENDING_MESSAGE, "We do not know *any* phone numbers for this device. " + "Attempting to send a message without knowing the local phone number is likely " + "to result in strange behavior, such as the message being sent to yourself, " + "or might entirely fail to send (or be received).");
        } else {
            // Pick an arbitrary phone number
            sendingPhoneNumber = allPhoneNumbers.get(0);
        }
        Log.w(SENDING_MESSAGE, "Unable to determine correct outgoing address for sub ID " + subID + ". Using " + sendingPhoneNumber);
    }
    if (sendingPhoneNumber.number != null) {
        // If the message is going to more than one target (to allow the user to send a message to themselves)
        if (addressList.size() > 1) {
            // Remove the user's phone number if present in the list of recipients
            addressList.removeIf(address -> sendingPhoneNumber.isMatchingPhoneNumber(address.address));
        }
    }
    try {
        Settings settings = new Settings();
        TelephonyHelper.ApnSetting apnSettings = TelephonyHelper.getPreferredApn(context, subID);
        if (apnSettings != null) {
            settings.setMmsc(apnSettings.getMmsc().toString());
            settings.setProxy(apnSettings.getMmsProxyAddressAsString());
            settings.setPort(Integer.toString(apnSettings.getMmsProxyPort()));
        } else {
            settings.setUseSystemSending(true);
        }
        settings.setSendLongAsMms(longTextAsMms);
        settings.setSendLongAsMmsAfter(sendLongAsMmsAfter);
        settings.setGroup(groupMessageAsMms);
        if (subID != -1) {
            settings.setSubscriptionId(subID);
        }
        Transaction transaction = new Transaction(context, settings);
        List<String> addresses = new ArrayList<>();
        for (SMSHelper.Address address : addressList) {
            addresses.add(address.toString());
        }
        Message message = new Message(textMessage, addresses.toArray(ArrayUtils.EMPTY_STRING_ARRAY));
        // If there are any attachment files add those into the message
        for (SMSHelper.Attachment attachedFile : attachedFiles) {
            byte[] file = Base64.decode(attachedFile.getBase64EncodedFile(), Base64.DEFAULT);
            String mimeType = attachedFile.getMimeType();
            String fileName = attachedFile.getUniqueIdentifier();
            message.addMedia(file, mimeType, fileName);
        }
        message.setFromAddress(sendingPhoneNumber.number);
        message.setSave(true);
        // This is the reason why there are separate branch handling for SMS and MMS.
        if (transaction.checkMMS(message)) {
            Log.v("", "Sending new MMS");
            // transaction.sendNewMessage(message, Transaction.NO_THREAD_ID);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
                sendMmsMessageNative(context, message, settings);
            } else {
                // Cross fingers and hope Klinker's library works for this case
                transaction.sendNewMessage(message, Transaction.NO_THREAD_ID);
            }
        } else {
            Log.v(SENDING_MESSAGE, "Sending new SMS");
            transaction.sendNewMessage(message, Transaction.NO_THREAD_ID);
        }
    // TODO: Notify other end
    } catch (Exception e) {
        // TODO: Notify other end
        Log.e(SENDING_MESSAGE, "Exception", e);
    }
}
Also used : Telephony(android.provider.Telephony) RequiresApi(androidx.annotation.RequiresApi) Bundle(android.os.Bundle) Message(com.klinker.android.send_message.Message) NonNull(androidx.annotation.NonNull) PduPart(com.google.android.mms.pdu_alt.PduPart) Uri(android.net.Uri) SmsManager(android.telephony.SmsManager) Random(java.util.Random) Utils(com.klinker.android.send_message.Utils) Transaction(com.klinker.android.send_message.Transaction) ByteArrayInputStream(java.io.ByteArrayInputStream) ContentResolver(android.content.ContentResolver) SmilXmlSerializer(com.android.mms.dom.smil.parser.SmilXmlSerializer) PreferenceManager(android.preference.PreferenceManager) Log(android.util.Log) SendReq(com.google.android.mms.pdu_alt.SendReq) IOUtils(org.apache.commons.io.IOUtils) List(java.util.List) ContentType(com.google.android.mms.ContentType) SmilHelper(com.google.android.mms.smil.SmilHelper) Optional(java.util.Optional) ContentValues(android.content.ContentValues) MultimediaMessagePdu(com.google.android.mms.pdu_alt.MultimediaMessagePdu) SMSHelper(org.kde.kdeconnect.Helpers.SMSHelper) Context(android.content.Context) ByteArrayOutputStream(java.io.ByteArrayOutputStream) BitmapFactory(android.graphics.BitmapFactory) ArrayUtils(org.apache.commons.lang3.ArrayUtils) MMSPart(com.google.android.mms.MMSPart) TelephonyHelper(org.kde.kdeconnect.Helpers.TelephonyHelper) R(org.kde.kdeconnect_tp.R) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet) Build(android.os.Build) InvalidHeaderValueException(com.google.android.mms.InvalidHeaderValueException) PduHeaders(com.google.android.mms.pdu_alt.PduHeaders) NetworkPacket(org.kde.kdeconnect.NetworkPacket) RetrieveConf(com.google.android.mms.pdu_alt.RetrieveConf) EncodedStringValue(com.google.android.mms.pdu_alt.EncodedStringValue) FileOutputStream(java.io.FileOutputStream) TextUtils(android.text.TextUtils) IOException(java.io.IOException) File(java.io.File) SharedPreferences(android.content.SharedPreferences) Bitmap(android.graphics.Bitmap) Base64(android.util.Base64) CharacterSets(com.google.android.mms.pdu_alt.CharacterSets) PduComposer(com.google.android.mms.pdu_alt.PduComposer) Settings(com.klinker.android.send_message.Settings) PduBody(com.google.android.mms.pdu_alt.PduBody) ContentUris(android.content.ContentUris) InputStream(java.io.InputStream) Message(com.klinker.android.send_message.Message) SharedPreferences(android.content.SharedPreferences) ArrayList(java.util.ArrayList) SMSHelper(org.kde.kdeconnect.Helpers.SMSHelper) InvalidHeaderValueException(com.google.android.mms.InvalidHeaderValueException) IOException(java.io.IOException) Transaction(com.klinker.android.send_message.Transaction) TelephonyHelper(org.kde.kdeconnect.Helpers.TelephonyHelper) Settings(com.klinker.android.send_message.Settings)

Example 2 with Base64

use of android.util.Base64 in project kdeconnect-android by KDE.

the class LanLinkProvider method identityPacketReceived.

/**
 * Called when a new 'identity' packet is received. Those are passed here by
 * {@link #tcpPacketReceived(Socket)} and {@link #udpPacketReceived(DatagramPacket)}.
 * <p>
 * If the remote device should be connected, this calls {@link #addLink}.
 * Otherwise, if there was an Exception, we unpair from that device.
 * </p>
 *
 * @param identityPacket    identity of a remote device
 * @param socket            a new Socket, which should be used to receive packets from the remote device
 * @param connectionStarted which side started this connection
 */
private void identityPacketReceived(final NetworkPacket identityPacket, final Socket socket, final LanLink.ConnectionStarted connectionStarted) {
    String myId = DeviceHelper.getDeviceId(context);
    final String deviceId = identityPacket.getString("deviceId");
    if (deviceId.equals(myId)) {
        Log.e("KDE/LanLinkProvider", "Somehow I'm connected to myself, ignoring. This should not happen.");
        return;
    }
    // If I'm the TCP server I will be the SSL client and viceversa.
    final boolean clientMode = (connectionStarted == LanLink.ConnectionStarted.Locally);
    // Do the SSL handshake
    try {
        SharedPreferences preferences = context.getSharedPreferences("trusted_devices", Context.MODE_PRIVATE);
        boolean isDeviceTrusted = preferences.getBoolean(deviceId, false);
        if (isDeviceTrusted && !SslHelper.isCertificateStored(context, deviceId)) {
            // Device paired with and old version, we can't use it as we lack the certificate
            BackgroundService.RunCommand(context, service -> {
                Device device = service.getDevice(deviceId);
                if (device == null)
                    return;
                device.unpair();
                // Retry as unpaired
                identityPacketReceived(identityPacket, socket, connectionStarted);
            });
        }
        Log.i("KDE/LanLinkProvider", "Starting SSL handshake with " + identityPacket.getString("deviceName") + " trusted:" + isDeviceTrusted);
        final SSLSocket sslsocket = SslHelper.convertToSslSocket(context, socket, deviceId, isDeviceTrusted, clientMode);
        sslsocket.addHandshakeCompletedListener(event -> {
            String mode = clientMode ? "client" : "server";
            try {
                Certificate certificate = event.getPeerCertificates()[0];
                identityPacket.set("certificate", Base64.encodeToString(certificate.getEncoded(), 0));
                Log.i("KDE/LanLinkProvider", "Handshake as " + mode + " successful with " + identityPacket.getString("deviceName") + " secured with " + event.getCipherSuite());
                addLink(identityPacket, sslsocket, connectionStarted);
            } catch (Exception e) {
                Log.e("KDE/LanLinkProvider", "Handshake as " + mode + " failed with " + identityPacket.getString("deviceName"), e);
                BackgroundService.RunCommand(context, service -> {
                    Device device = service.getDevice(deviceId);
                    if (device == null)
                        return;
                    device.unpair();
                });
            }
        });
        // Handshake is blocking, so do it on another thread and free this thread to keep receiving new connection
        new Thread(() -> {
            try {
                synchronized (this) {
                    sslsocket.startHandshake();
                }
            } catch (Exception e) {
                Log.e("KDE/LanLinkProvider", "Handshake failed with " + identityPacket.getString("deviceName"), e);
            // String[] ciphers = sslsocket.getSupportedCipherSuites();
            // for (String cipher : ciphers) {
            // Log.i("SupportedCiphers","cipher: " + cipher);
            // }
            }
        }).start();
    } catch (Exception e) {
        Log.e("LanLink", "Exception", e);
    }
}
Also used : Context(android.content.Context) Socket(java.net.Socket) SSLSocket(javax.net.ssl.SSLSocket) HashMap(java.util.HashMap) Timer(java.util.Timer) Device(org.kde.kdeconnect.Device) ArrayList(java.util.ArrayList) Charsets(kotlin.text.Charsets) DatagramSocket(java.net.DatagramSocket) InetAddress(java.net.InetAddress) ServerSocket(java.net.ServerSocket) SocketException(java.net.SocketException) DeviceHelper(org.kde.kdeconnect.Helpers.DeviceHelper) CustomDevicesActivity(org.kde.kdeconnect.UserInterface.CustomDevicesActivity) PreferenceManager(android.preference.PreferenceManager) TimerTask(java.util.TimerTask) NetworkPacket(org.kde.kdeconnect.NetworkPacket) Log(android.util.Log) OutputStream(java.io.OutputStream) IOException(java.io.IOException) SslHelper(org.kde.kdeconnect.Helpers.SecurityHelpers.SslHelper) InputStreamReader(java.io.InputStreamReader) InetSocketAddress(java.net.InetSocketAddress) BackgroundService(org.kde.kdeconnect.BackgroundService) SocketFactory(javax.net.SocketFactory) Certificate(java.security.cert.Certificate) SharedPreferences(android.content.SharedPreferences) Base64(android.util.Base64) BaseLinkProvider(org.kde.kdeconnect.Backends.BaseLinkProvider) BaseLink(org.kde.kdeconnect.Backends.BaseLink) BufferedReader(java.io.BufferedReader) DatagramPacket(java.net.DatagramPacket) TrustedNetworkHelper(org.kde.kdeconnect.Helpers.TrustedNetworkHelper) SharedPreferences(android.content.SharedPreferences) Device(org.kde.kdeconnect.Device) SSLSocket(javax.net.ssl.SSLSocket) SocketException(java.net.SocketException) IOException(java.io.IOException) Certificate(java.security.cert.Certificate)

Aggregations

Context (android.content.Context)2 SharedPreferences (android.content.SharedPreferences)2 PreferenceManager (android.preference.PreferenceManager)2 Base64 (android.util.Base64)2 Log (android.util.Log)2 ContentResolver (android.content.ContentResolver)1 ContentUris (android.content.ContentUris)1 ContentValues (android.content.ContentValues)1 Bitmap (android.graphics.Bitmap)1 BitmapFactory (android.graphics.BitmapFactory)1 Uri (android.net.Uri)1 Build (android.os.Build)1 Bundle (android.os.Bundle)1 Telephony (android.provider.Telephony)1 SmsManager (android.telephony.SmsManager)1 TextUtils (android.text.TextUtils)1 NonNull (androidx.annotation.NonNull)1 RequiresApi (androidx.annotation.RequiresApi)1 SmilXmlSerializer (com.android.mms.dom.smil.parser.SmilXmlSerializer)1 ContentType (com.google.android.mms.ContentType)1