@@ -155,6 +155,20 @@ impl fmt::Debug for Client {
155
155
f. debug_struct ( "Client" ) . finish ( )
156
156
}
157
157
}
158
+ const UNCONDITIONAL_CAPS : & [ & str ] = & [
159
+ "account-notify" ,
160
+ "away-notify" ,
161
+ "batch" ,
162
+ "chghost" ,
163
+ "draft/read-marker" ,
164
+ "extended-monitor" ,
165
+ "invite-notify" ,
166
+ "labeled-response" ,
167
+ "message-tags" ,
168
+ "multi-prefix" ,
169
+ "server-time" ,
170
+ "userhost-in-names" ,
171
+ ] ;
158
172
159
173
impl Client {
160
174
pub fn new (
@@ -646,92 +660,52 @@ impl Client {
646
660
) ] ) ;
647
661
}
648
662
}
649
- Command :: CAP ( _, sub, a, b) if sub == "LS" => {
650
- let ( caps, asterisk) = match ( a, b) {
651
- ( Some ( caps) , None ) => ( caps, None ) ,
652
- ( Some ( asterisk) , Some ( caps) ) => ( caps, Some ( asterisk) ) ,
653
- // Unreachable
654
- ( None , None ) | ( None , Some ( _) ) => return Ok ( vec ! [ ] ) ,
655
- } ;
656
-
663
+ Command :: CAP ( _, sub, Some ( _asterisk) , Some ( caps) ) if sub == "LS" => {
664
+ self . listed_caps . extend ( caps. split ( ' ' ) . map ( String :: from) ) ;
665
+ }
666
+ // Finished with LS
667
+ Command :: CAP ( _, sub, Some ( caps) , None ) if sub == "LS" => {
657
668
self . listed_caps . extend ( caps. split ( ' ' ) . map ( String :: from) ) ;
658
669
659
- // Finished
660
- if asterisk. is_none ( ) {
661
- let mut requested = vec ! [ ] ;
670
+ let contains = |s : & str | self . listed_caps . iter ( ) . any ( |cap| cap == s) ;
662
671
663
- let contains = |s| self . listed_caps . iter ( ) . any ( |cap| cap == s) ;
672
+ let mut requested: Vec < & str > = UNCONDITIONAL_CAPS
673
+ . iter ( )
674
+ . copied ( )
675
+ . filter ( |c| contains ( c) )
676
+ . collect ( ) ;
664
677
665
- if contains ( "invite-notify" ) {
666
- requested. push ( "invite-notify" ) ;
667
- }
668
- if contains ( "userhost-in-names" ) {
669
- requested. push ( "userhost-in-names" ) ;
670
- }
671
- if contains ( "away-notify" ) {
672
- requested. push ( "away-notify" ) ;
673
- }
674
- if contains ( "message-tags" ) {
675
- requested. push ( "message-tags" ) ;
676
- }
677
- if contains ( "server-time" ) {
678
- requested. push ( "server-time" ) ;
679
- }
680
- if contains ( "chghost" ) {
681
- requested. push ( "chghost" ) ;
682
- }
683
- if contains ( "extended-monitor" ) {
684
- requested. push ( "extended-monitor" ) ;
685
- }
686
- if contains ( "account-notify" ) {
687
- requested. push ( "account-notify" ) ;
678
+ if contains ( "account-notify" ) && contains ( "extended-join" ) {
679
+ requested. push ( "extended-join" ) ;
680
+ }
681
+ if contains ( "batch" ) && contains ( "draft/chathistory" ) {
682
+ // We require batch for our chathistory support
683
+ requested. push ( "draft/chathistory" ) ;
688
684
689
- if contains ( "extended-join" ) {
690
- requested. push ( "extended-join" ) ;
691
- }
685
+ if contains ( "draft/event-playback" ) {
686
+ requested. push ( "draft/event-playback" ) ;
692
687
}
693
- if contains ( "batch" ) {
694
- requested. push ( "batch" ) ;
688
+ }
689
+ // We require labeled-response so we can properly tag echo-messages
690
+ if contains ( "labeled-response" ) && contains ( "echo-message" ) {
691
+ requested. push ( "echo-message" ) ;
692
+ }
693
+ if self . listed_caps . iter ( ) . any ( |cap| cap. starts_with ( "sasl" ) ) {
694
+ requested. push ( "sasl" ) ;
695
+ }
695
696
696
- // We require batch for our chathistory support
697
- if contains ( "draft/chathistory" ) {
698
- requested. push ( "draft/chathistory" ) ;
699
697
700
- if contains ( "draft/event-playback" ) {
701
- requested. push ( "draft/event-playback" ) ;
702
- }
703
- }
704
- }
705
- if contains ( "labeled-response" ) {
706
- requested. push ( "labeled-response" ) ;
707
-
708
- // We require labeled-response so we can properly tag echo-messages
709
- if contains ( "echo-message" ) {
710
- requested. push ( "echo-message" ) ;
711
- }
712
- }
713
- if self . listed_caps . iter ( ) . any ( |cap| cap. starts_with ( "sasl" ) ) {
714
- requested. push ( "sasl" ) ;
715
- }
716
- if contains ( "multi-prefix" ) {
717
- requested. push ( "multi-prefix" ) ;
718
- }
719
- if contains ( "draft/read-marker" ) {
720
- requested. push ( "draft/read-marker" ) ;
721
- }
722
-
723
- if !requested. is_empty ( ) {
724
- // Request
725
- self . registration_step = RegistrationStep :: Req ;
698
+ if !requested. is_empty ( ) {
699
+ // Request
700
+ self . registration_step = RegistrationStep :: Req ;
726
701
727
- for message in group_capability_requests ( & requested) {
728
- self . handle . try_send ( message) ?;
729
- }
730
- } else {
731
- // If none requested, end negotiation
732
- self . registration_step = RegistrationStep :: End ;
733
- self . handle . try_send ( command ! ( "CAP" , "END" ) ) ?;
702
+ for message in group_capability_requests ( & requested) {
703
+ self . handle . try_send ( message) ?;
734
704
}
705
+ } else {
706
+ // If none requested, end negotiation
707
+ self . registration_step = RegistrationStep :: End ;
708
+ self . handle . try_send ( command ! ( "CAP" , "END" ) ) ?;
735
709
}
736
710
}
737
711
Command :: CAP ( _, sub, a, b) if sub == "ACK" => {
@@ -791,33 +765,16 @@ impl Client {
791
765
792
766
let new_caps = caps. split ( ' ' ) . map ( String :: from) . collect :: < Vec < String > > ( ) ;
793
767
794
- let mut requested = vec ! [ ] ;
795
-
796
768
let newly_contains = |s| new_caps. iter ( ) . any ( |cap| cap == s) ;
797
769
770
+ let mut requested: Vec < & str > = UNCONDITIONAL_CAPS
771
+ . iter ( )
772
+ . copied ( )
773
+ . filter ( |c| newly_contains ( * c) )
774
+ . collect ( ) ;
775
+
798
776
let contains = |s| self . listed_caps . iter ( ) . any ( |cap| cap == s) ;
799
777
800
- if newly_contains ( "invite-notify" ) {
801
- requested. push ( "invite-notify" ) ;
802
- }
803
- if newly_contains ( "userhost-in-names" ) {
804
- requested. push ( "userhost-in-names" ) ;
805
- }
806
- if newly_contains ( "away-notify" ) {
807
- requested. push ( "away-notify" ) ;
808
- }
809
- if newly_contains ( "message-tags" ) {
810
- requested. push ( "message-tags" ) ;
811
- }
812
- if newly_contains ( "server-time" ) {
813
- requested. push ( "server-time" ) ;
814
- }
815
- if newly_contains ( "chghost" ) {
816
- requested. push ( "chghost" ) ;
817
- }
818
- if newly_contains ( "extended-monitor" ) {
819
- requested. push ( "extended-monitor" ) ;
820
- }
821
778
if contains ( "account-notify" ) || newly_contains ( "account-notify" ) {
822
779
if newly_contains ( "account-notify" ) {
823
780
requested. push ( "account-notify" ) ;
@@ -851,12 +808,6 @@ impl Client {
851
808
requested. push ( "echo-message" ) ;
852
809
}
853
810
}
854
- if newly_contains ( "multi-prefix" ) {
855
- requested. push ( "multi-prefix" ) ;
856
- }
857
- if newly_contains ( "draft/read-marker" ) {
858
- requested. push ( "draft/read-marker" ) ;
859
- }
860
811
861
812
if !requested. is_empty ( ) {
862
813
for message in group_capability_requests ( & requested) {
@@ -957,7 +908,7 @@ impl Client {
957
908
) ] ) ;
958
909
}
959
910
dcc:: Command :: Unsupported ( command) => {
960
- bail ! ( "Unsupported DCC command: {command}" , ) ;
911
+ bail ! ( "Unsupported DCC command: {command}" ) ;
961
912
}
962
913
}
963
914
} else {
@@ -1122,11 +1073,18 @@ impl Client {
1122
1073
// Updated actual nick
1123
1074
let nick = ok ! ( args. first( ) ) ;
1124
1075
self . resolved_nick = Some ( nick. to_string ( ) ) ;
1076
+ }
1077
+ // end of registration (including ISUPPORT) is indicated by either RPL_ENDOFMOTD or
1078
+ // ERR_NOMOTD: https://modern.ircdocs.horse/#connection-registration
1079
+ Command :: Numeric ( RPL_ENDOFMOTD , _args) | Command :: Numeric ( ERR_NOMOTD , _args) => {
1080
+ let Some ( nick) = self . resolved_nick . as_deref ( ) else {
1081
+ bail ! ( "Error, registration completed without RPL_WELCOME completed" ) ;
1082
+ } ;
1125
1083
1126
1084
// Send nick password & ghost
1127
1085
if let Some ( nick_pass) = self . config . nick_password . as_ref ( ) {
1128
1086
// Try ghost recovery if we couldn't claim our nick
1129
- if self . config . should_ghost && nick != & self . config . nickname {
1087
+ if self . config . should_ghost && nick != self . config . nickname {
1130
1088
for sequence in & self . config . ghost_sequence {
1131
1089
self . handle . try_send ( command ! (
1132
1090
"PRIVMSG" ,
0 commit comments