// 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.
namespace WixToolset.Msmq
{
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Security;
using System.Xml.Linq;
using WixToolset.Data;
using WixToolset.Data.WindowsInstaller;
using WixToolset.Extensibility;
using WixToolset.Extensibility.Data;
using WixToolset.Extensibility.Services;
///
/// The decompiler for the WiX Toolset MSMQ Extension.
///
public sealed class MsmqDecompiler : BaseWindowsInstallerDecompilerExtension
{
public override IReadOnlyCollection TableDefinitions => MsmqTableDefinitions.All;
private IParseHelper ParseHelper { get; set; }
internal static XNamespace Namespace => "http://wixtoolset.org/schemas/v4/wxs/msmq";
internal static XName MessageQueueName => Namespace + "MessageQueue";
internal static XName MessageQueuePermissionName => Namespace + "MessageQueuePermission";
public override void PreDecompile(IWindowsInstallerDecompileContext context, IWindowsInstallerDecompilerHelper helper)
{
base.PreDecompile(context, helper);
this.ParseHelper = context.ServiceProvider.GetService();
}
///
/// Called at the beginning of the decompilation of a database.
///
/// The collection of all tables.
public override void PreDecompileTables(TableIndexedCollection tables)
{
}
///
/// Decompiles an extension table.
///
/// The table to decompile.
public override bool TryDecompileTable(Table table)
{
switch (table.Name)
{
case "MessageQueue":
case "Wix4MessageQueue":
this.DecompileMessageQueueTable(table);
break;
case "MessageQueueUserPermission":
case "Wix4MessageQueueUserPermission":
this.DecompileMessageQueueUserPermissionTable(table);
break;
case "MessageQueueGroupPermission":
case "Wix4MessageQueueGroupPermission":
this.DecompileMessageQueueGroupPermissionTable(table);
break;
default:
return false;
}
return true;
}
///
/// Finalize decompilation.
///
/// The collection of all tables.
public override void PostDecompileTables(TableIndexedCollection tables)
{
this.FinalizeMessageQueueTable(tables);
this.FinalizeMessageQueueUserPermissionTable(tables);
this.FinalizeMessageQueueGroupPermissionTable(tables);
}
///
/// Decompile the MessageQueue table.
///
/// The table to decompile.
private void DecompileMessageQueueTable(Table table)
{
foreach (Row row in table.Rows)
{
var messageQueue = new XElement(MessageQueueName,
new XAttribute("Id", row.FieldAsString(0))
);
// Column(1) Component_ resolved in FinalizeMessageQueueTable
if (!row.IsColumnEmpty(2))
{
messageQueue.Add(new XAttribute("BasePriority", row.FieldAsString(2)));
}
if (!row.IsColumnEmpty(3))
{
messageQueue.Add(new XAttribute("JournalQuota", row.FieldAsString(3)));
}
messageQueue.Add(new XAttribute("Label", row.FieldAsString(4)));
if (!row.IsColumnEmpty(5))
{
messageQueue.Add(new XAttribute("MulticastAddress", row.FieldAsString(5)));
}
messageQueue.Add(new XAttribute("PathName", row.FieldAsString(6)));
if (!row.IsColumnEmpty(7))
{
int privLevel = row.FieldAsInteger(7);
switch ((MsmqCompiler.MqiMessageQueuePrivacyLevel)privLevel)
{
case MsmqCompiler.MqiMessageQueuePrivacyLevel.None:
messageQueue.Add(new XAttribute("PrivLevel", "none"));
break;
case MsmqCompiler.MqiMessageQueuePrivacyLevel.Optional:
messageQueue.Add(new XAttribute("PrivLevel", "optional"));
break;
case MsmqCompiler.MqiMessageQueuePrivacyLevel.Body:
messageQueue.Add(new XAttribute("PrivLevel", "body"));
break;
default:
break;
}
}
if (!row.IsColumnEmpty(8))
{
messageQueue.Add(new XAttribute("Quota", row.FieldAsString(8)));
}
if (!row.IsColumnEmpty(9))
{
messageQueue.Add(new XAttribute("ServiceTypeGuid", row.FieldAsString(9)));
}
int attributes = row.FieldAsInteger(10);
if (0 != (attributes & (int)MsmqCompiler.MqiMessageQueueAttributes.Authenticate))
{
messageQueue.Add(new XAttribute("Authenticate", "yes"));
}
if (0 != (attributes & (int)MsmqCompiler.MqiMessageQueueAttributes.Journal))
{
messageQueue.Add(new XAttribute("Journal", "yes"));
}
if (0 != (attributes & (int)MsmqCompiler.MqiMessageQueueAttributes.Transactional))
{
messageQueue.Add(new XAttribute("Transactional", "yes"));
}
this.DecompilerHelper.IndexElement(row, messageQueue);
}
}
///
/// Finalize the MessageQueue table.
///
/// Collection of all tables.
private void FinalizeMessageQueueTable(TableIndexedCollection tables)
{
Table messageQueueTable;
if (tables.TryGetTable("MessageQueue", out messageQueueTable)
|| tables.TryGetTable("Wix4MessageQueue", out messageQueueTable))
{
foreach (var row in messageQueueTable.Rows)
{
var xmlConfig = this.DecompilerHelper.GetIndexedElement(row);
var componentId = row.FieldAsString(1);
if (this.DecompilerHelper.TryGetIndexedElement("Component", componentId, out var component))
{
component.Add(xmlConfig);
}
else
{
this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, messageQueueTable.Name, row.GetPrimaryKey(), "Component_", componentId, "Component"));
}
}
}
}
///
/// Decompile the MessageQueueUserPermission table.
///
/// The table to decompile.
private void DecompileMessageQueueUserPermissionTable(Table table)
{
foreach (Row row in table.Rows)
{
var queuePermission = new XElement(MessageQueuePermissionName,
new XAttribute("Id", row.FieldAsString(0))
);
DecompileMessageQueuePermissionAttributes(row, queuePermission);
this.DecompilerHelper.IndexElement(row, queuePermission);
}
}
///
/// Finalize the MessageQueueUserPermissionTable table.
///
/// Collection of all tables.
private void FinalizeMessageQueueUserPermissionTable(TableIndexedCollection tables)
{
Table messageQueueUserPermissionTable;
if (tables.TryGetTable("MessageQueueUserPermission", out messageQueueUserPermissionTable)
|| tables.TryGetTable("Wix4MessageQueueUserPermission", out messageQueueUserPermissionTable))
{
foreach (var row in messageQueueUserPermissionTable.Rows)
{
var xmlConfig = this.DecompilerHelper.GetIndexedElement(row);
var componentId = row.FieldAsString(1);
if (this.DecompilerHelper.TryGetIndexedElement("Component", componentId, out var component))
{
component.Add(xmlConfig);
}
else
{
this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, messageQueueUserPermissionTable.Name, row.GetPrimaryKey(), "Component_", componentId, "Component"));
}
var messageQueueId = row.FieldAsString(2);
XElement messageQueue;
if (this.DecompilerHelper.TryGetIndexedElement("MessageQueue", messageQueueId, out messageQueue)
|| this.DecompilerHelper.TryGetIndexedElement("Wix4MessageQueue", messageQueueId, out messageQueue))
{
xmlConfig.Add(new XAttribute("MessageQueue", messageQueueId));
}
else
{
this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, messageQueueUserPermissionTable.Name, row.GetPrimaryKey(), "MessageQueue_", messageQueueId, "Wix4MessageQueue"));
}
var userId = row.FieldAsString(3);
XElement user;
if (this.DecompilerHelper.TryGetIndexedElement("User", userId, out user)
|| this.DecompilerHelper.TryGetIndexedElement("Wix4User", userId, out user))
{
xmlConfig.Add(new XAttribute("User", userId));
}
else
{
this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, messageQueueUserPermissionTable.Name, row.GetPrimaryKey(), "User_", userId, "Wix4User"));
}
}
}
}
///
/// Decompile the MessageQueueGroupPermission table.
///
/// The table to decompile.
private void DecompileMessageQueueGroupPermissionTable(Table table)
{
foreach (Row row in table.Rows)
{
var queuePermission = new XElement(MessageQueuePermissionName,
new XAttribute("Id", row.FieldAsString(0))
);
DecompileMessageQueuePermissionAttributes(row, queuePermission);
this.DecompilerHelper.IndexElement(row, queuePermission);
}
}
///
/// Finalize the MessageQueueGroupPermissionTable table.
///
/// Collection of all tables.
private void FinalizeMessageQueueGroupPermissionTable(TableIndexedCollection tables)
{
Table messageQueueGroupPermissionTable;
if (tables.TryGetTable("MessageQueueGroupPermission", out messageQueueGroupPermissionTable)
|| tables.TryGetTable("Wix4MessageQueueGroupPermission", out messageQueueGroupPermissionTable))
{
foreach (var row in messageQueueGroupPermissionTable.Rows)
{
var xmlConfig = this.DecompilerHelper.GetIndexedElement(row);
var componentId = row.FieldAsString(1);
if (this.DecompilerHelper.TryGetIndexedElement("Component", componentId, out var component))
{
component.Add(xmlConfig);
}
else
{
this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, messageQueueGroupPermissionTable.Name, row.GetPrimaryKey(), "Component_", componentId, "Component"));
}
var messageQueueId = row.FieldAsString(2);
XElement messageQueue;
if (this.DecompilerHelper.TryGetIndexedElement("MessageQueue", messageQueueId, out messageQueue)
|| this.DecompilerHelper.TryGetIndexedElement("Wix4MessageQueue", messageQueueId, out messageQueue))
{
xmlConfig.Add(new XAttribute("MessageQueue", messageQueueId));
}
else
{
this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, messageQueueGroupPermissionTable.Name, row.GetPrimaryKey(), "MessageQueue_", messageQueueId, "Wix4MessageQueue"));
}
var groupId = row.FieldAsString(3);
XElement group;
if (this.DecompilerHelper.TryGetIndexedElement("Group", groupId, out group)
|| this.DecompilerHelper.TryGetIndexedElement("Wix4Group", groupId, out group))
{
xmlConfig.Add(new XAttribute("Group", groupId));
}
else
{
this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, messageQueueGroupPermissionTable.Name, row.GetPrimaryKey(), "Group_", groupId, "Wix4Group"));
}
}
}
}
///
/// Decompile row attributes for the MessageQueueUserPermission and MessageQueueGroupPermission tables.
///
/// The row to decompile.
/// Target element.
private void DecompileMessageQueuePermissionAttributes(Row row, XElement element)
{
int attributes = row.FieldAsInteger(4);
if (0 != (attributes & (int)MsmqCompiler.MqiMessageQueuePermission.DeleteMessage))
{
element.Add(new XAttribute("DeleteMessage", "yes"));
}
if (0 != (attributes & (int)MsmqCompiler.MqiMessageQueuePermission.PeekMessage))
{
element.Add(new XAttribute("PeekMessage", "yes"));
}
if (0 != (attributes & (int)MsmqCompiler.MqiMessageQueuePermission.WriteMessage))
{
element.Add(new XAttribute("WriteMessage", "yes"));
}
if (0 != (attributes & (int)MsmqCompiler.MqiMessageQueuePermission.DeleteJournalMessage))
{
element.Add(new XAttribute("DeleteJournalMessage", "yes"));
}
if (0 != (attributes & (int)MsmqCompiler.MqiMessageQueuePermission.SetQueueProperties))
{
element.Add(new XAttribute("SetQueueProperties", "yes"));
}
if (0 != (attributes & (int)MsmqCompiler.MqiMessageQueuePermission.GetQueueProperties))
{
element.Add(new XAttribute("GetQueueProperties", "yes"));
}
if (0 != (attributes & (int)MsmqCompiler.MqiMessageQueuePermission.DeleteQueue))
{
element.Add(new XAttribute("DeleteQueue", "yes"));
}
if (0 != (attributes & (int)MsmqCompiler.MqiMessageQueuePermission.GetQueuePermissions))
{
element.Add(new XAttribute("GetQueuePermissions", "yes"));
}
if (0 != (attributes & (int)MsmqCompiler.MqiMessageQueuePermission.ChangeQueuePermissions))
{
element.Add(new XAttribute("ChangeQueuePermissions", "yes"));
}
if (0 != (attributes & (int)MsmqCompiler.MqiMessageQueuePermission.TakeQueueOwnership))
{
element.Add(new XAttribute("TakeQueueOwnership", "yes"));
}
if (0 != (attributes & (int)MsmqCompiler.MqiMessageQueuePermission.ReceiveMessage))
{
element.Add(new XAttribute("ReceiveMessage", "yes"));
}
if (0 != (attributes & (int)MsmqCompiler.MqiMessageQueuePermission.ReceiveJournalMessage))
{
element.Add(new XAttribute("ReceiveJournalMessage", "yes"));
}
if (0 != (attributes & (int)MsmqCompiler.MqiMessageQueuePermission.QueueGenericRead))
{
element.Add(new XAttribute("QueueGenericRead", "yes"));
}
if (0 != (attributes & (int)MsmqCompiler.MqiMessageQueuePermission.QueueGenericWrite))
{
element.Add(new XAttribute("QueueGenericWrite", "yes"));
}
if (0 != (attributes & (int)MsmqCompiler.MqiMessageQueuePermission.QueueGenericExecute))
{
element.Add(new XAttribute("QueueGenericExecute", "yes"));
}
if (0 != (attributes & (int)MsmqCompiler.MqiMessageQueuePermission.QueueGenericAll))
{
element.Add(new XAttribute("QueueGenericAll", "yes"));
}
}
}
}