@@ -1559,6 +1559,7 @@ fn migrate_pgp_contacts(
1559
1559
. context ( "Step 20" ) ?
1560
1560
. collect :: < Result < BTreeSet < u32 > , rusqlite:: Error > > ( )
1561
1561
. context ( "Step 21" ) ?;
1562
+
1562
1563
{
1563
1564
let mut stmt = transaction
1564
1565
. prepare (
@@ -1578,6 +1579,37 @@ fn migrate_pgp_contacts(
1578
1579
. context ( "Step 23" ) ?;
1579
1580
let mut load_chat_contacts_stmt = transaction
1580
1581
. prepare ( "SELECT contact_id FROM chats_contacts WHERE chat_id=? AND contact_id>9" ) ?;
1582
+ let is_chatmail: Option < String > = transaction
1583
+ . query_row (
1584
+ "SELECT value FROM config WHERE keyname='is_chatmail'" ,
1585
+ ( ) ,
1586
+ |row| row. get ( 0 ) ,
1587
+ )
1588
+ . optional ( )
1589
+ . context ( "Step 23.1" ) ?;
1590
+ let is_chatmail = is_chatmail
1591
+ . and_then ( |s| s. parse :: < i32 > ( ) . ok ( ) )
1592
+ . unwrap_or_default ( )
1593
+ != 0 ;
1594
+ let map_to_pgp_contact = |old_member : & u32 | {
1595
+ (
1596
+ * old_member,
1597
+ autocrypt_pgp_contacts
1598
+ . get ( old_member)
1599
+ . or_else ( || {
1600
+ // For chatmail servers,
1601
+ // we send encrypted even if the peerstate is reset,
1602
+ // because an unencrypted message likely won't arrive.
1603
+ // This is the same behavior as before PGP-contacts migration.
1604
+ if is_chatmail {
1605
+ autocrypt_pgp_contacts_with_reset_peerstate. get ( old_member)
1606
+ } else {
1607
+ None
1608
+ }
1609
+ } )
1610
+ . copied ( ) ,
1611
+ )
1612
+ } ;
1581
1613
1582
1614
let mut update_member_stmt = transaction
1583
1615
. prepare ( "UPDATE chats_contacts SET contact_id=? WHERE contact_id=? AND chat_id=?" ) ?;
@@ -1598,29 +1630,6 @@ fn migrate_pgp_contacts(
1598
1630
orphaned_contacts. remove ( m) ;
1599
1631
}
1600
1632
} ;
1601
- let retain_autocrypt_pgp_contacts = || {
1602
- old_members
1603
- . iter ( )
1604
- . map ( |original| {
1605
- (
1606
- * original,
1607
- autocrypt_pgp_contacts
1608
- . get ( original)
1609
- // TODO it's unclear whether we want to do this:
1610
- // We could also make the group unencrypted
1611
- // if any peerstate is reset.
1612
- // Also, right now, if we have no key at all,
1613
- // the member will be silently removed from the group;
1614
- // maybe we should at least post an info message?
1615
- . or_else ( || {
1616
- autocrypt_pgp_contacts_with_reset_peerstate. get ( original)
1617
- } )
1618
- . copied ( ) ,
1619
- )
1620
- } )
1621
- . collect :: < Vec < ( u32 , Option < u32 > ) > > ( )
1622
- } ;
1623
-
1624
1633
let old_and_new_members: Vec < ( u32 , Option < u32 > ) > = match typ {
1625
1634
// 1:1 chats retain:
1626
1635
// - email-contact if peerstate is in the "reset" state,
@@ -1634,7 +1643,8 @@ fn migrate_pgp_contacts(
1634
1643
info ! ( context, "1:1 chat {chat_id} doesn't contain contact, probably it's self or device chat" ) ;
1635
1644
continue ;
1636
1645
} ;
1637
- let Some ( & new_contact) = autocrypt_pgp_contacts. get ( old_member) else {
1646
+
1647
+ let ( _, Some ( new_contact) ) = map_to_pgp_contact ( old_member) else {
1638
1648
keep_email_contacts ( "No peerstate, or peerstate in 'reset' state" ) ;
1639
1649
continue ;
1640
1650
} ;
@@ -1668,7 +1678,10 @@ fn migrate_pgp_contacts(
1668
1678
} )
1669
1679
. collect ( )
1670
1680
} else {
1671
- retain_autocrypt_pgp_contacts ( )
1681
+ old_members
1682
+ . iter ( )
1683
+ . map ( map_to_pgp_contact)
1684
+ . collect :: < Vec < ( u32 , Option < u32 > ) > > ( )
1672
1685
}
1673
1686
}
1674
1687
@@ -1679,16 +1692,36 @@ fn migrate_pgp_contacts(
1679
1692
}
1680
1693
1681
1694
// Broadcast list
1682
- 160 => retain_autocrypt_pgp_contacts ( ) ,
1683
-
1695
+ 160 => old_members
1696
+ . iter ( )
1697
+ . map ( |original| {
1698
+ (
1699
+ * original,
1700
+ autocrypt_pgp_contacts
1701
+ . get ( original)
1702
+ // There will be no unencrypted broadcast lists anymore,
1703
+ // so, if a peerstate is reset,
1704
+ // the best we can do is encrypting to this key regardless.
1705
+ . or_else ( || {
1706
+ autocrypt_pgp_contacts_with_reset_peerstate. get ( original)
1707
+ } )
1708
+ . copied ( ) ,
1709
+ )
1710
+ } )
1711
+ . collect :: < Vec < ( u32 , Option < u32 > ) > > ( ) ,
1684
1712
_ => {
1685
1713
warn ! ( context, "Invalid chat type {typ}" ) ;
1686
1714
continue ;
1687
1715
}
1688
1716
} ;
1689
1717
1690
- if old_and_new_members. iter ( ) . all ( |( _old, new) | new. is_none ( ) ) {
1691
- keep_email_contacts ( "All contacts in chat are e-mail contacts" ) ;
1718
+ // If a group contains a contact without a key or with 'reset' peerstate,
1719
+ // downgrade to unencrypted Ad-Hoc group.
1720
+ if typ == 120 && old_and_new_members. iter ( ) . any ( |( _old, new) | new. is_none ( ) ) {
1721
+ transaction
1722
+ . execute ( "UPDATE chats SET grpid='' WHERE id=?" , ( chat_id, ) )
1723
+ . context ( "Step 26.1" ) ?;
1724
+ keep_email_contacts ( "Group contains contact without peerstate" ) ;
1692
1725
continue ;
1693
1726
}
1694
1727
0 commit comments