-revert janderwalds change until because it breaks the gcc 4.x build
[reactos.git] / irc / TechBot / TechBot.Library / ErrorCommand.cs
1 using System;
2 using System.Xml;
3 using System.Collections;
4
5 namespace TechBot.Library
6 {
7 public class ErrorCommand : BaseCommand, ICommand
8 {
9 private IServiceOutput serviceOutput;
10 private NtStatusCommand ntStatus;
11 private WinerrorCommand winerror;
12 private HresultCommand hresult;
13
14 public ErrorCommand(IServiceOutput serviceOutput, string ntstatusXml,
15 string winerrorXml, string hresultXml)
16 {
17 this.serviceOutput = serviceOutput;
18 this.ntStatus = new NtStatusCommand(serviceOutput,
19 ntstatusXml);
20 this.winerror = new WinerrorCommand(serviceOutput,
21 winerrorXml);
22 this.hresult = new HresultCommand(serviceOutput,
23 hresultXml);
24 }
25
26 public bool CanHandle(string commandName)
27 {
28 return CanHandle(commandName,
29 new string[] { "error" });
30 }
31
32 private static int GetSeverity(long error)
33 {
34 return (int)((error >> 30) & 0x3);
35 }
36
37 private static bool IsCustomer(long error)
38 {
39 return (error & 0x20000000) != 0;
40 }
41
42 private static bool IsReserved(long error)
43 {
44 return (error & 0x10000000) != 0;
45 }
46
47 private static int GetFacility(long error)
48 {
49 return (int)((error >> 16) & 0xFFF);
50 }
51
52 private static short GetCode(long error)
53 {
54 return (short)((error >> 0) & 0xFFFF);
55 }
56
57 private static string FormatSeverity(long error)
58 {
59 int severity = GetSeverity(error);
60 switch (severity)
61 {
62 case 0: return "SUCCESS";
63 case 1: return "INFORMATIONAL";
64 case 2: return "WARNING";
65 case 3: return "ERROR";
66 }
67 return null;
68 }
69
70 private static string FormatFacility(long error)
71 {
72 int facility = GetFacility(error);
73 return facility.ToString();
74 }
75
76 private static string FormatCode(long error)
77 {
78 int code = GetCode(error);
79 return code.ToString();
80 }
81
82 public void Handle(MessageContext context,
83 string commandName,
84 string parameters)
85 {
86 string originalErrorText = parameters.Trim();
87 if (originalErrorText.Equals(String.Empty))
88 {
89 serviceOutput.WriteLine(context,
90 "Please provide an Error Code.");
91 return;
92 }
93
94 string errorText = originalErrorText;
95
96 retry:
97 NumberParser np = new NumberParser();
98 long error = np.Parse(errorText);
99 if (np.Error)
100 {
101 serviceOutput.WriteLine(context,
102 String.Format("{0} is not a valid Error Code.",
103 originalErrorText));
104 return;
105 }
106
107 ArrayList descriptions = new ArrayList();
108
109 // Error is out of bounds
110 if ((ulong)error > uint.MaxValue)
111 {
112 // Do nothing
113 }
114 // Error is outside of the range [0, 65535]: it cannot be a plain Win32 error code
115 else if ((ulong)error > ushort.MaxValue)
116 {
117 // Customer bit is set: custom error code
118 if (IsCustomer(error))
119 {
120 string description = String.Format("[custom, severity {0}, facility {1}, code {2}]",
121 FormatSeverity(error),
122 FormatFacility(error),
123 FormatCode(error));
124 descriptions.Add(description);
125 }
126 // Reserved bit is set: HRESULT_FROM_NT(ntstatus)
127 else if (IsReserved(error))
128 {
129 int status = (int)(error & 0xCFFFFFFF);
130 string description = ntStatus.GetNtstatusDescription(status);
131
132 if (description == null)
133 description = status.ToString("X");
134
135 description = String.Format("HRESULT_FROM_NT({0})", description);
136 descriptions.Add(description);
137 }
138 // Win32 facility: HRESULT_FROM_WIN32(winerror)
139 else if (GetFacility(error) == 7)
140 {
141 // Must be an error code
142 if (GetSeverity(error) == 2)
143 {
144 short err = GetCode(error);
145 string description = winerror.GetWinerrorDescription(err);
146
147 if (description == null)
148 description = err.ToString("D");
149
150 description = String.Format("HRESULT_FROM_WIN32({0})", description);
151 descriptions.Add(description);
152 }
153 }
154 }
155
156 string winerrorDescription = winerror.GetWinerrorDescription(error);
157 string ntstatusDescription = ntStatus.GetNtstatusDescription(error);
158 string hresultDescription = hresult.GetHresultDescription(error);
159
160 if (winerrorDescription != null)
161 descriptions.Add(winerrorDescription);
162 if (ntstatusDescription != null)
163 descriptions.Add(ntstatusDescription);
164 if (hresultDescription != null)
165 descriptions.Add(hresultDescription);
166
167 if (descriptions.Count == 0)
168 {
169 // Last chance heuristics: attempt to parse a 8-digit decimal as hexadecimal
170 if (errorText.Length == 8)
171 {
172 errorText = "0x" + errorText;
173 goto retry;
174 }
175
176 serviceOutput.WriteLine(context,
177 String.Format("I don't know about Error Code {0}.",
178 originalErrorText));
179 }
180 else if (descriptions.Count == 1)
181 {
182 string description = (string)descriptions[0];
183 serviceOutput.WriteLine(context,
184 String.Format("{0} is {1}.",
185 originalErrorText,
186 description));
187 }
188 else
189 {
190 serviceOutput.WriteLine(context,
191 String.Format("{0} could be:",
192 originalErrorText));
193
194 foreach(string description in descriptions)
195 serviceOutput.WriteLine(context, String.Format("\t{0}", description));
196 }
197 }
198
199 public string Help()
200 {
201 return "!error <value>";
202 }
203 }
204 }