@@ -2289,19 +2289,40 @@ impl Chat {
22892289
22902290 /// Sends a `SyncAction` synchronising chat contacts to other devices.
22912291 pub ( crate ) async fn sync_contacts ( & self , context : & Context ) -> Result < ( ) > {
2292- let addrs = context
2293- . sql
2294- . query_map (
2295- "SELECT c.addr \
2296- FROM contacts c INNER JOIN chats_contacts cc \
2297- ON c.id=cc.contact_id \
2298- WHERE cc.chat_id=? AND cc.add_timestamp >= cc.remove_timestamp",
2299- ( self . id , ) ,
2300- |row| row. get :: < _ , String > ( 0 ) ,
2301- |addrs| addrs. collect :: < Result < Vec < _ > , _ > > ( ) . map_err ( Into :: into) ,
2302- )
2303- . await ?;
2304- self . sync ( context, SyncAction :: SetContacts ( addrs) ) . await
2292+ if self . is_encrypted ( context) . await ? {
2293+ let fingerprint_addrs = context
2294+ . sql
2295+ . query_map (
2296+ "SELECT c.fingerprint, c.addr
2297+ FROM contacts c INNER JOIN chats_contacts cc
2298+ ON c.id=cc.contact_id
2299+ WHERE cc.chat_id=? AND cc.add_timestamp >= cc.remove_timestamp" ,
2300+ ( self . id , ) ,
2301+ |row| {
2302+ let fingerprint = row. get ( 0 ) ?;
2303+ let addr = row. get ( 1 ) ?;
2304+ Ok ( ( fingerprint, addr) )
2305+ } ,
2306+ |addrs| addrs. collect :: < Result < Vec < _ > , _ > > ( ) . map_err ( Into :: into) ,
2307+ )
2308+ . await ?;
2309+ self . sync ( context, SyncAction :: SetPgpContacts ( fingerprint_addrs) ) . await ?;
2310+ } else {
2311+ let addrs = context
2312+ . sql
2313+ . query_map (
2314+ "SELECT c.addr \
2315+ FROM contacts c INNER JOIN chats_contacts cc \
2316+ ON c.id=cc.contact_id \
2317+ WHERE cc.chat_id=? AND cc.add_timestamp >= cc.remove_timestamp",
2318+ ( self . id , ) ,
2319+ |row| row. get :: < _ , String > ( 0 ) ,
2320+ |addrs| addrs. collect :: < Result < Vec < _ > , _ > > ( ) . map_err ( Into :: into) ,
2321+ )
2322+ . await ?;
2323+ self . sync ( context, SyncAction :: SetContacts ( addrs) ) . await ?;
2324+ }
2325+ Ok ( ( ) )
23052326 }
23062327
23072328 /// Returns chat id for the purpose of synchronisation across devices.
@@ -4811,6 +4832,10 @@ pub(crate) async fn update_msg_text_and_timestamp(
48114832/// Set chat contacts by their addresses creating the corresponding contacts if necessary.
48124833async fn set_contacts_by_addrs ( context : & Context , id : ChatId , addrs : & [ String ] ) -> Result < ( ) > {
48134834 let chat = Chat :: load_from_db ( context, id) . await ?;
4835+ ensure ! (
4836+ !chat. is_encrypted( context) . await ?,
4837+ "Cannot add email-contacts to encrypted chat {id}"
4838+ ) ;
48144839 ensure ! (
48154840 chat. typ == Chattype :: Broadcast ,
48164841 "{id} is not a broadcast list" ,
@@ -4846,6 +4871,54 @@ async fn set_contacts_by_addrs(context: &Context, id: ChatId, addrs: &[String])
48464871 Ok ( ( ) )
48474872}
48484873
4874+ /// Set chat contacts by their fingerprints creating the corresponding contacts if necessary.
4875+ ///
4876+ /// `fingerprint_addrs` is a list of pairs of fingerprint and address.
4877+ async fn set_contacts_by_fingerprints (
4878+ context : & Context ,
4879+ id : ChatId ,
4880+ fingerprint_addrs : & [ ( String , String ) ] ,
4881+ ) -> Result < ( ) > {
4882+ let chat = Chat :: load_from_db ( context, id) . await ?;
4883+ ensure ! (
4884+ chat. is_encrypted( context) . await ?,
4885+ "Cannot add PGP-contacts to unencrypted chat {id}"
4886+ ) ;
4887+ ensure ! (
4888+ chat. typ == Chattype :: Broadcast ,
4889+ "{id} is not a broadcast list" ,
4890+ ) ;
4891+ let mut contacts = HashSet :: new ( ) ;
4892+ for ( fingerprint, addr) in fingerprint_addrs {
4893+ let contact_addr = ContactAddress :: new ( addr) ?;
4894+ let contact = Contact :: add_or_lookup_ex ( context, "" , & contact_addr, & fingerprint, Origin :: Hidden )
4895+ . await ?
4896+ . 0 ;
4897+ contacts. insert ( contact) ;
4898+ }
4899+ let contacts_old = HashSet :: < ContactId > :: from_iter ( get_chat_contacts ( context, id) . await ?) ;
4900+ if contacts == contacts_old {
4901+ return Ok ( ( ) ) ;
4902+ }
4903+ context
4904+ . sql
4905+ . transaction ( move |transaction| {
4906+ transaction. execute ( "DELETE FROM chats_contacts WHERE chat_id=?" , ( id, ) ) ?;
4907+
4908+ // We do not care about `add_timestamp` column
4909+ // because timestamps are not used for broadcast lists.
4910+ let mut statement = transaction
4911+ . prepare ( "INSERT INTO chats_contacts (chat_id, contact_id) VALUES (?, ?)" ) ?;
4912+ for contact_id in & contacts {
4913+ statement. execute ( ( id, contact_id) ) ?;
4914+ }
4915+ Ok ( ( ) )
4916+ } )
4917+ . await ?;
4918+ context. emit_event ( EventType :: ChatModified ( id) ) ;
4919+ Ok ( ( ) )
4920+ }
4921+
48494922/// A cross-device chat id used for synchronisation.
48504923#[ derive( Debug , Serialize , Deserialize , PartialEq ) ]
48514924pub ( crate ) enum SyncId {
@@ -4876,6 +4949,10 @@ pub(crate) enum SyncAction {
48764949 Rename ( String ) ,
48774950 /// Set chat contacts by their addresses.
48784951 SetContacts ( Vec < String > ) ,
4952+ /// Set chat contacts by their fingerprints.
4953+ ///
4954+ /// The list is a list of pairs of fingerprint and address.
4955+ SetPgpContacts ( Vec < ( String , String ) > ) ,
48794956 Delete ,
48804957}
48814958
@@ -4959,6 +5036,7 @@ impl Context {
49595036 }
49605037 SyncAction :: Rename ( to) => rename_ex ( self , Nosync , chat_id, to) . await ,
49615038 SyncAction :: SetContacts ( addrs) => set_contacts_by_addrs ( self , chat_id, addrs) . await ,
5039+ SyncAction :: SetPgpContacts ( fingerprint_addrs) => set_contacts_by_fingerprints ( self , chat_id, fingerprint_addrs) . await ,
49625040 SyncAction :: Delete => chat_id. delete_ex ( self , Nosync ) . await ,
49635041 }
49645042 }
0 commit comments