diff --git a/src/db.rs b/src/db.rs index c18ff27..dcd6f7a 100644 --- a/src/db.rs +++ b/src/db.rs @@ -775,6 +775,16 @@ pub async fn message_find_by_originid(db: &Db, user: &str, jidfrom: &str, origin })) } +/// Find a note to self by the id of its stanza +pub async fn message_find_note_by_messageid(db: &Db, user: &str, messageid: &str) -> Result> { + let sql = db.sql(&format!( + "SELECT {MESSAGE_COLUMNS} FROM messages WHERE user_id = ? AND jidfrom = ? AND jidto = ? AND messageid = ? LIMIT 1" + )); + Ok(on!(db, p => { + sqlx::query_as::<_, Message>(sql).bind(user).bind(user).bind(user).bind(messageid).fetch_optional(p).await? + })) +} + pub async fn message_by_mid(db: &Db, user: &str, mid: i64) -> Result> { let sql = db.sql(&format!("SELECT {MESSAGE_COLUMNS} FROM messages WHERE user_id = ? AND mid = ?")); Ok(on!(db, p => sqlx::query_as::<_, Message>(sql).bind(user).bind(mid).fetch_optional(p).await?)) @@ -1535,6 +1545,12 @@ pub mod tests { messages_clear(db, me, me, me).await.unwrap(); assert_eq!(messages_count(db, me, me).await.unwrap(), 0); assert_eq!(messages_count(db, me, bob).await.unwrap(), 2); + + // Found by stanza id, but only among the notes + message_save(db, &Message { id: "n4".into(), messageid: Some("s1".into()), jidfrom: me.into(), jidto: me.into(), ..m.clone() }).await.unwrap(); + message_save(db, &Message { id: "n5".into(), messageid: Some("s2".into()), jidfrom: me.into(), jidto: bob.into(), ..m.clone() }).await.unwrap(); + assert_eq!(message_find_note_by_messageid(db, me, "s1").await.unwrap().map(|n| n.id), Some("n4".to_string())); + assert!(message_find_note_by_messageid(db, me, "s2").await.unwrap().is_none()); } #[test] diff --git a/src/handler.rs b/src/handler.rs index e0bd8f4..d463c79 100644 --- a/src/handler.rs +++ b/src/handler.rs @@ -574,6 +574,13 @@ pub async fn handle_message(ctx: &Ctx, m: &Element, origin: Origin, outer_stamp: existing = db::message_find_by_originid(ctx.db(), &me, &jidfrom, oid).await.ok().flatten(); } } + // A note to self sent by another of our clients comes both directly and as a carbon, + // the only thing they share without origin-id is the id of the stanza + if existing.is_none() && jidfrom == me && jidto == me { + if let Some(id) = &message_id { + existing = db::message_find_note_by_messageid(ctx.db(), &me, id).await.ok().flatten(); + } + } let is_new = existing.is_none(); let mut msg = existing.unwrap_or_else(|| db::Message {