1 /++
2 +
3 +/
4 module virc.numerics.rfc2812;
5 
6 import std.range : ElementType;
7 
8 import virc.numerics.definitions;
9 /++
10 + 004 RPL_MYINFO response.
11 +/
12 struct MyInfo {
13 	import virc.common : User;
14 	import virc.numerics.magicparser : Optional;
15 	User me;
16 	///Server name. Typically a valid hostname, but not necessarily.
17 	string name;
18 	///Version string of the software run by server.
19 	string version_;
20 	///Modes that can be set on users.
21 	string userModes;
22 	///Modes that can be set on channels.
23 	string channelModes;
24 	/++
25 	+ Modes that can be set on channels that have parameters. If non-empty, it is
26 	+ assumed that the modes in channelModes do not have parameters.
27 	+/
28 	@Optional string channelModesWithParams;
29 	/++
30 	+ Modes that can be set on users that have parameters. If non-empty, it is
31 	+ assumed that the modes in userModes do not have parameters.
32 	+/
33 	@Optional string userModesWithParams;
34 	///Modes that can be set on servers.
35 	@Optional string serverModes;
36 	/++
37 	+ Modes that can be set on servers that have parameters. If non-empty, it is
38 	+ assumed that the modes in serverModes do not have parameters.
39 	+/
40 	@Optional string serverModesWithParams;
41 }
42 /++
43 +
44 +/
45 //004 <username> <server_name> <version> <user_modes> <chan_modes> [<channel_modes_with_params> <user_modes_with_params> <server_modes> <server_modes_with_params>]
46 auto parseNumeric(Numeric numeric : Numeric.RPL_MYINFO, T)(T input) {
47 	import virc.numerics.magicparser : autoParse;
48 	return autoParse!MyInfo(input);
49 }
50 ///
51 @safe pure nothrow @nogc unittest { //Numeric.RPL_MYINFO
52 	import std.range : only;
53 	{
54 		immutable info = parseNumeric!(Numeric.RPL_MYINFO)(only("someone", "localhost", "IRCd-2.0", "BGHIRSWcdgikorswx", "ABCDFGIJKLMNOPQRSTYabcefghijklmnopqrstuvz", "FIJLYabefghjkloqv"));
55 		assert(info.get.name == "localhost");
56 		assert(info.get.version_ == "IRCd-2.0");
57 		assert(info.get.userModes == "BGHIRSWcdgikorswx");
58 		assert(info.get.userModesWithParams == "");
59 		assert(info.get.channelModes == "ABCDFGIJKLMNOPQRSTYabcefghijklmnopqrstuvz");
60 		assert(info.get.channelModesWithParams == "FIJLYabefghjkloqv");
61 		assert(info.get.serverModes == "");
62 		assert(info.get.serverModesWithParams == "");
63 	}
64 	{
65 		immutable info = parseNumeric!(Numeric.RPL_MYINFO)(only("someone", "localhost", "IRCd-2.0", "BGHIRSWcdgikorswx", "ABCDFGIJKLMNOPQRSTYabcefghijklmnopqrstuvz", "FIJLYabefghjkloqv", "q", "w", "x"));
66 		assert(info.get.name == "localhost");
67 		assert(info.get.version_ == "IRCd-2.0");
68 		assert(info.get.userModes == "BGHIRSWcdgikorswx");
69 		assert(info.get.userModesWithParams == "q");
70 		assert(info.get.channelModes == "ABCDFGIJKLMNOPQRSTYabcefghijklmnopqrstuvz");
71 		assert(info.get.channelModesWithParams == "FIJLYabefghjkloqv");
72 		assert(info.get.serverModes == "w");
73 		assert(info.get.serverModesWithParams == "x");
74 	}
75 	{
76 		immutable info = parseNumeric!(Numeric.RPL_MYINFO)(only("someone", "localhost", "IRCd-2.0", "BGHIRSWcdgikorswx ABCDFGIJKLMNOPQRSTYabcefghijklmnopqrstuvz FIJLYabefghjkloqv"));
77 		assert(info.isNull);
78 	}
79 }
80 struct RPL_TraceService {
81 	import virc.common : User;
82 	User me;
83 	string service;
84 	string class_;
85 	string name;
86 	string type;
87 	string activeType;
88 }
89 /++
90 + Parser for RPL_TRACESERVICE.
91 +
92 + Format is `207 <client> Service <class> <name> <type> <active_type>`
93 +/
94 auto parseNumeric(Numeric numeric : Numeric.RPL_TRACESERVICE, T)(T input) if (is(ElementType!T : string)) {
95 	import virc.numerics.magicparser : autoParse;
96 	return autoParse!RPL_TraceService(input);
97 }
98 ///
99 @safe pure @nogc nothrow unittest {
100 	import std.range : only, takeNone;
101 	//Need real world examples... No idea what these will really look like
102 	{
103 		immutable trace = parseNumeric!(Numeric.RPL_TRACESERVICE)(only("someone", "Service", "classy", "fred", "something", "no_idea"));
104 		assert(trace.get.class_ == "classy");
105 		assert(trace.get.name == "fred");
106 		assert(trace.get.type == "something");
107 		assert(trace.get.activeType == "no_idea");
108 	}
109 	{
110 		immutable badTrace = parseNumeric!(Numeric.RPL_TRACESERVICE)(takeNone!(string[]));
111 		assert(badTrace.isNull);
112 	}
113 	{
114 		immutable badTrace = parseNumeric!(Numeric.RPL_TRACESERVICE)(only("someone"));
115 		assert(badTrace.isNull);
116 	}
117 	{
118 		immutable badTrace = parseNumeric!(Numeric.RPL_TRACESERVICE)(only("someone", "Service"));
119 		assert(badTrace.isNull);
120 	}
121 	{
122 		immutable badTrace = parseNumeric!(Numeric.RPL_TRACESERVICE)(only("someone", "Service", "classy"));
123 		assert(badTrace.isNull);
124 	}
125 	{
126 		immutable badTrace = parseNumeric!(Numeric.RPL_TRACESERVICE)(only("someone", "Service", "classy", "fred"));
127 		assert(badTrace.isNull);
128 	}
129 	{
130 		immutable badTrace = parseNumeric!(Numeric.RPL_TRACESERVICE)(only("someone", "Service", "classy", "fred", "something"));
131 		assert(badTrace.isNull);
132 	}
133 }
134 struct RPL_TraceClass {
135 	import virc.common : User;
136 	User me;
137 	string classConstant;
138 	string class_;
139 	string count;
140 }
141 /++
142 + Parser for RPL_TRACECLASS.
143 +
144 + Format is `209 <client> Class <class> <count>`
145 +/
146 auto parseNumeric(Numeric numeric : Numeric.RPL_TRACECLASS, T)(T input) {
147 	import virc.numerics.magicparser : autoParse;
148 	return autoParse!RPL_TraceClass(input);
149 }
150 ///
151 @safe pure unittest {
152 	import std.range : only, takeNone;
153 	//Need real world examples... No idea what these will really look like
154 	{
155 		immutable trace = parseNumeric!(Numeric.RPL_TRACECLASS)(only("someone", "CLASS", "classy", "238525813"));
156 		assert(trace.get.class_ == "classy");
157 		assert(trace.get.count == "238525813");
158 	}
159 	{
160 		immutable badTrace = parseNumeric!(Numeric.RPL_TRACECLASS)(takeNone!(string[]));
161 		assert(badTrace.isNull);
162 	}
163 	{
164 		immutable badTrace = parseNumeric!(Numeric.RPL_TRACECLASS)(only("someone"));
165 		assert(badTrace.isNull);
166 	}
167 	{
168 		immutable badTrace = parseNumeric!(Numeric.RPL_TRACECLASS)(only("someone", "Class"));
169 		assert(badTrace.isNull);
170 	}
171 	{
172 		immutable badTrace = parseNumeric!(Numeric.RPL_TRACECLASS)(only("someone", "Class", "classy"));
173 		assert(badTrace.isNull);
174 	}
175 }