théoriquement on peut envoyer des MMS (chiffrés ou non)
This commit is contained in:
parent
c2a888a792
commit
cd4e674759
|
@ -1,6 +1,5 @@
|
|||
package xyz.johnny.norntalk.database
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.arch.persistence.db.SupportSQLiteDatabase
|
||||
import android.arch.persistence.room.Database
|
||||
import android.arch.persistence.room.Room
|
||||
|
@ -17,7 +16,7 @@ import java.lang.ref.WeakReference
|
|||
* Base de données de Norn Talk
|
||||
*/
|
||||
@Database(entities = arrayOf(Message::class, Member::class, Media::class,
|
||||
Conversation::class, Contact::class), version=4, exportSchema=false)
|
||||
Conversation::class, Contact::class), version=5, exportSchema=false)
|
||||
abstract class NornDatabase : RoomDatabase() {
|
||||
|
||||
companion object {
|
||||
|
@ -34,21 +33,35 @@ abstract class NornDatabase : RoomDatabase() {
|
|||
* Migration de la base de données de la version 2 à la version 3.
|
||||
* Rajoute le champs read de l'entité Message.
|
||||
*/
|
||||
private val migration2_3 = object : Migration(2, 3) {
|
||||
private val migrations = arrayOf(
|
||||
object : Migration(2, 3) {
|
||||
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
database.execSQL("alter table Message add column read integer not null default 0")
|
||||
}
|
||||
|
||||
},
|
||||
object: Migration(4, 5) {
|
||||
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
database.execSQL("alter table Media add column name text not null default ''")
|
||||
database.execSQL("alter table Media add column position integer not null default 0")
|
||||
}
|
||||
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
database.execSQL("alter table Message add column read integer not null default 0")
|
||||
}
|
||||
|
||||
}
|
||||
)
|
||||
|
||||
class BuildDBTask : AsyncTask<Context, Void, Unit>() {
|
||||
|
||||
override fun doInBackground(vararg params: Context) {
|
||||
val dbBuilder = Room.databaseBuilder(params[0].applicationContext,
|
||||
NornDatabase::class.java,
|
||||
DB_NAME).fallbackToDestructiveMigration()
|
||||
dbBuilder.addMigrations(migration2_3)
|
||||
val dbBuilder = Room.databaseBuilder(
|
||||
params[0].applicationContext, NornDatabase::class.java, DB_NAME
|
||||
).fallbackToDestructiveMigration()
|
||||
|
||||
for (migration in migrations) {
|
||||
dbBuilder.addMigrations(migration)
|
||||
}
|
||||
|
||||
instance = dbBuilder.build()
|
||||
}
|
||||
|
||||
|
|
|
@ -36,9 +36,17 @@ interface MediaDao {
|
|||
/**
|
||||
* Supprimer un media donné
|
||||
*
|
||||
* @param media Média à supprimer
|
||||
* @param media [Media] à supprimer
|
||||
*/
|
||||
@Delete
|
||||
fun deleteMedia(media: Media)
|
||||
|
||||
/**
|
||||
* Récupére les documents associés à un message
|
||||
*
|
||||
* @param messageId Identifiant du message
|
||||
*/
|
||||
@Query("select * from Media where messageId = :messageId order by position")
|
||||
fun getMediasFromMessage(messageId: Long) : Array<Media>
|
||||
|
||||
}
|
|
@ -11,6 +11,7 @@ import android.arch.persistence.room.PrimaryKey
|
|||
* @property type MIME type du média
|
||||
* @property data Contenu du média
|
||||
* @property messageId Identifiant du message auquel le média est associé
|
||||
* @property position position du document dans le message
|
||||
*/
|
||||
@Entity(foreignKeys = arrayOf(ForeignKey(entity= Message::class,
|
||||
parentColumns = arrayOf("id"),
|
||||
|
@ -20,7 +21,9 @@ data class Media(var type: String,
|
|||
@ColumnInfo(typeAffinity = ColumnInfo.BLOB)
|
||||
var data: ByteArray,
|
||||
@ColumnInfo(index=true)
|
||||
var messageId: Long) {
|
||||
var messageId: Long,
|
||||
var name: String,
|
||||
val position: Int) {
|
||||
|
||||
/**
|
||||
* Identifiant du média
|
||||
|
|
79
app/src/main/java/xyz/johnny/norntalk/messages/NornMedia.kt
Normal file
79
app/src/main/java/xyz/johnny/norntalk/messages/NornMedia.kt
Normal file
|
@ -0,0 +1,79 @@
|
|||
package xyz.johnny.norntalk.messages
|
||||
|
||||
import android.content.Context
|
||||
import xyz.johnny.norntalk.database.NornDatabase
|
||||
import xyz.johnny.norntalk.database.entities.Media
|
||||
import xyz.johnny.norntalk.security.Curve
|
||||
|
||||
/**
|
||||
* Classe permettant de gérer un document contenu dans un MMS
|
||||
*/
|
||||
class NornMedia(data: ByteArray?, val mimeType: String, name: String?) {
|
||||
|
||||
var _data = data
|
||||
val data get() = _data!!
|
||||
|
||||
companion object {
|
||||
|
||||
fun from(media: Media): NornMedia {
|
||||
return NornMedia(media.data, media.type, media.name)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
val name = name ?: "media_%d".format(System.currentTimeMillis())
|
||||
|
||||
/**
|
||||
* Insérer le document dans la base de données
|
||||
*
|
||||
* @param context Contexte courant
|
||||
* @param message Message auquel le [Media] est associé
|
||||
* @param position position de ce [Media] pour le message
|
||||
*/
|
||||
fun insert(context: Context, message: NornMessage, position: Int) {
|
||||
NornDatabase.Helper(context).run { db ->
|
||||
val media = Media(this.mimeType, this.data, message.id, this.name, position)
|
||||
db.mediaDao().insertMedia(media)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Chiffre le contenu du message
|
||||
*
|
||||
* @param context Contexte courant
|
||||
* @param contact Destinataire du message
|
||||
* @return document chiffré
|
||||
*/
|
||||
fun encrypt(context: Context, contact: NornContact): ByteArray {
|
||||
val curve = Curve.getCurve(context)
|
||||
val cipher = curve.getCipher(contact.pubKey!!)
|
||||
return cipher.encrypt(this.data)
|
||||
}
|
||||
|
||||
/**
|
||||
* Chiffre le contenu du message en fonction de la conversation
|
||||
*
|
||||
* @param context Contexte courant
|
||||
* @param message Message auquel le document est associé
|
||||
*/
|
||||
fun getContent(context: Context, message: NornMessage): ByteArray? {
|
||||
return if (message.conversation.secured && message.ciphertext != null)
|
||||
this.encrypt(context, message.contact)
|
||||
else
|
||||
this.data
|
||||
}
|
||||
|
||||
/**
|
||||
* Déchiffre le document
|
||||
*
|
||||
* @param context Contexte courant
|
||||
* @param pubKey clé publique utilisée lors du chiffrement du message
|
||||
* @return document déchiffré
|
||||
*/
|
||||
fun decrypt(context: Context, pubKey: ByteArray): ByteArray {
|
||||
val curve = Curve.getCurve(context)
|
||||
val cipher = curve.getCipher(pubKey)
|
||||
return cipher.decrypt(this.data)
|
||||
}
|
||||
|
||||
}
|
|
@ -11,6 +11,7 @@ import xyz.johnny.norntalk.database.NornDatabase
|
|||
import xyz.johnny.norntalk.database.entities.Message
|
||||
import xyz.johnny.norntalk.security.Curve
|
||||
import java.util.*
|
||||
import kotlin.collections.ArrayList
|
||||
|
||||
|
||||
/**
|
||||
|
@ -127,6 +128,22 @@ class NornMessage constructor(text: String?, var ciphertext: String?, sender: St
|
|||
*/
|
||||
val addresses get() = conversation.members.map { it.number }.toTypedArray()
|
||||
|
||||
private var _medias : ArrayList<NornMedia>? = null
|
||||
private val mediaLock = Object()
|
||||
/**
|
||||
* Medias attachés au message
|
||||
*/
|
||||
val medias get(): ArrayList<NornMedia> {
|
||||
synchronized(mediaLock) {
|
||||
return _medias!!
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sujet du MMS
|
||||
*/
|
||||
var subject: String = ""
|
||||
|
||||
init {
|
||||
if (sender == null) {
|
||||
this.sender = null
|
||||
|
@ -135,6 +152,16 @@ class NornMessage constructor(text: String?, var ciphertext: String?, sender: St
|
|||
this.sender = NornContact.getContact(sender, context)
|
||||
this.contact = this.sender
|
||||
}
|
||||
if (this._dbMessage == null) {
|
||||
this._medias = ArrayList()
|
||||
} else {
|
||||
NornDatabase.Helper(context).run { db ->
|
||||
synchronized(mediaLock) {
|
||||
val medias = db.mediaDao().getMediasFromMessage(this.id)
|
||||
this._medias = ArrayList(medias.map { NornMedia.from(it) })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -210,6 +237,12 @@ class NornMessage constructor(text: String?, var ciphertext: String?, sender: St
|
|||
// Ajouter le message à la conversation
|
||||
this.conversation.messages[this.id] = this
|
||||
|
||||
if (this.medias.isNotEmpty()) {
|
||||
for (i in this.medias.indices) {
|
||||
this.medias[i].insert(context, this, i)
|
||||
}
|
||||
}
|
||||
|
||||
// retourner le message
|
||||
this.dbMessage
|
||||
}
|
||||
|
@ -250,7 +283,6 @@ class NornMessage constructor(text: String?, var ciphertext: String?, sender: St
|
|||
*/
|
||||
fun send(context: Context, insert: Boolean, raw: Boolean = false) {
|
||||
Log.d(this::class.java.simpleName, "sending: " + this)
|
||||
// envoyer le message
|
||||
val transaction = NornTransaction(context)
|
||||
transaction.sendNewMessage(this, insert, raw)
|
||||
}
|
||||
|
@ -286,6 +318,15 @@ class NornMessage constructor(text: String?, var ciphertext: String?, sender: St
|
|||
this.sender!!.setPublicKey(Hex.decode(pubkey), context)
|
||||
}
|
||||
|
||||
/**
|
||||
* Envoyer le message chiffré en fonction de la conversation
|
||||
*
|
||||
* @param raw forcer l'envoi du message en clair
|
||||
*/
|
||||
fun messageBody(raw: Boolean) =
|
||||
if (this.conversation.secured && this.ciphertext != null && !raw) this.ciphertext!!
|
||||
else this.text
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
|
|
@ -19,7 +19,6 @@ package xyz.johnny.norntalk.messages
|
|||
import android.app.Activity
|
||||
import android.app.PendingIntent
|
||||
import android.content.*
|
||||
import android.graphics.Bitmap
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.os.Looper
|
||||
|
@ -72,43 +71,27 @@ class NornTransaction constructor(private val context: Context) {
|
|||
}
|
||||
}
|
||||
|
||||
fun sendNewMessage(message: NornMessage, insert: Boolean, raw: Boolean) {
|
||||
this.sendSmsMessage(message, insert, raw)
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to send a new message depending on settings and provided Message object
|
||||
* If you want to send message as mms, call this from the UI thread
|
||||
* Evoyer un message à partir d'une instance de [NornMessage]
|
||||
*
|
||||
* @param message is the message that you want to send
|
||||
* @param message Message à envoyer
|
||||
* @param insert Si Vrai le message doit être inséré dans la base de données, Faux sinon
|
||||
* cela permet de cacher les messages d'échange de clés à l'utilisateur
|
||||
* @param raw Si Vrai le message sera envoyé en clair, sinon le message sera chiffré en fonction
|
||||
* des propriétés de la conversation
|
||||
*/
|
||||
fun sendNewMessage(message: Message) {
|
||||
this.saveMessage = message.save
|
||||
|
||||
// if message:
|
||||
// 1) Has images attached
|
||||
// or
|
||||
// 1) is enabled to send long messages as mms
|
||||
// 2) number of pages for that sms exceeds value stored in settings for when to send the mms by
|
||||
// 3) prefer voice is disabled
|
||||
// or
|
||||
// 1) more than one address is attached
|
||||
// 2) group messaging is enabled
|
||||
//
|
||||
// then, send as MMS, else send as Voice or SMS
|
||||
if (checkMMS(message)) {
|
||||
fun sendNewMessage(message: NornMessage, insert: Boolean, raw: Boolean) {
|
||||
if (message.medias.isEmpty()) {
|
||||
this.sendSmsMessage(message, insert, raw)
|
||||
} else {
|
||||
try {
|
||||
Looper.prepare()
|
||||
} catch (e: Exception) {
|
||||
}
|
||||
} catch (e: Exception) {}
|
||||
|
||||
RateController.init(context)
|
||||
DownloadManager.init(context)
|
||||
sendMmsMessage(message.text, message.addresses, message.images, message.imageNames, message.parts, message.subject)
|
||||
}// else {
|
||||
// sendSmsMessage(message.text, message.addresses, message.delay)
|
||||
//}
|
||||
|
||||
this.sendMmsMessage(message)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -153,8 +136,7 @@ class NornTransaction constructor(private val context: Context) {
|
|||
|
||||
private fun sendSmsMessage(message: NornMessage, insert: Boolean, raw: Boolean) {
|
||||
// envoyer le message chiffré si la conversation est sécurisée
|
||||
val body = if (message.conversation.secured && message.ciphertext != null && !raw) message.ciphertext!!
|
||||
else message.text
|
||||
val body = message.messageBody(raw)
|
||||
|
||||
// save the message for each of the addresses
|
||||
for (i in message.addresses.indices) {
|
||||
|
@ -258,47 +240,22 @@ class NornTransaction constructor(private val context: Context) {
|
|||
}
|
||||
}
|
||||
|
||||
private fun sendMmsMessage(text: String?, addresses: Array<String>, image: Array<Bitmap>, imageNames: Array<String>?, parts: List<Message.Part>?, subject: String) {
|
||||
// merge the string[] of addresses into a single string so they can be inserted into the database easier
|
||||
var address = ""
|
||||
|
||||
for (i in addresses.indices) {
|
||||
address += addresses[i] + " "
|
||||
}
|
||||
|
||||
address = address.trim { it <= ' ' }
|
||||
|
||||
// create the parts to send
|
||||
private fun sendMmsMessage(message: NornMessage) {
|
||||
// create the medias to send
|
||||
val data = ArrayList<MMSPart>()
|
||||
|
||||
for (i in image.indices) {
|
||||
// turn bitmap into byte array to be stored
|
||||
val imageBytes = Message.bitmapToByteArray(image[i])
|
||||
|
||||
val part = MMSPart()
|
||||
part.MimeType = "image/jpeg"
|
||||
part.Name = if (imageNames != null) imageNames[i] else "image_" + System.currentTimeMillis()
|
||||
part.Data = imageBytes
|
||||
data.add(part)
|
||||
}
|
||||
|
||||
// add any extra media according to their mimeType set in the message
|
||||
// eg. videos, audio, contact cards, location maybe?
|
||||
if (parts != null) {
|
||||
for (p in parts) {
|
||||
val part = MMSPart()
|
||||
if (p.name != null) {
|
||||
part.Name = p.name
|
||||
} else {
|
||||
part.Name = p.contentType.split("/".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()[0]
|
||||
}
|
||||
part.MimeType = p.contentType
|
||||
part.Data = p.media
|
||||
data.add(part)
|
||||
}
|
||||
for (m in message.medias) {
|
||||
val part = MMSPart()
|
||||
part.Name = m.name
|
||||
part.MimeType = m.mimeType
|
||||
part.Data = m.getContent(context, message)
|
||||
data.add(part)
|
||||
}
|
||||
|
||||
if (text != null && text != "") {
|
||||
val text = message.messageBody(false)
|
||||
if (message.text != "") {
|
||||
// add text to the end of the part and send
|
||||
val part = MMSPart()
|
||||
part.Name = "text"
|
||||
|
@ -308,8 +265,7 @@ class NornTransaction constructor(private val context: Context) {
|
|||
}
|
||||
|
||||
Log.v(TAG, "using system method for sending")
|
||||
sendMmsThroughSystem(context, subject, data, addresses, explicitSentMmsReceiver)
|
||||
|
||||
sendMmsThroughSystem(context, message.subject, data, message.addresses, explicitSentMmsReceiver)
|
||||
}
|
||||
|
||||
class MessageInfo {
|
||||
|
|
Loading…
Reference in a new issue