@@ -1588,8 +1588,10 @@ fn migrate_key_contacts(
1588
1588
Ok ( ( id, typ, grpid, protected) )
1589
1589
} )
1590
1590
. context ( "Step 23" ) ?;
1591
- let mut load_chat_contacts_stmt = transaction
1592
- . prepare ( "SELECT contact_id FROM chats_contacts WHERE chat_id=? AND contact_id>9" ) ?;
1591
+ let mut load_chat_contacts_stmt = transaction. prepare (
1592
+ "SELECT contact_id, add_timestamp>=remove_timestamp FROM chats_contacts
1593
+ WHERE chat_id=? AND contact_id>9" ,
1594
+ ) ?;
1593
1595
let is_chatmail: Option < String > = transaction
1594
1596
. query_row (
1595
1597
"SELECT value FROM config WHERE keyname='is_chatmail'" ,
@@ -1603,23 +1605,20 @@ fn migrate_key_contacts(
1603
1605
. unwrap_or_default ( )
1604
1606
!= 0 ;
1605
1607
let map_to_key_contact = |old_member : & u32 | {
1606
- (
1607
- * old_member,
1608
- autocrypt_key_contacts
1609
- . get ( old_member)
1610
- . or_else ( || {
1611
- // For chatmail servers,
1612
- // we send encrypted even if the peerstate is reset,
1613
- // because an unencrypted message likely won't arrive.
1614
- // This is the same behavior as before key-contacts migration.
1615
- if is_chatmail {
1616
- autocrypt_key_contacts_with_reset_peerstate. get ( old_member)
1617
- } else {
1618
- None
1619
- }
1620
- } )
1621
- . copied ( ) ,
1622
- )
1608
+ autocrypt_key_contacts
1609
+ . get ( old_member)
1610
+ . or_else ( || {
1611
+ // For chatmail servers,
1612
+ // we send encrypted even if the peerstate is reset,
1613
+ // because an unencrypted message likely won't arrive.
1614
+ // This is the same behavior as before key-contacts migration.
1615
+ if is_chatmail {
1616
+ autocrypt_key_contacts_with_reset_peerstate. get ( old_member)
1617
+ } else {
1618
+ None
1619
+ }
1620
+ } )
1621
+ . copied ( )
1623
1622
} ;
1624
1623
1625
1624
let mut update_member_stmt = transaction
@@ -1628,23 +1627,27 @@ fn migrate_key_contacts(
1628
1627
. prepare ( "SELECT c.addr=d.addr FROM contacts c, contacts d WHERE c.id=? AND d.id=?" ) ?;
1629
1628
for chat in all_chats {
1630
1629
let ( chat_id, typ, grpid, protected) = chat. context ( "Step 24" ) ?;
1631
- // In groups, this also contains past members
1632
- let old_members: Vec < u32 > = load_chat_contacts_stmt
1633
- . query_map ( ( chat_id, ) , |row| row. get :: < _ , u32 > ( 0 ) )
1630
+ // In groups, this also contains past members, i.e. `(_, false)` entries.
1631
+ let old_members: Vec < ( u32 , bool ) > = load_chat_contacts_stmt
1632
+ . query_map ( ( chat_id, ) , |row| {
1633
+ let id: u32 = row. get ( 0 ) ?;
1634
+ let present: bool = row. get ( 1 ) ?;
1635
+ Ok ( ( id, present) )
1636
+ } )
1634
1637
. context ( "Step 25" ) ?
1635
- . collect :: < Result < Vec < u32 > , rusqlite :: Error > > ( )
1638
+ . collect :: < Result < Vec < _ > , _ > > ( )
1636
1639
. context ( "Step 26" ) ?;
1637
1640
1638
1641
let mut keep_address_contacts = |reason : & str | {
1639
1642
info ! (
1640
1643
context,
1641
- "Chat {chat_id} will be an unencrypted chat with contacts identified by email address: {reason}"
1644
+ "Chat {chat_id} will be an unencrypted chat with contacts identified by email address: {reason}. "
1642
1645
) ;
1643
- for m in & old_members {
1646
+ for ( m , _ ) in & old_members {
1644
1647
orphaned_contacts. remove ( m) ;
1645
1648
}
1646
1649
} ;
1647
- let old_and_new_members: Vec < ( u32 , Option < u32 > ) > = match typ {
1650
+ let old_and_new_members: Vec < ( u32 , bool , Option < u32 > ) > = match typ {
1648
1651
// 1:1 chats retain:
1649
1652
// - address-contact if peerstate is in the "reset" state,
1650
1653
// or if there is no key-contact that has the right email address.
@@ -1653,15 +1656,15 @@ fn migrate_key_contacts(
1653
1656
// Since the autocrypt and verified key-contact are identital in this case, we can add the Autocrypt key-contact,
1654
1657
// and the effect will be the same.
1655
1658
100 => {
1656
- let Some ( old_member) = old_members. first ( ) else {
1659
+ let Some ( ( old_member, _ ) ) = old_members. first ( ) else {
1657
1660
info ! (
1658
1661
context,
1659
- "1:1 chat {chat_id} doesn't contain contact, probably it's self or device chat"
1662
+ "1:1 chat {chat_id} doesn't contain contact, probably it's self or device chat. "
1660
1663
) ;
1661
1664
continue ;
1662
1665
} ;
1663
1666
1664
- let ( _ , Some ( new_contact) ) = map_to_key_contact ( old_member) else {
1667
+ let Some ( new_contact) = map_to_key_contact ( old_member) else {
1665
1668
keep_address_contacts ( "No peerstate, or peerstate in 'reset' state" ) ;
1666
1669
continue ;
1667
1670
} ;
@@ -1677,7 +1680,7 @@ fn migrate_key_contacts(
1677
1680
keep_address_contacts ( "key contact has different email" ) ;
1678
1681
continue ;
1679
1682
}
1680
- vec ! [ ( * old_member, Some ( new_contact) ) ]
1683
+ vec ! [ ( * old_member, true , Some ( new_contact) ) ]
1681
1684
}
1682
1685
1683
1686
// Group
@@ -1690,15 +1693,15 @@ fn migrate_key_contacts(
1690
1693
} else if protected == 1 {
1691
1694
old_members
1692
1695
. iter ( )
1693
- . map ( |old_member | {
1694
- ( * old_member , verified_key_contacts. get ( old_member ) . copied ( ) )
1696
+ . map ( |& ( id , present ) | {
1697
+ ( id , present , verified_key_contacts. get ( & id ) . copied ( ) )
1695
1698
} )
1696
1699
. collect ( )
1697
1700
} else {
1698
1701
old_members
1699
1702
. iter ( )
1700
- . map ( map_to_key_contact)
1701
- . collect :: < Vec < ( u32 , Option < u32 > ) > > ( )
1703
+ . map ( | & ( id , present ) | ( id , present , map_to_key_contact ( & id ) ) )
1704
+ . collect :: < Vec < ( u32 , bool , Option < u32 > ) > > ( )
1702
1705
}
1703
1706
}
1704
1707
@@ -1711,9 +1714,10 @@ fn migrate_key_contacts(
1711
1714
// Broadcast list
1712
1715
160 => old_members
1713
1716
. iter ( )
1714
- . map ( |original| {
1717
+ . map ( |( original, _ ) | {
1715
1718
(
1716
1719
* original,
1720
+ true ,
1717
1721
autocrypt_key_contacts
1718
1722
. get ( original)
1719
1723
// There will be no unencrypted broadcast lists anymore,
@@ -1725,7 +1729,7 @@ fn migrate_key_contacts(
1725
1729
. copied ( ) ,
1726
1730
)
1727
1731
} )
1728
- . collect :: < Vec < ( u32 , Option < u32 > ) > > ( ) ,
1732
+ . collect :: < Vec < ( u32 , bool , Option < u32 > ) > > ( ) ,
1729
1733
_ => {
1730
1734
warn ! ( context, "Invalid chat type {typ}" ) ;
1731
1735
continue ;
@@ -1734,7 +1738,11 @@ fn migrate_key_contacts(
1734
1738
1735
1739
// If a group contains a contact without a key or with 'reset' peerstate,
1736
1740
// downgrade to unencrypted Ad-Hoc group.
1737
- if typ == 120 && old_and_new_members. iter ( ) . any ( |( _old, new) | new. is_none ( ) ) {
1741
+ if typ == 120
1742
+ && old_and_new_members
1743
+ . iter ( )
1744
+ . any ( |& ( _old, present, new) | present && new. is_none ( ) )
1745
+ {
1738
1746
transaction
1739
1747
. execute ( "UPDATE chats SET grpid='' WHERE id=?" , ( chat_id, ) )
1740
1748
. context ( "Step 26.1" ) ?;
@@ -1744,15 +1752,15 @@ fn migrate_key_contacts(
1744
1752
1745
1753
let human_readable_transitions = old_and_new_members
1746
1754
. iter ( )
1747
- . map ( |( old, new) | format ! ( "{old}->{}" , new. unwrap_or_default( ) ) )
1755
+ . map ( |( old, _ , new) | format ! ( "{old}->{}" , new. unwrap_or_default( ) ) )
1748
1756
. collect :: < Vec < String > > ( )
1749
1757
. join ( " " ) ;
1750
1758
info ! (
1751
1759
context,
1752
1760
"Migrating chat {chat_id} to key-contacts: {human_readable_transitions}"
1753
1761
) ;
1754
1762
1755
- for ( old_member, new_member) in old_and_new_members {
1763
+ for ( old_member, _ , new_member) in old_and_new_members {
1756
1764
if let Some ( new_member) = new_member {
1757
1765
orphaned_contacts. remove ( & new_member) ;
1758
1766
let res = update_member_stmt. execute ( ( new_member, old_member, chat_id) ) ;
0 commit comments