omextra 0.0.0.dev423__py3-none-any.whl → 0.0.0.dev425__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. omextra/.omlish-manifests.json +14 -0
  2. omextra/__about__.py +3 -1
  3. omextra/defs.py +216 -0
  4. omextra/dynamic.py +219 -0
  5. omextra/formats/__init__.py +0 -0
  6. omextra/formats/json/Json.g4 +77 -0
  7. omextra/formats/json/__init__.py +0 -0
  8. omextra/formats/json/_antlr/JsonLexer.py +109 -0
  9. omextra/formats/json/_antlr/JsonListener.py +61 -0
  10. omextra/formats/json/_antlr/JsonParser.py +457 -0
  11. omextra/formats/json/_antlr/JsonVisitor.py +42 -0
  12. omextra/formats/json/_antlr/__init__.py +0 -0
  13. omextra/io/__init__.py +0 -0
  14. omextra/io/trampoline.py +289 -0
  15. omextra/specs/__init__.py +0 -0
  16. omextra/specs/irc/__init__.py +0 -0
  17. omextra/specs/irc/messages/__init__.py +0 -0
  18. omextra/specs/irc/messages/base.py +50 -0
  19. omextra/specs/irc/messages/formats.py +92 -0
  20. omextra/specs/irc/messages/messages.py +775 -0
  21. omextra/specs/irc/messages/parsing.py +99 -0
  22. omextra/specs/irc/numerics/__init__.py +0 -0
  23. omextra/specs/irc/numerics/formats.py +97 -0
  24. omextra/specs/irc/numerics/numerics.py +865 -0
  25. omextra/specs/irc/numerics/types.py +59 -0
  26. omextra/specs/irc/protocol/LICENSE +11 -0
  27. omextra/specs/irc/protocol/__init__.py +61 -0
  28. omextra/specs/irc/protocol/consts.py +6 -0
  29. omextra/specs/irc/protocol/errors.py +30 -0
  30. omextra/specs/irc/protocol/message.py +21 -0
  31. omextra/specs/irc/protocol/nuh.py +55 -0
  32. omextra/specs/irc/protocol/parsing.py +158 -0
  33. omextra/specs/irc/protocol/rendering.py +153 -0
  34. omextra/specs/irc/protocol/tags.py +102 -0
  35. omextra/specs/irc/protocol/utils.py +30 -0
  36. omextra/specs/proto/Protobuf3.g4 +396 -0
  37. omextra/specs/proto/__init__.py +0 -0
  38. omextra/specs/proto/_antlr/Protobuf3Lexer.py +340 -0
  39. omextra/specs/proto/_antlr/Protobuf3Listener.py +448 -0
  40. omextra/specs/proto/_antlr/Protobuf3Parser.py +3909 -0
  41. omextra/specs/proto/_antlr/Protobuf3Visitor.py +257 -0
  42. omextra/specs/proto/_antlr/__init__.py +0 -0
  43. omextra/specs/proto/nodes.py +54 -0
  44. omextra/specs/proto/parsing.py +98 -0
  45. omextra/sql/__init__.py +0 -0
  46. omextra/sql/parsing/Minisql.g4 +292 -0
  47. omextra/sql/parsing/__init__.py +0 -0
  48. omextra/sql/parsing/_antlr/MinisqlLexer.py +322 -0
  49. omextra/sql/parsing/_antlr/MinisqlListener.py +511 -0
  50. omextra/sql/parsing/_antlr/MinisqlParser.py +3763 -0
  51. omextra/sql/parsing/_antlr/MinisqlVisitor.py +292 -0
  52. omextra/sql/parsing/_antlr/__init__.py +0 -0
  53. omextra/sql/parsing/parsing.py +120 -0
  54. omextra/text/__init__.py +0 -0
  55. omextra/text/antlr/__init__.py +0 -0
  56. omextra/text/antlr/cli/__init__.py +0 -0
  57. omextra/text/antlr/cli/__main__.py +11 -0
  58. omextra/text/antlr/cli/cli.py +62 -0
  59. omextra/text/antlr/cli/consts.py +7 -0
  60. omextra/text/antlr/cli/gen.py +188 -0
  61. {omextra-0.0.0.dev423.dist-info → omextra-0.0.0.dev425.dist-info}/METADATA +2 -3
  62. omextra-0.0.0.dev425.dist-info/RECORD +67 -0
  63. omextra/.manifests.json +0 -1
  64. omextra-0.0.0.dev423.dist-info/RECORD +0 -9
  65. {omextra-0.0.0.dev423.dist-info → omextra-0.0.0.dev425.dist-info}/WHEEL +0 -0
  66. {omextra-0.0.0.dev423.dist-info → omextra-0.0.0.dev425.dist-info}/entry_points.txt +0 -0
  67. {omextra-0.0.0.dev423.dist-info → omextra-0.0.0.dev425.dist-info}/licenses/LICENSE +0 -0
  68. {omextra-0.0.0.dev423.dist-info → omextra-0.0.0.dev425.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,775 @@
1
+ """
2
+ TODO:
3
+ - PONG - optional *before* required ...
4
+ - CAPABILITIES - ':' last param
5
+
6
+ ==
7
+
8
+ https://datatracker.ietf.org/doc/html/rfc2812
9
+ https://modern.ircdocs.horse/
10
+ """
11
+ import typing as ta
12
+
13
+ from omlish import check
14
+ from omlish import dataclasses as dc
15
+
16
+ from ..numerics import numerics as nr
17
+ from .base import Message
18
+ from .base import MessageFormat
19
+ from .base import list_pair_params_unpacker
20
+
21
+
22
+ ##
23
+
24
+
25
+ _REGISTERED_IRC_MESSAGES_BY_NAME: dict[str, list[type['Message']]] = {}
26
+
27
+
28
+ def _register_irc_message(cls):
29
+ check.issubclass(cls, Message)
30
+ _REGISTERED_IRC_MESSAGES_BY_NAME.setdefault(cls.FORMAT.name, []).append(cls)
31
+ return cls
32
+
33
+
34
+ ##
35
+ # Connection Messages
36
+
37
+
38
+ @_register_irc_message
39
+ class CapMessage(Message):
40
+ FORMAT = MessageFormat.of(
41
+ 'CAP',
42
+ 'subcommand',
43
+ 'capabilities',
44
+ )
45
+
46
+ subcommand: str
47
+ capabilities: ta.Sequence[str]
48
+
49
+
50
+ @_register_irc_message
51
+ class AuthenticateMessage(Message):
52
+ FORMAT = MessageFormat.of('AUTHENTICATE')
53
+
54
+
55
+ @_register_irc_message
56
+ class PassMessage(Message):
57
+ FORMAT = MessageFormat.of(
58
+ 'PASS',
59
+ 'password',
60
+ )
61
+
62
+ REPLIES = (
63
+ nr.ERR_NEEDMOREPARAMS,
64
+ nr.ERR_ALREADYREGISTERED,
65
+ nr.ERR_PASSWDMISMATCH,
66
+ )
67
+
68
+ password: str
69
+
70
+
71
+ @_register_irc_message
72
+ class NickMessage(Message):
73
+ FORMAT = MessageFormat.of(
74
+ 'NICK',
75
+ 'nickname',
76
+ )
77
+
78
+ REPLIES = (
79
+ nr.ERR_NONICKNAMEGIVEN,
80
+ nr.ERR_ERRONEUSNICKNAME,
81
+ nr.ERR_NICKNAMEINUSE,
82
+ nr.ERR_NICKCOLLISION,
83
+ )
84
+
85
+ nickname: str
86
+
87
+
88
+ class UserMessage(Message):
89
+ FORMAT = MessageFormat.of(
90
+ 'USER',
91
+ 'username',
92
+ 'param1', # 0
93
+ 'param2', # *
94
+ 'realname',
95
+ )
96
+
97
+ REPLIES = (
98
+ nr.ERR_NEEDMOREPARAMS,
99
+ nr.ERR_ALREADYREGISTERED,
100
+ )
101
+
102
+ username: str
103
+ realname: str
104
+
105
+ param1: str = '8'
106
+ param2: str = '*'
107
+
108
+
109
+ @_register_irc_message
110
+ class PingMessage(Message):
111
+ FORMAT = MessageFormat.of(
112
+ 'PING',
113
+ 'token',
114
+ )
115
+
116
+ REPLIES = (
117
+ nr.ERR_NEEDMOREPARAMS,
118
+ nr.ERR_NOORIGIN,
119
+ nr.ERR_NOSUCHSERVER,
120
+ )
121
+
122
+ token: str
123
+
124
+
125
+ @_register_irc_message
126
+ class PongMessage(Message):
127
+ FORMAT = MessageFormat.of(
128
+ 'PONG',
129
+ '?server',
130
+ 'token',
131
+ )
132
+
133
+ token: str
134
+ server: str | None = None
135
+
136
+
137
+ @_register_irc_message
138
+ class OperMessage(Message):
139
+ FORMAT = MessageFormat.of(
140
+ 'OPER',
141
+ 'name',
142
+ 'password',
143
+ )
144
+
145
+ REPLIES = (
146
+ nr.ERR_NEEDMOREPARAMS,
147
+ nr.ERR_PASSWDMISMATCH,
148
+ nr.ERR_NOOPERHOST,
149
+ nr.RPL_YOUREOPER,
150
+ )
151
+
152
+ name: str
153
+ password: str
154
+
155
+
156
+ @_register_irc_message
157
+ class QuitMessage(Message):
158
+ FORMAT = MessageFormat.of(
159
+ 'QUIT',
160
+ '?reason',
161
+ )
162
+
163
+ reason: str | None = None
164
+
165
+
166
+ @_register_irc_message
167
+ class ErrorMessage(Message):
168
+ FORMAT = MessageFormat.of(
169
+ 'ERROR',
170
+ '?reason',
171
+ )
172
+
173
+ reason: str | None = None
174
+
175
+
176
+ ##
177
+ # Channel Operations
178
+
179
+
180
+ @_register_irc_message
181
+ class JoinMessage(Message):
182
+ FORMAT = MessageFormat.of(
183
+ 'JOIN',
184
+ ','
185
+ 'channels', '?,keys',
186
+ unpack_params=list_pair_params_unpacker(
187
+ 'channels',
188
+ 'channels',
189
+ 'keys',
190
+ ),
191
+ )
192
+
193
+ REPLIES = (
194
+ nr.ERR_NEEDMOREPARAMS,
195
+ nr.ERR_NOSUCHCHANNEL,
196
+ nr.ERR_TOOMANYCHANNELS,
197
+ nr.ERR_BADCHANNELKEY,
198
+ nr.ERR_BANNEDFROMCHAN,
199
+ nr.ERR_CHANNELISFULL,
200
+ nr.ERR_INVITEONLYCHAN,
201
+ nr.ERR_BADCHANMASK,
202
+ nr.RPL_TOPIC,
203
+ nr.RPL_TOPICWHOTIME,
204
+ nr.RPL_NAMREPLY,
205
+ nr.RPL_ENDOFNAMES,
206
+ )
207
+
208
+ channels: ta.Sequence[str | tuple[str, str]]
209
+
210
+ @property
211
+ def has_keys(self) -> bool:
212
+ return check.single({isinstance(e, tuple) for e in self.channels})
213
+
214
+ @dc.init
215
+ def _validate_channels(self) -> None:
216
+ check.not_isinstance(self.channels, str)
217
+ if self.has_keys:
218
+ for c, _ in self.channels: # type: ignore[misc]
219
+ check.non_empty_str(c)
220
+ else:
221
+ for c in self.channels:
222
+ check.non_empty_str(c) # type: ignore
223
+
224
+
225
+ @_register_irc_message
226
+ class LeaveAllJoinMessage(Message):
227
+ FORMAT = MessageFormat.of(
228
+ 'JOIN',
229
+ MessageFormat.LiteralParam('0'),
230
+ )
231
+
232
+ REPLIES = JoinMessage.REPLIES
233
+
234
+
235
+ @_register_irc_message
236
+ class PartMessage(Message):
237
+ FORMAT = MessageFormat.of(
238
+ 'PART',
239
+ ',channels',
240
+ '?reason',
241
+ )
242
+
243
+ REPLIES = (
244
+ nr.ERR_NEEDMOREPARAMS,
245
+ nr.ERR_NOSUCHCHANNEL,
246
+ nr.ERR_NOTONCHANNEL,
247
+ )
248
+
249
+ channels: ta.Sequence[str] = dc.xfield(validate=check.of_not_isinstance(str))
250
+ reason: str | None = None
251
+
252
+
253
+ @_register_irc_message
254
+ class TopicMessage(Message):
255
+ FORMAT = MessageFormat.of(
256
+ 'TOPIC',
257
+ 'channel',
258
+ '?topic',
259
+ )
260
+
261
+ REPLIES = (
262
+ nr.ERR_NEEDMOREPARAMS,
263
+ nr.ERR_NOSUCHCHANNEL,
264
+ nr.ERR_NOTONCHANNEL,
265
+ nr.ERR_CHANOPRIVSNEEDED,
266
+ nr.RPL_NOTOPIC,
267
+ nr.RPL_TOPIC,
268
+ nr.RPL_TOPICWHOTIME,
269
+ )
270
+
271
+ channel: str
272
+ topic: str | None = None
273
+
274
+
275
+ @_register_irc_message
276
+ class NamesMessage(Message):
277
+ FORMAT = MessageFormat.of(
278
+ 'NAMES',
279
+ ',channels',
280
+ )
281
+
282
+ REPLIES = (
283
+ nr.RPL_NAMREPLY,
284
+ nr.RPL_ENDOFNAMES,
285
+ )
286
+
287
+ channels: ta.Sequence[str] = dc.xfield(validate=check.of_not_isinstance(str))
288
+
289
+
290
+ @_register_irc_message
291
+ class ListMessage(Message):
292
+ FORMAT = MessageFormat.of(
293
+ 'LIST',
294
+ '?,channels',
295
+ '?,elistconds',
296
+ )
297
+
298
+ REPLIES = (
299
+ nr.RPL_LISTSTART,
300
+ nr.RPL_LIST,
301
+ nr.RPL_LISTEND,
302
+ )
303
+
304
+ channels: ta.Sequence[str]
305
+ elistconds: ta.Sequence[str]
306
+
307
+
308
+ @_register_irc_message
309
+ class InviteMessage(Message):
310
+ FORMAT = MessageFormat.of(
311
+ 'INVITE',
312
+ 'nickname',
313
+ 'channel',
314
+ )
315
+
316
+ REPLIES = (
317
+ nr.RPL_INVITING,
318
+ nr.ERR_NEEDMOREPARAMS,
319
+ nr.ERR_NOSUCHCHANNEL,
320
+ nr.ERR_NOTONCHANNEL,
321
+ nr.ERR_CHANOPRIVSNEEDED,
322
+ nr.ERR_USERONCHANNEL,
323
+ )
324
+
325
+ nickname: str
326
+ channel: str
327
+
328
+
329
+ @_register_irc_message
330
+ class KickMessage(Message):
331
+ FORMAT = MessageFormat.of(
332
+ 'KICK',
333
+ 'channel',
334
+ ',users',
335
+ '?comment',
336
+ )
337
+
338
+ REPLIES = (
339
+ nr.ERR_NEEDMOREPARAMS,
340
+ nr.ERR_NOSUCHCHANNEL,
341
+ nr.ERR_CHANOPRIVSNEEDED,
342
+ nr.ERR_USERNOTINCHANNEL,
343
+ nr.ERR_NOTONCHANNEL,
344
+ nr.ERR_BADCHANMASK,
345
+ )
346
+
347
+ channel: str
348
+ users: ta.Sequence[str]
349
+ comment: str | None = None
350
+
351
+
352
+ ##
353
+ # Server Queries and Commands
354
+
355
+
356
+ @_register_irc_message
357
+ class MotdMessage(Message):
358
+ FORMAT = MessageFormat.of(
359
+ 'MOTD',
360
+ '?target',
361
+ )
362
+
363
+ REPLIES = (
364
+ nr.ERR_NOSUCHSERVER,
365
+ nr.ERR_NOMOTD,
366
+ nr.RPL_MOTDSTART,
367
+ nr.RPL_MOTD,
368
+ nr.RPL_ENDOFMOTD,
369
+ )
370
+
371
+ target: str | None = None
372
+
373
+
374
+ @_register_irc_message
375
+ class VersionMessage(Message):
376
+ FORMAT = MessageFormat.of(
377
+ 'VERSION',
378
+ '?target',
379
+ )
380
+
381
+ REPLIES = (
382
+ nr.ERR_NOSUCHSERVER,
383
+ nr.RPL_ISUPPORT,
384
+ nr.RPL_VERSION,
385
+ )
386
+
387
+ target: str | None = None
388
+
389
+
390
+ @_register_irc_message
391
+ class AdminMessage(Message):
392
+ FORMAT = MessageFormat.of(
393
+ 'ADMIN',
394
+ '?target',
395
+ )
396
+
397
+ REPLIES = (
398
+ nr.ERR_NOSUCHSERVER,
399
+ nr.RPL_ADMINME,
400
+ nr.RPL_ADMINLOC1,
401
+ nr.RPL_ADMINLOC2,
402
+ nr.RPL_ADMINEMAIL,
403
+ )
404
+
405
+ target: str | None = None
406
+
407
+
408
+ @_register_irc_message
409
+ class ConnectMessage(Message):
410
+ FORMAT = MessageFormat.of(
411
+ 'CONNECT',
412
+ 'target_server',
413
+ '?port',
414
+ '?remote_server',
415
+ )
416
+
417
+ REPLIES = (
418
+ nr.ERR_NOSUCHSERVER,
419
+ nr.ERR_NEEDMOREPARAMS,
420
+ nr.ERR_NOPRIVILEGES,
421
+ nr.ERR_NOPRIVS,
422
+ )
423
+
424
+ target_server: str
425
+ port: str | None = None
426
+ remote_server: str | None = None
427
+
428
+
429
+ @_register_irc_message
430
+ class LusersMessage(Message):
431
+ FORMAT = MessageFormat.of('LUSERS')
432
+
433
+ REPLIES = (
434
+ nr.RPL_LUSERCLIENT,
435
+ nr.RPL_LUSEROP,
436
+ nr.RPL_LUSERUNKNOWN,
437
+ nr.RPL_LUSERCHANNELS,
438
+ nr.RPL_LUSERME,
439
+ nr.RPL_LOCALUSERS,
440
+ nr.RPL_GLOBALUSERS,
441
+ )
442
+
443
+
444
+ @_register_irc_message
445
+ class TimeMessage(Message):
446
+ FORMAT = MessageFormat.of(
447
+ 'TIME',
448
+ '?server',
449
+ )
450
+
451
+ REPLIES = (
452
+ nr.ERR_NOSUCHSERVER,
453
+ nr.RPL_TIME,
454
+ )
455
+
456
+ server: str | None = None
457
+
458
+
459
+ @_register_irc_message
460
+ class StatsMessage(Message):
461
+ FORMAT = MessageFormat.of(
462
+ 'STATS',
463
+ 'query',
464
+ '?server',
465
+ )
466
+
467
+ REPLIES = (
468
+ nr.ERR_NOSUCHSERVER,
469
+ nr.ERR_NEEDMOREPARAMS,
470
+ nr.ERR_NOPRIVILEGES,
471
+ nr.ERR_NOPRIVS,
472
+ nr.RPL_STATSCLINE,
473
+ nr.RPL_STATSHLINE,
474
+ nr.RPL_STATSILINE,
475
+ nr.RPL_STATSKLINE,
476
+ nr.RPL_STATSLLINE,
477
+ nr.RPL_STATSOLINE,
478
+ nr.RPL_STATSLINKINFO,
479
+ nr.RPL_STATSUPTIME,
480
+ nr.RPL_STATSCOMMANDS,
481
+ nr.RPL_ENDOFSTATS,
482
+ )
483
+
484
+ query: str
485
+ server: str | None = None
486
+
487
+
488
+ @_register_irc_message
489
+ class HelpMessage(Message):
490
+ FORMAT = MessageFormat.of(
491
+ 'HELP',
492
+ '?subject',
493
+ )
494
+
495
+ REPLIES = (
496
+ nr.ERR_HELPNOTFOUND,
497
+ nr.RPL_HELPSTART,
498
+ nr.RPL_HELPTXT,
499
+ nr.RPL_ENDOFHELP,
500
+ )
501
+
502
+ subject: str | None = None
503
+
504
+
505
+ @_register_irc_message
506
+ class InfoMessage(Message):
507
+ FORMAT = MessageFormat.of('INFO')
508
+
509
+ REPLIES = (
510
+ nr.RPL_INFO,
511
+ nr.RPL_ENDOFINFO,
512
+ )
513
+
514
+
515
+ @_register_irc_message
516
+ class ModeMessage(Message):
517
+ FORMAT = MessageFormat.of(
518
+ 'MODE',
519
+ 'target',
520
+ '?modestring',
521
+ '*mode_arguments',
522
+ )
523
+
524
+ REPLIES = (
525
+ nr.ERR_NOSUCHCHANNEL,
526
+ nr.RPL_CHANNELMODEIS,
527
+ nr.RPL_CREATIONTIME,
528
+ nr.RPL_CHANNELMODEIS,
529
+ nr.ERR_CHANOPRIVSNEEDED,
530
+ nr.RPL_BANLIST,
531
+ nr.RPL_ENDOFBANLIST,
532
+ nr.RPL_EXCEPTLIST,
533
+ nr.RPL_ENDOFEXCEPTLIST,
534
+ nr.RPL_INVITELIST,
535
+ nr.RPL_ENDOFINVITELIST,
536
+ )
537
+
538
+ target: str
539
+ modestring: str | None = None
540
+ mode_arguments: ta.Sequence[str] | None = None
541
+
542
+
543
+ ##
544
+ # Sending Messages
545
+
546
+
547
+ @_register_irc_message
548
+ class PrivmsgMessage(Message):
549
+ FORMAT = MessageFormat.of(
550
+ 'PRIVMSG',
551
+ ',targets',
552
+ 'text',
553
+ )
554
+
555
+ REPLIES = (
556
+ nr.ERR_NOSUCHNICK,
557
+ nr.ERR_NOSUCHSERVER,
558
+ nr.ERR_CANNOTSENDTOCHAN,
559
+ nr.ERR_TOOMANYTARGETS,
560
+ nr.ERR_NORECIPIENT,
561
+ nr.ERR_NOTEXTTOSEND,
562
+ nr.ERR_NOTOPLEVEL,
563
+ nr.ERR_WILDTOPLEVEL,
564
+ nr.RPL_AWAY,
565
+ )
566
+
567
+ targets: ta.Sequence[str]
568
+ text: str
569
+
570
+
571
+ @_register_irc_message
572
+ class NoticeMessage(Message):
573
+ FORMAT = MessageFormat.of(
574
+ 'NOTICE',
575
+ ',targets',
576
+ 'text',
577
+ )
578
+
579
+ targets: ta.Sequence[str]
580
+ text: str
581
+
582
+
583
+ ##
584
+ # User-Based Queries
585
+
586
+ @_register_irc_message
587
+ class WhoMessage(Message):
588
+ FORMAT = MessageFormat.of(
589
+ 'WHO',
590
+ 'mask',
591
+ )
592
+
593
+ REPLIES = (
594
+ nr.RPL_WHOREPLY,
595
+ nr.RPL_ENDOFWHO,
596
+ )
597
+
598
+ mask: str
599
+
600
+
601
+ @_register_irc_message
602
+ class WhoisMessage(Message):
603
+ FORMAT = MessageFormat.of(
604
+ 'WHOIS',
605
+ '?target',
606
+ 'nick',
607
+ )
608
+
609
+ REPLIES = (
610
+ nr.ERR_NOSUCHNICK,
611
+ nr.ERR_NOSUCHSERVER,
612
+ nr.ERR_NONICKNAMEGIVEN,
613
+ nr.RPL_WHOISCERTFP,
614
+ nr.RPL_WHOISREGNICK,
615
+ nr.RPL_WHOISUSER,
616
+ nr.RPL_WHOISSERVER,
617
+ nr.RPL_WHOISOPERATOR,
618
+ nr.RPL_WHOISIDLE,
619
+ nr.RPL_WHOISCHANNELS,
620
+ nr.RPL_WHOISSPECIAL,
621
+ nr.RPL_WHOISACCOUNT,
622
+ nr.RPL_WHOISACTUALLY,
623
+ nr.RPL_WHOISHOST,
624
+ nr.RPL_WHOISMODES,
625
+ nr.RPL_WHOISSECURE,
626
+ nr.RPL_AWAY,
627
+ )
628
+
629
+ nick: str
630
+ target: str | None = None
631
+
632
+
633
+ @_register_irc_message
634
+ class WhowasMessage(Message):
635
+ FORMAT = MessageFormat.of(
636
+ 'WHOWAS',
637
+ 'nick',
638
+ '?count',
639
+ )
640
+
641
+ REPLIES = (
642
+ nr.ERR_WASNOSUCHNICK,
643
+ nr.RPL_ENDOFWHOWAS,
644
+ nr.RPL_WHOWASUSER,
645
+ nr.RPL_WHOISACTUALLY,
646
+ nr.RPL_WHOISSERVER,
647
+ nr.RPL_WHOWASUSER,
648
+ nr.ERR_NONICKNAMEGIVEN,
649
+ nr.ERR_NEEDMOREPARAMS,
650
+ )
651
+
652
+ nick: str
653
+ count: str | None = None
654
+
655
+
656
+ ##
657
+ # Operator Messages
658
+
659
+
660
+ @_register_irc_message
661
+ class KillMessage(Message):
662
+ FORMAT = MessageFormat.of(
663
+ 'KILL',
664
+ 'nickname',
665
+ 'comment',
666
+ )
667
+
668
+ REPLIES = (
669
+ nr.ERR_NOSUCHSERVER,
670
+ nr.ERR_NEEDMOREPARAMS,
671
+ nr.ERR_NOPRIVILEGES,
672
+ nr.ERR_NOPRIVS,
673
+ )
674
+
675
+ nickname: str
676
+ comment: str
677
+
678
+
679
+ @_register_irc_message
680
+ class RehashMessage(Message):
681
+ FORMAT = MessageFormat.of('REHASH')
682
+
683
+ REPLIES = (
684
+ nr.RPL_REHASHING,
685
+ nr.ERR_NOPRIVILEGES,
686
+ )
687
+
688
+
689
+ @_register_irc_message
690
+ class RestartMessage(Message):
691
+ FORMAT = MessageFormat.of('RESTART')
692
+
693
+ REPLIES = (
694
+ nr.ERR_NOPRIVILEGES,
695
+ )
696
+
697
+
698
+ @_register_irc_message
699
+ class SquitMessage(Message):
700
+ FORMAT = MessageFormat.of(
701
+ 'SQUIT',
702
+ 'server',
703
+ 'comment',
704
+ )
705
+
706
+ REPLIES = (
707
+ nr.ERR_NOSUCHSERVER,
708
+ nr.ERR_NEEDMOREPARAMS,
709
+ nr.ERR_NOPRIVILEGES,
710
+ nr.ERR_NOPRIVS,
711
+ )
712
+
713
+ server: str
714
+ comment: str
715
+
716
+
717
+ ##
718
+ # Optional Messages
719
+
720
+
721
+ @_register_irc_message
722
+ class AwayMessage(Message):
723
+ FORMAT = MessageFormat.of(
724
+ 'AWAY',
725
+ '?text',
726
+ )
727
+
728
+ REPLIES = (
729
+ nr.RPL_AWAY,
730
+ nr.RPL_UNAWAY,
731
+ nr.RPL_NOWAWAY,
732
+ )
733
+
734
+ text: str | None = None
735
+
736
+
737
+ @_register_irc_message
738
+ class LinksMessage(Message):
739
+ FORMAT = MessageFormat.of('LINKS')
740
+
741
+ REPLIES = (
742
+ nr.RPL_LINKS,
743
+ nr.RPL_ENDOFLINKS,
744
+ )
745
+
746
+
747
+ @_register_irc_message
748
+ class UserhostMessage(Message):
749
+ FORMAT = MessageFormat.of(
750
+ 'USERHOST',
751
+ '*nicknames',
752
+ )
753
+
754
+ REPLIES = (
755
+ nr.ERR_NEEDMOREPARAMS,
756
+ nr.RPL_USERHOST,
757
+ )
758
+
759
+ nicknames: ta.Sequence[str] | None = dc.xfield(default=None, validate=check.of_not_isinstance(str))
760
+
761
+
762
+ @_register_irc_message
763
+ class WallopsMessage(Message):
764
+ FORMAT = MessageFormat.of(
765
+ 'WALLOPS',
766
+ 'text',
767
+ )
768
+
769
+ REPLIES = (
770
+ nr.ERR_NEEDMOREPARAMS,
771
+ nr.ERR_NOPRIVILEGES,
772
+ nr.ERR_NOPRIVS,
773
+ )
774
+
775
+ text: str