aboutsummaryrefslogtreecommitdiff
path: root/src/ext/Msmq/wixext/MsmqCompiler.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/ext/Msmq/wixext/MsmqCompiler.cs')
-rw-r--r--src/ext/Msmq/wixext/MsmqCompiler.cs528
1 files changed, 528 insertions, 0 deletions
diff --git a/src/ext/Msmq/wixext/MsmqCompiler.cs b/src/ext/Msmq/wixext/MsmqCompiler.cs
new file mode 100644
index 00000000..cfc4ef65
--- /dev/null
+++ b/src/ext/Msmq/wixext/MsmqCompiler.cs
@@ -0,0 +1,528 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3namespace WixToolset.Msmq
4{
5 using System;
6 using System.Collections.Generic;
7 using System.Xml.Linq;
8 using WixToolset.Data;
9 using WixToolset.Extensibility;
10 using WixToolset.Msmq.Symbols;
11
12 /// <summary>
13 /// The compiler for the WiX Toolset MSMQ Extension.
14 /// </summary>
15 public sealed class MsmqCompiler : BaseCompilerExtension
16 {
17 public override XNamespace Namespace => "http://wixtoolset.org/schemas/v4/wxs/msmq";
18
19 /// <summary>
20 /// </summary>
21 /// <remarks></remarks>
22 public enum MqiMessageQueueAttributes
23 {
24 Authenticate = (1 << 0),
25 Journal = (1 << 1),
26 Transactional = (1 << 2)
27 }
28
29 /// <summary>
30 /// </summary>
31 /// <remarks></remarks>
32 public enum MqiMessageQueuePrivacyLevel
33 {
34 None = 0,
35 Optional = 1,
36 Body = 2
37 }
38
39 /// <summary>
40 /// </summary>
41 /// <remarks></remarks>
42 public enum MqiMessageQueuePermission
43 {
44 DeleteMessage = (1 << 0),
45 PeekMessage = (1 << 1),
46 WriteMessage = (1 << 2),
47 DeleteJournalMessage = (1 << 3),
48 SetQueueProperties = (1 << 4),
49 GetQueueProperties = (1 << 5),
50 DeleteQueue = (1 << 6),
51 GetQueuePermissions = (1 << 7),
52 ChangeQueuePermissions = (1 << 8),
53 TakeQueueOwnership = (1 << 9),
54 ReceiveMessage = (1 << 10),
55 ReceiveJournalMessage = (1 << 11),
56 QueueGenericRead = (1 << 12),
57 QueueGenericWrite = (1 << 13),
58 QueueGenericExecute = (1 << 14),
59 QueueGenericAll = (1 << 15)
60 }
61
62 /// <summary>
63 /// Processes an element for the Compiler.
64 /// </summary>
65 /// <param name="parentElement">Parent element of element to process.</param>
66 /// <param name="element">Element to process.</param>
67 /// <param name="contextValues">Extra information about the context in which this element is being parsed.</param>
68 public override void ParseElement(Intermediate intermediate, IntermediateSection section, XElement parentElement, XElement element, IDictionary<string, string> context)
69 {
70 switch (parentElement.Name.LocalName)
71 {
72 case "Component":
73 var componentId = context["ComponentId"];
74 var directoryId = context["DirectoryId"];
75
76 switch (element.Name.LocalName)
77 {
78 case "MessageQueue":
79 this.ParseMessageQueueElement(intermediate, section, element, componentId);
80 break;
81 case "MessageQueuePermission":
82 this.ParseMessageQueuePermissionElement(intermediate, section, element, componentId, null);
83 break;
84 default:
85 this.ParseHelper.UnexpectedElement(parentElement, element);
86 break;
87 }
88 break;
89 default:
90 this.ParseHelper.UnexpectedElement(parentElement, element);
91 break;
92 }
93 }
94
95 /// <summary>
96 /// Parses an MSMQ message queue element.
97 /// </summary>
98 /// <param name="node">Element to parse.</param>
99 /// <param name="componentKey">Identifier of parent component.</param>
100 private void ParseMessageQueueElement(Intermediate intermediate, IntermediateSection section, XElement node, string componentId)
101 {
102 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(node);
103
104 Identifier id = null;
105 var basePriority = CompilerConstants.IntegerNotSet;
106 var journalQuota = CompilerConstants.IntegerNotSet;
107 string label = null;
108 string multicastAddress = null;
109 string pathName = null;
110 var privLevel = CompilerConstants.IntegerNotSet;
111 var quota = CompilerConstants.IntegerNotSet;
112 string serviceTypeGuid = null;
113 int attributes = 0;
114
115 foreach (var attrib in node.Attributes())
116 {
117 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
118 {
119 switch (attrib.Name.LocalName)
120 {
121 case "Id":
122 id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
123 break;
124 case "Authenticate":
125 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
126 {
127 attributes |= (int)MqiMessageQueueAttributes.Authenticate;
128 }
129 else
130 {
131 attributes &= ~(int)MqiMessageQueueAttributes.Authenticate;
132 }
133 break;
134 case "BasePriority":
135 basePriority = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, short.MaxValue);
136 break;
137 case "Journal":
138 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
139 {
140 attributes |= (int)MqiMessageQueueAttributes.Journal;
141 }
142 else
143 {
144 attributes &= ~(int)MqiMessageQueueAttributes.Journal;
145 }
146 break;
147 case "JournalQuota":
148 journalQuota = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, int.MaxValue);
149 break;
150 case "Label":
151 label = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
152 break;
153 case "MulticastAddress":
154 multicastAddress = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
155 break;
156 case "PathName":
157 pathName = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
158 break;
159 case "PrivLevel":
160 var privLevelAttr = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
161 switch (privLevelAttr)
162 {
163 case "none":
164 privLevel = (int)MqiMessageQueuePrivacyLevel.None;
165 break;
166 case "optional":
167 privLevel = (int)MqiMessageQueuePrivacyLevel.Optional;
168 break;
169 case "body":
170 privLevel = (int)MqiMessageQueuePrivacyLevel.Body;
171 break;
172 default:
173 this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, "MessageQueue", "PrivLevel", privLevelAttr, "none", "body", "optional"));
174 break;
175 }
176 break;
177 case "Quota":
178 quota = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, int.MaxValue);
179 break;
180 case "Transactional":
181 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
182 {
183 attributes |= (int)MqiMessageQueueAttributes.Transactional;
184 }
185 else
186 {
187 attributes &= ~(int)MqiMessageQueueAttributes.Transactional;
188 }
189 break;
190 case "ServiceTypeGuid":
191 serviceTypeGuid = this.TryFormatGuidValue(this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib));
192 break;
193 default:
194 this.ParseHelper.UnexpectedAttribute(node, attrib);
195 break;
196 }
197 }
198 else
199 {
200 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, node, attrib);
201 }
202 }
203
204 foreach (var child in node.Elements())
205 {
206 if (this.Namespace == child.Name.Namespace)
207 {
208 switch (child.Name.LocalName)
209 {
210 case "MessageQueuePermission":
211 this.ParseMessageQueuePermissionElement(intermediate, section, child, componentId, id?.Id);
212 break;
213 default:
214 this.ParseHelper.UnexpectedElement(node, child);
215 break;
216 }
217 }
218 else
219 {
220 this.ParseHelper.ParseExtensionElement(this.Context.Extensions, intermediate, section, node, child);
221 }
222 }
223
224 var symbol = section.AddSymbol(new MessageQueueSymbol(sourceLineNumbers, id)
225 {
226 ComponentRef = componentId,
227 Label = label,
228 MulticastAddress = multicastAddress,
229 PathName = pathName,
230 ServiceTypeGuid = serviceTypeGuid,
231 Attributes = attributes,
232 });
233
234 if (CompilerConstants.IntegerNotSet != basePriority)
235 {
236 symbol.BasePriority = basePriority;
237 }
238 if (CompilerConstants.IntegerNotSet != journalQuota)
239 {
240 symbol.JournalQuota = journalQuota;
241 }
242
243 if (CompilerConstants.IntegerNotSet != privLevel)
244 {
245 symbol.PrivLevel = privLevel;
246 }
247 if (CompilerConstants.IntegerNotSet != quota)
248 {
249 symbol.Quota = quota;
250 }
251
252 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, SymbolDefinitions.CustomAction, "MessageQueuingInstall");
253 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, SymbolDefinitions.CustomAction, "MessageQueuingUninstall");
254 }
255
256 /// <summary>
257 /// Parses an MSMQ message queue permission element.
258 /// </summary>
259 /// <param name="node">Element to parse.</param>
260 /// <param name="componentKey">Identifier of parent component.</param>
261 /// <param name="applicationKey">Optional identifier of parent message queue.</param>
262 private void ParseMessageQueuePermissionElement(Intermediate intermediate, IntermediateSection section, XElement node, string componentId, string messageQueueId)
263 {
264 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(node);
265
266 Identifier id = null;
267 string user = null;
268 string group = null;
269 int permissions = 0;
270
271 foreach (var attrib in node.Attributes())
272 {
273 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
274 {
275 switch (attrib.Name.LocalName)
276 {
277 case "Id":
278 id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
279 break;
280 case "MessageQueue":
281 if (null != messageQueueId)
282 {
283 this.Messaging.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, node.Parent.Name.LocalName));
284 }
285 messageQueueId = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
286 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, MsmqSymbolDefinitions.MessageQueue, messageQueueId);
287 break;
288 case "User":
289 if (null != group)
290 {
291 this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "User", "Group"));
292 }
293 user = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
294 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "User", user);
295 break;
296 case "Group":
297 if (null != user)
298 {
299 this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Group", "User"));
300 }
301 group = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
302 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "Group", group);
303 break;
304 case "DeleteMessage":
305 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
306 {
307 permissions |= (int)MqiMessageQueuePermission.DeleteMessage;
308 }
309 else
310 {
311 permissions &= ~(int)MqiMessageQueuePermission.DeleteMessage;
312 }
313 break;
314 case "PeekMessage":
315 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
316 {
317 permissions |= (int)MqiMessageQueuePermission.PeekMessage;
318 }
319 else
320 {
321 permissions &= ~(int)MqiMessageQueuePermission.PeekMessage;
322 }
323 break;
324 case "WriteMessage":
325 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
326 {
327 permissions |= (int)MqiMessageQueuePermission.WriteMessage;
328 }
329 else
330 {
331 permissions &= ~(int)MqiMessageQueuePermission.WriteMessage;
332 }
333 break;
334 case "DeleteJournalMessage":
335 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
336 {
337 permissions |= (int)MqiMessageQueuePermission.DeleteJournalMessage;
338 }
339 else
340 {
341 permissions &= ~(int)MqiMessageQueuePermission.DeleteJournalMessage;
342 }
343 break;
344 case "SetQueueProperties":
345 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
346 {
347 permissions |= (int)MqiMessageQueuePermission.SetQueueProperties;
348 }
349 else
350 {
351 permissions &= ~(int)MqiMessageQueuePermission.SetQueueProperties;
352 }
353 break;
354 case "GetQueueProperties":
355 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
356 {
357 permissions |= (int)MqiMessageQueuePermission.GetQueueProperties;
358 }
359 else
360 {
361 permissions &= ~(int)MqiMessageQueuePermission.GetQueueProperties;
362 }
363 break;
364 case "DeleteQueue":
365 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
366 {
367 permissions |= (int)MqiMessageQueuePermission.DeleteQueue;
368 }
369 else
370 {
371 permissions &= ~(int)MqiMessageQueuePermission.DeleteQueue;
372 }
373 break;
374 case "GetQueuePermissions":
375 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
376 {
377 permissions |= (int)MqiMessageQueuePermission.GetQueuePermissions;
378 }
379 else
380 {
381 permissions &= ~(int)MqiMessageQueuePermission.GetQueuePermissions;
382 }
383 break;
384 case "ChangeQueuePermissions":
385 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
386 {
387 permissions |= (int)MqiMessageQueuePermission.ChangeQueuePermissions;
388 }
389 else
390 {
391 permissions &= ~(int)MqiMessageQueuePermission.ChangeQueuePermissions;
392 }
393 break;
394 case "TakeQueueOwnership":
395 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
396 {
397 permissions |= (int)MqiMessageQueuePermission.TakeQueueOwnership;
398 }
399 else
400 {
401 permissions &= ~(int)MqiMessageQueuePermission.TakeQueueOwnership;
402 }
403 break;
404 case "ReceiveMessage":
405 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
406 {
407 permissions |= (int)MqiMessageQueuePermission.ReceiveMessage;
408 }
409 else
410 {
411 permissions &= ~(int)MqiMessageQueuePermission.ReceiveMessage;
412 }
413 break;
414 case "ReceiveJournalMessage":
415 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
416 {
417 permissions |= (int)MqiMessageQueuePermission.ReceiveJournalMessage;
418 }
419 else
420 {
421 permissions &= ~(int)MqiMessageQueuePermission.ReceiveJournalMessage;
422 }
423 break;
424 case "QueueGenericRead":
425 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
426 {
427 permissions |= (int)MqiMessageQueuePermission.QueueGenericRead;
428 }
429 else
430 {
431 permissions &= ~(int)MqiMessageQueuePermission.QueueGenericRead;
432 }
433 break;
434 case "QueueGenericWrite":
435 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
436 {
437 permissions |= (int)MqiMessageQueuePermission.QueueGenericWrite;
438 }
439 else
440 {
441 permissions &= ~(int)MqiMessageQueuePermission.QueueGenericWrite;
442 }
443 break;
444 case "QueueGenericExecute":
445 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
446 {
447 permissions |= (int)MqiMessageQueuePermission.QueueGenericExecute;
448 }
449 else
450 {
451 permissions &= ~(int)MqiMessageQueuePermission.QueueGenericExecute;
452 }
453 break;
454 case "QueueGenericAll":
455 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
456 {
457 permissions |= (int)MqiMessageQueuePermission.QueueGenericAll;
458 }
459 else
460 {
461 permissions &= ~(int)MqiMessageQueuePermission.QueueGenericAll;
462 }
463 break;
464 default:
465 this.ParseHelper.UnexpectedAttribute(node, attrib);
466 break;
467 }
468 }
469 else
470 {
471 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, node, attrib);
472 }
473 }
474
475 if (null == id)
476 {
477 id = this.ParseHelper.CreateIdentifier("mqp", componentId, messageQueueId, user, group);
478 }
479
480 if (null == messageQueueId)
481 {
482 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "MessageQueue"));
483 }
484 if (null == user && null == group)
485 {
486 this.Messaging.Write(ErrorMessages.ExpectedAttributes(sourceLineNumbers, node.Name.LocalName, "User", "Group"));
487 }
488
489 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, node);
490
491 if (null != user)
492 {
493 section.AddSymbol(new MessageQueueUserPermissionSymbol(sourceLineNumbers, id)
494 {
495 ComponentRef = componentId,
496 MessageQueueRef = messageQueueId,
497 UserRef = user,
498 Permissions = permissions,
499 });
500 }
501 if (null != group)
502 {
503 section.AddSymbol(new MessageQueueGroupPermissionSymbol(sourceLineNumbers, id)
504 {
505 ComponentRef = componentId,
506 MessageQueueRef = messageQueueId,
507 GroupRef = group,
508 Permissions = permissions,
509 });
510 }
511 }
512
513 /// <summary>
514 /// Attempts to parse the input value as a GUID, and in case the value is a valid
515 /// GUID returnes it in the format "{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}".
516 /// </summary>
517 /// <param name="val"></param>
518 /// <returns></returns>
519 string TryFormatGuidValue(string val)
520 {
521 if (!Guid.TryParse(val, out var guid))
522 {
523 return val;
524 }
525 return guid.ToString("B").ToUpper();
526 }
527 }
528}