1 /++
2 +
3 +/
4 module virc.numerics.sasl;
5 
6 import std.algorithm : among;
7 
8 import virc.numerics.definitions;
9 
10 /++
11 +
12 + Format is `900 <nick> <nick>!<ident>@<host> <account> :You are now logged in as <user>`
13 +/
14 //900 <nick> <nick>!<ident>@<host> <account> :You are now logged in as <user>
15 auto parseNumeric(Numeric numeric : Numeric.RPL_LOGGEDIN, T)(T input) {
16 	import std.typecons : Nullable;
17 	import virc.common : User;
18 	import virc.usermask : UserMask;
19 	Nullable!User user;
20 	if (input.empty) {
21 		return user;
22 	}
23 	input.popFront();
24 	if (input.empty) {
25 		return user.init;
26 	}
27 	user = User(input.front);
28 	input.popFront();
29 	if (input.empty) {
30 		return user.init;
31 	}
32 	user.get.account = input.front;
33 	return user;
34 }
35 ///
36 @safe pure nothrow @nogc unittest { //Numeric.RPL_LOGGEDIN
37 	import std.range : only, takeNone;
38 	{
39 		immutable logon = parseNumeric!(Numeric.RPL_LOGGEDIN)(only("test", "someone!someIdent@example.net", "some_account", "Well hello there"));
40 		assert(logon.get.mask.nickname == "someone");
41 		assert(logon.get.mask.ident == "someIdent");
42 		assert(logon.get.mask.host == "example.net");
43 		assert(logon.get.account == "some_account");
44 	}
45 	{
46 		immutable logon = parseNumeric!(Numeric.RPL_LOGGEDIN)(takeNone(only("")));
47 		assert(logon.isNull);
48 	}
49 	{
50 		immutable logon = parseNumeric!(Numeric.RPL_LOGGEDIN)(only("test"));
51 		assert(logon.isNull);
52 	}
53 	{
54 		immutable logon = parseNumeric!(Numeric.RPL_LOGGEDIN)(only("test", "someone!someIdent@example.net"));
55 		assert(logon.isNull);
56 	}
57 }
58 /++
59 +
60 + Format is `901 <nick> <nick>!<ident>@<host> :You are now logged out`
61 +/
62 auto parseNumeric(Numeric numeric : Numeric.RPL_LOGGEDOUT, T)(T input) {
63 	import std.typecons : Nullable;
64 	import virc.common : User;
65 	import virc.usermask : UserMask;
66 	Nullable!User user;
67 	if (input.empty) {
68 		return user;
69 	}
70 	input.popFront();
71 	if (input.empty) {
72 		return user.init;
73 	}
74 	user = User(input.front);
75 	return user;
76 }
77 ///
78 @safe pure nothrow @nogc unittest { //Numeric.RPL_LOGGEDOUT
79 	import std.range : only, takeNone;
80 	{
81 		immutable logon = parseNumeric!(Numeric.RPL_LOGGEDOUT)(only("test", "someone!someIdent@example.net", "Well hello there"));
82 		assert(logon.get.mask.nickname == "someone");
83 		assert(logon.get.mask.ident == "someIdent");
84 		assert(logon.get.mask.host == "example.net");
85 		assert(logon.get.account.isNull);
86 	}
87 	{
88 		immutable logon = parseNumeric!(Numeric.RPL_LOGGEDOUT)(takeNone(only("")));
89 		assert(logon.isNull);
90 	}
91 	{
92 		immutable logon = parseNumeric!(Numeric.RPL_LOGGEDOUT)(only("test"));
93 		assert(logon.isNull);
94 	}
95 }
96 /++
97 + SASL numerics that don't have any parsable information.
98 +
99 + This includes 902, 903, 904, 905, 906 and 907.
100 +/
101 void parseNumeric(Numeric numeric, T)(T) if (numeric.among(Numeric.ERR_NICKLOCKED, Numeric.RPL_SASLSUCCESS, Numeric.ERR_SASLFAIL, Numeric.ERR_SASLTOOLONG, Numeric.ERR_SASLABORTED, Numeric.ERR_SASLALREADY)) {
102 }
103 ///
104 @safe pure nothrow @nogc unittest { //Numeric.RPL_LOGGEDOUT
105 	import std.range : only;
106 	{
107 		parseNumeric!(Numeric.ERR_NICKLOCKED)(only("test", "You must use a nick assigned to you"));
108 	}
109 	{
110 		parseNumeric!(Numeric.RPL_SASLSUCCESS)(only("test", "SASL authentication successful"));
111 	}
112 	{
113 		parseNumeric!(Numeric.ERR_SASLFAIL)(only("test", "SASL authentication failed"));
114 	}
115 	{
116 		parseNumeric!(Numeric.ERR_SASLTOOLONG)(only("test", "SASL message too long"));
117 	}
118 	{
119 		parseNumeric!(Numeric.ERR_SASLABORTED)(only("test", "SASL authentication aborted"));
120 	}
121 	{
122 		parseNumeric!(Numeric.ERR_SASLALREADY)(only("test", "You have already authenticated using SASL"));
123 	}
124 }
125 
126 /++
127 + RPL_SASLMECHS. This is sent in response to a request for a mechanism the
128 + server does not support, and will list any mechanisms that are available.
129 +
130 + Format is `908 <nick> <mechanisms> :are available SASL mechanisms`
131 +/
132 auto parseNumeric(Numeric numeric : Numeric.RPL_SASLMECHS, T)(T input) {
133 	import std.algorithm : splitter;
134 	import std.typecons : nullable;
135 	if (!input.empty) {
136 		input.popFront();
137 	}
138 	if (!input.empty) {
139 		return nullable(input.front.splitter(","));
140 	} else {
141 		return typeof(return).init;
142 	}
143 }
144 ///
145 @safe pure nothrow @nogc unittest { //Numeric.RPL_SASLMECHS
146 	import std.algorithm.searching : canFind;
147 	import std.range : only, takeNone;
148 	{
149 		auto logon = parseNumeric!(Numeric.RPL_SASLMECHS)(only("test", "EXTERNAL,PLAIN", "Well hello there"));
150 		assert(logon.get.canFind("EXTERNAL"));
151 		assert(logon.get.canFind("PLAIN"));
152 	}
153 	{
154 		immutable logon = parseNumeric!(Numeric.RPL_SASLMECHS)(takeNone(only("")));
155 		assert(logon.isNull);
156 	}
157 	{
158 		immutable logon = parseNumeric!(Numeric.RPL_SASLMECHS)(only("test"));
159 		assert(logon.isNull);
160 	}
161 }