From c8f60440a00d5d26cd10554066bdd3f78c71667b Mon Sep 17 00:00:00 2001 From: xWTF Date: Sun, 8 Jan 2023 20:38:05 +0800 Subject: [PATCH] Initial code upload --- README.md | 87 +++++++ SnipeIT-bPAC.sln | 28 +++ SnipeIT-bPAC/App.config | 21 ++ SnipeIT-bPAC/HttpListenerContextExtension.cs | 25 ++ SnipeIT-bPAC/Interop.bpac.dll | Bin 0 -> 25600 bytes SnipeIT-bPAC/Program.cs | 17 ++ SnipeIT-bPAC/Properties/Settings.Designer.cs | 62 +++++ SnipeIT-bPAC/Properties/Settings.settings | 15 ++ SnipeIT-bPAC/ServerForm.Designer.cs | 228 +++++++++++++++++++ SnipeIT-bPAC/ServerForm.cs | 227 ++++++++++++++++++ SnipeIT-bPAC/ServerForm.resx | 63 +++++ SnipeIT-bPAC/SnipeIT-bPAC.csproj | 43 ++++ 12 files changed, 816 insertions(+) create mode 100644 README.md create mode 100644 SnipeIT-bPAC.sln create mode 100644 SnipeIT-bPAC/App.config create mode 100644 SnipeIT-bPAC/HttpListenerContextExtension.cs create mode 100644 SnipeIT-bPAC/Interop.bpac.dll create mode 100644 SnipeIT-bPAC/Program.cs create mode 100644 SnipeIT-bPAC/Properties/Settings.Designer.cs create mode 100644 SnipeIT-bPAC/Properties/Settings.settings create mode 100644 SnipeIT-bPAC/ServerForm.Designer.cs create mode 100644 SnipeIT-bPAC/ServerForm.cs create mode 100644 SnipeIT-bPAC/ServerForm.resx create mode 100644 SnipeIT-bPAC/SnipeIT-bPAC.csproj diff --git a/README.md b/README.md new file mode 100644 index 0000000..7d86405 --- /dev/null +++ b/README.md @@ -0,0 +1,87 @@ +# Snipe-IT bPAC Daemon + +## Usage + +Install the [bPAC Client Component](https://support.brother.com/g/s/es/dev/en/bpac/download/index.html#client) on the server that runs this daemon. + +(TODO: Write detailed guide) + +## Start with Windows + +Create a shortcut in `shell:startup` folder. + +## Start minimized + +Just pass `-m` to the argument list. + +# labels.blade.php + +Replace `resources/views/hardware/labels.blade.php` with content below: + +Specifically, if you're using docker, mount it to `/var/www/html/resources/views/hardware/labels.blade.php`. + +```php + 'ID: ' . $asset->id, + 'name' => empty($asset->name) ? '' : 'N: ' . $asset->name, + 'serial' => empty($asset->serial) ? '' : 'S: ' . $asset->serial, + 'model' => empty($asset->model->name) ? '' : 'M: ' . $asset->model->name, + 'company' => $asset->company === null ? null : 'C: ' . $asset->company->name, + 'asset_tag' => $asset->asset_tag, + ]; +} +?> + + + + + + + Labels Print + + + +
+ Labels Data: +
+ +
+ +
+ + + + +``` diff --git a/SnipeIT-bPAC.sln b/SnipeIT-bPAC.sln new file mode 100644 index 0000000..435a2b4 --- /dev/null +++ b/SnipeIT-bPAC.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.3.32804.467 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SnipeIT-bPAC", "SnipeIT-bPAC\SnipeIT-bPAC.csproj", "{4FC36674-2D6F-4DDD-AB2E-5DA6A1B13B26}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {4FC36674-2D6F-4DDD-AB2E-5DA6A1B13B26}.Debug|Any CPU.ActiveCfg = Debug|x64 + {4FC36674-2D6F-4DDD-AB2E-5DA6A1B13B26}.Debug|x86.ActiveCfg = Debug|x86 + {4FC36674-2D6F-4DDD-AB2E-5DA6A1B13B26}.Debug|x86.Build.0 = Debug|x86 + {4FC36674-2D6F-4DDD-AB2E-5DA6A1B13B26}.Release|Any CPU.ActiveCfg = Release|x64 + {4FC36674-2D6F-4DDD-AB2E-5DA6A1B13B26}.Release|x86.ActiveCfg = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {84AD9696-89C8-4A3B-AFBD-30C6889879DB} + EndGlobalSection +EndGlobal diff --git a/SnipeIT-bPAC/App.config b/SnipeIT-bPAC/App.config new file mode 100644 index 0000000..c95444a --- /dev/null +++ b/SnipeIT-bPAC/App.config @@ -0,0 +1,21 @@ + + + + +
+ + + + + + + + + + + + 8000 + + + + \ No newline at end of file diff --git a/SnipeIT-bPAC/HttpListenerContextExtension.cs b/SnipeIT-bPAC/HttpListenerContextExtension.cs new file mode 100644 index 0000000..f77714c --- /dev/null +++ b/SnipeIT-bPAC/HttpListenerContextExtension.cs @@ -0,0 +1,25 @@ +using System.Net; +using System.Text; +using System.Text.Json; + +namespace SnipeIT_bPAC +{ + public static class HttpListenerContextExtension + { + public static void SendJson(this HttpListenerContext ctx, object? data) + { + var resp = ctx.Response; + resp.StatusCode = 200; + resp.ContentType = "application/json"; + + resp.AppendHeader("Access-Control-Allow-Origin", "*"); + resp.AppendHeader("Access-Control-Allow-Headers", "authorization"); + + if (data != null) + { + resp.OutputStream.Write(Encoding.UTF8.GetBytes(JsonSerializer.Serialize(data))); + } + resp.OutputStream.Close(); + } + } +} diff --git a/SnipeIT-bPAC/Interop.bpac.dll b/SnipeIT-bPAC/Interop.bpac.dll new file mode 100644 index 0000000000000000000000000000000000000000..bfe58dff9c32f6a96793bd7095b430b4f3c2be7a GIT binary patch literal 25600 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 literal 0 HcmV?d00001 diff --git a/SnipeIT-bPAC/Program.cs b/SnipeIT-bPAC/Program.cs new file mode 100644 index 0000000..084a3f2 --- /dev/null +++ b/SnipeIT-bPAC/Program.cs @@ -0,0 +1,17 @@ +namespace SnipeIT_bPAC +{ + internal static class Program + { + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main(string[] args) + { + // To customize application configuration such as set high DPI settings or default font, + // see https://aka.ms/applicationconfiguration. + ApplicationConfiguration.Initialize(); + Application.Run(new ServerForm(args)); + } + } +} \ No newline at end of file diff --git a/SnipeIT-bPAC/Properties/Settings.Designer.cs b/SnipeIT-bPAC/Properties/Settings.Designer.cs new file mode 100644 index 0000000..afaff68 --- /dev/null +++ b/SnipeIT-bPAC/Properties/Settings.Designer.cs @@ -0,0 +1,62 @@ +//------------------------------------------------------------------------------ +// +// 此代码由工具生成。 +// 运行时版本:4.0.30319.42000 +// +// 对此文件的更改可能会导致不正确的行为,并且如果 +// 重新生成代码,这些更改将会丢失。 +// +//------------------------------------------------------------------------------ + +namespace SnipeIT_bPAC.Properties { + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.3.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default { + get { + return defaultInstance; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("")] + public string AccessKey { + get { + return ((string)(this["AccessKey"])); + } + set { + this["AccessKey"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("")] + public string TemplateFile { + get { + return ((string)(this["TemplateFile"])); + } + set { + this["TemplateFile"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("8000")] + public ushort ServerPort { + get { + return ((ushort)(this["ServerPort"])); + } + set { + this["ServerPort"] = value; + } + } + } +} diff --git a/SnipeIT-bPAC/Properties/Settings.settings b/SnipeIT-bPAC/Properties/Settings.settings new file mode 100644 index 0000000..46dc61a --- /dev/null +++ b/SnipeIT-bPAC/Properties/Settings.settings @@ -0,0 +1,15 @@ + + + + + + + + + + + + 8000 + + + \ No newline at end of file diff --git a/SnipeIT-bPAC/ServerForm.Designer.cs b/SnipeIT-bPAC/ServerForm.Designer.cs new file mode 100644 index 0000000..566117c --- /dev/null +++ b/SnipeIT-bPAC/ServerForm.Designer.cs @@ -0,0 +1,228 @@ +namespace SnipeIT_bPAC +{ + partial class ServerForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.label1 = new System.Windows.Forms.Label(); + this.label2 = new System.Windows.Forms.Label(); + this.textBox_accesskey = new System.Windows.Forms.TextBox(); + this.textBox_template = new System.Windows.Forms.TextBox(); + this.checkBox1 = new System.Windows.Forms.CheckBox(); + this.button_selectFile = new System.Windows.Forms.Button(); + this.notifyIcon1 = new System.Windows.Forms.NotifyIcon(this.components); + this.textBox_log = new System.Windows.Forms.TextBox(); + this.label3 = new System.Windows.Forms.Label(); + this.button_start = new System.Windows.Forms.Button(); + this.button_stop = new System.Windows.Forms.Button(); + this.numericUpDown_port = new System.Windows.Forms.NumericUpDown(); + this.linkLabel1 = new System.Windows.Forms.LinkLabel(); + ((System.ComponentModel.ISupportInitialize)(this.numericUpDown_port)).BeginInit(); + this.SuspendLayout(); + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(12, 47); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(75, 17); + this.label1.TabIndex = 0; + this.label1.Text = "Access Key:"; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(12, 78); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(88, 17); + this.label2.TabIndex = 1; + this.label2.Text = "Template File:"; + // + // textBox_accesskey + // + this.textBox_accesskey.Location = new System.Drawing.Point(106, 44); + this.textBox_accesskey.Name = "textBox_accesskey"; + this.textBox_accesskey.PasswordChar = '*'; + this.textBox_accesskey.Size = new System.Drawing.Size(343, 23); + this.textBox_accesskey.TabIndex = 2; + this.textBox_accesskey.Leave += new System.EventHandler(this.SaveSettings); + // + // textBox_template + // + this.textBox_template.Location = new System.Drawing.Point(106, 75); + this.textBox_template.Name = "textBox_template"; + this.textBox_template.Size = new System.Drawing.Size(318, 23); + this.textBox_template.TabIndex = 3; + this.textBox_template.Leave += new System.EventHandler(this.SaveSettings); + // + // checkBox1 + // + this.checkBox1.AutoSize = true; + this.checkBox1.Location = new System.Drawing.Point(455, 49); + this.checkBox1.Name = "checkBox1"; + this.checkBox1.Size = new System.Drawing.Size(15, 14); + this.checkBox1.TabIndex = 4; + this.checkBox1.UseVisualStyleBackColor = true; + this.checkBox1.CheckedChanged += new System.EventHandler(this.checkBox1_CheckedChanged); + // + // button_selectFile + // + this.button_selectFile.Location = new System.Drawing.Point(430, 75); + this.button_selectFile.Name = "button_selectFile"; + this.button_selectFile.Size = new System.Drawing.Size(40, 23); + this.button_selectFile.TabIndex = 5; + this.button_selectFile.Text = "..."; + this.button_selectFile.UseVisualStyleBackColor = true; + this.button_selectFile.Click += new System.EventHandler(this.button_selectFile_Click); + // + // notifyIcon1 + // + this.notifyIcon1.Text = "SnipeIT bPAC Daemon"; + this.notifyIcon1.MouseClick += new System.Windows.Forms.MouseEventHandler(this.notifyIcon1_MouseClick); + // + // textBox_log + // + this.textBox_log.Location = new System.Drawing.Point(12, 116); + this.textBox_log.Multiline = true; + this.textBox_log.Name = "textBox_log"; + this.textBox_log.ReadOnly = true; + this.textBox_log.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; + this.textBox_log.Size = new System.Drawing.Size(458, 183); + this.textBox_log.TabIndex = 6; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(12, 15); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(76, 17); + this.label3.TabIndex = 7; + this.label3.Text = "Server Port:"; + // + // button_start + // + this.button_start.Location = new System.Drawing.Point(314, 12); + this.button_start.Name = "button_start"; + this.button_start.Size = new System.Drawing.Size(75, 23); + this.button_start.TabIndex = 9; + this.button_start.Text = "Start"; + this.button_start.UseVisualStyleBackColor = true; + this.button_start.Click += new System.EventHandler(this.button_start_Click); + // + // button_stop + // + this.button_stop.Enabled = false; + this.button_stop.Location = new System.Drawing.Point(395, 12); + this.button_stop.Name = "button_stop"; + this.button_stop.Size = new System.Drawing.Size(75, 23); + this.button_stop.TabIndex = 10; + this.button_stop.Text = "Stop"; + this.button_stop.UseVisualStyleBackColor = true; + this.button_stop.Click += new System.EventHandler(this.button_stop_Click); + // + // numericUpDown_port + // + this.numericUpDown_port.Location = new System.Drawing.Point(106, 12); + this.numericUpDown_port.Maximum = new decimal(new int[] { + 65535, + 0, + 0, + 0}); + this.numericUpDown_port.Minimum = new decimal(new int[] { + 1, + 0, + 0, + 0}); + this.numericUpDown_port.Name = "numericUpDown_port"; + this.numericUpDown_port.Size = new System.Drawing.Size(202, 23); + this.numericUpDown_port.TabIndex = 11; + this.numericUpDown_port.Value = new decimal(new int[] { + 1, + 0, + 0, + 0}); + this.numericUpDown_port.ValueChanged += new System.EventHandler(this.SaveSettings); + // + // linkLabel1 + // + this.linkLabel1.AutoSize = true; + this.linkLabel1.Location = new System.Drawing.Point(235, 302); + this.linkLabel1.Name = "linkLabel1"; + this.linkLabel1.Size = new System.Drawing.Size(235, 17); + this.linkLabel1.TabIndex = 12; + this.linkLabel1.TabStop = true; + this.linkLabel1.Text = "https://github.com/xWTF/SnipeIT-bPAC"; + this.linkLabel1.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkLabel1_LinkClicked); + // + // ServerForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 17F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(482, 328); + this.Controls.Add(this.linkLabel1); + this.Controls.Add(this.numericUpDown_port); + this.Controls.Add(this.button_stop); + this.Controls.Add(this.button_start); + this.Controls.Add(this.label3); + this.Controls.Add(this.textBox_log); + this.Controls.Add(this.button_selectFile); + this.Controls.Add(this.checkBox1); + this.Controls.Add(this.textBox_template); + this.Controls.Add(this.textBox_accesskey); + this.Controls.Add(this.label2); + this.Controls.Add(this.label1); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; + this.MaximizeBox = false; + this.Name = "ServerForm"; + this.Text = "Snipe-IT bPAC Daemon"; + this.Load += new System.EventHandler(this.ServerForm_Load); + this.SizeChanged += new System.EventHandler(this.ServerForm_SizeChanged); + this.VisibleChanged += new System.EventHandler(this.ServerForm_VisibleChanged); + ((System.ComponentModel.ISupportInitialize)(this.numericUpDown_port)).EndInit(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private Label label1; + private Label label2; + private TextBox textBox_accesskey; + private TextBox textBox_template; + private CheckBox checkBox1; + private Button button_selectFile; + private NotifyIcon notifyIcon1; + private TextBox textBox_log; + private Label label3; + private Button button_start; + private Button button_stop; + private NumericUpDown numericUpDown_port; + private LinkLabel linkLabel1; + } +} \ No newline at end of file diff --git a/SnipeIT-bPAC/ServerForm.cs b/SnipeIT-bPAC/ServerForm.cs new file mode 100644 index 0000000..6258d64 --- /dev/null +++ b/SnipeIT-bPAC/ServerForm.cs @@ -0,0 +1,227 @@ +using bpac; +using System.Diagnostics; +using System.Net; +using System.Text; +using System.Text.Json; + +namespace SnipeIT_bPAC +{ + public partial class ServerForm : Form + { + public HttpListener? Listener; + public DocumentClass Document = new DocumentClass(); + + private bool StartMinimized = false; + + public ServerForm(string[] args) + { + if (args.Contains("-m")) + { + StartMinimized = true; + } + + InitializeComponent(); + + notifyIcon1.Icon = Icon; + textBox_log.BackColor = Color.White; + + numericUpDown_port.DataBindings.Add("Value", Properties.Settings.Default, "ServerPort"); + textBox_accesskey.DataBindings.Add("Text", Properties.Settings.Default, "AccessKey"); + textBox_template.DataBindings.Add("Text", Properties.Settings.Default, "TemplateFile"); + } + + protected override void SetVisibleCore(bool value) + { + if (StartMinimized) + { + StartMinimized = false; + base.SetVisibleCore(false); + return; + } + base.SetVisibleCore(value); + } + + private void Log(string data) => Invoke(() => + { + textBox_log.AppendText("[" + DateTime.Now.ToString("G") + "] " + data + Environment.NewLine); + }); + + private void ServerForm_Load(object sender, EventArgs e) + { + button_start.PerformClick(); + } + + private void ServerForm_VisibleChanged(object sender, EventArgs e) => notifyIcon1.Visible = !Visible; + + private void ServerForm_SizeChanged(object sender, EventArgs e) + { + if (WindowState == FormWindowState.Minimized) + { + Hide(); + } + } + + private void notifyIcon1_MouseClick(object sender, MouseEventArgs e) + { + Show(); + WindowState = FormWindowState.Normal; + BringToFront(); + } + + private void checkBox1_CheckedChanged(object sender, EventArgs e) + { + textBox_accesskey.PasswordChar = checkBox1.Checked ? '\0' : '*'; + } + + private void button_selectFile_Click(object sender, EventArgs e) + { + var dialog = new OpenFileDialog() + { + Title = "Select Template File", + Filter = "Template Files|*.lbx|All Files|*.*", + CheckFileExists = true, + }; + if (dialog.ShowDialog() == DialogResult.OK) + { + Properties.Settings.Default.TemplateFile = textBox_template.Text = dialog.FileName; + SaveSettings(); + } + } + + private void button_start_Click(object sender, EventArgs e) + { + try + { + var port = (ushort)numericUpDown_port.Value; + + Listener = new HttpListener(); + Listener.Prefixes.Add($"http://127.0.0.1:{port}/"); + + Listener.Start(); + BeginGetContext(); + + Log("Server started on port: " + port); + } + catch (Exception ex) + { + Log("Unable to start server: " + ex); + return; + } + numericUpDown_port.Enabled = button_start.Enabled = false; + button_stop.Enabled = true; + } + + private void button_stop_Click(object sender, EventArgs e) + { + Listener?.Stop(); + Listener = null; + Log("Server stopped"); + + numericUpDown_port.Enabled = button_start.Enabled = true; + button_stop.Enabled = false; + } + + private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) => Process.Start(new ProcessStartInfo + { + FileName = "https://github.com/xWTF/SnipeIT-bPAC", + UseShellExecute = true, + }); + + private void SaveSettings(object? sender = null, EventArgs? e = null) => Properties.Settings.Default.Save(); + + private void HandleRequest(HttpListenerContext ctx) + { + var req = ctx.Request; + if (req.Url?.AbsolutePath != "/print") + { + ctx.SendJson(new { code = 404 }); + return; + } + + if (req.HttpMethod == "OPTIONS") + { + ctx.SendJson(null); + return; + } + else if (req.HttpMethod != "POST") + { + ctx.SendJson(new { code = 403, msg = "bad method" }); + return; + } + + var auth = req.Headers["Authorization"]?.Split(" "); + if (auth == null || auth.Length != 2 || auth[0].ToLower() != "bearer" || auth[1] != Invoke(() => textBox_accesskey.Text)) + { + Log("Access denied: " + req.RemoteEndPoint.ToString()); + ctx.SendJson(new { code = 403, msg = "access denied" }); + return; + } + + using var reader = new StreamReader(req.InputStream, Encoding.UTF8); + var requests = JsonSerializer.Deserialize[]>(reader.ReadToEnd()); + if (requests == null) + { + ctx.SendJson(new { code = 400, msg = "Unable to deserialize the JSON" }); + return; + } + + try + { + if (!Document.Open(Invoke(() => textBox_template.Text))) + { + Log("Print error: Unable to open template"); + ctx.SendJson(new { code = 500, msg = "Unable to open template" }); + return; + } + + Document.StartPrint(requests.Length + " Labels", PrintOptionConstants.bpoDefault); + foreach (var r in requests) + { + foreach (var kv in r) + { + var obj = Document.GetObject(kv.Key); + if (obj != null) + { + obj.Text = kv.Value.ToString(); + } + } + Document.PrintOut(1, PrintOptionConstants.bpoDefault); + } + Document.EndPrint(); + Document.Close(); + + Log("Printed " + requests.Length + " labels from " + req.RemoteEndPoint.ToString()); + } + catch (Exception ex) + { + Log("Print error: " + ex); + ctx.SendJson(new { code = 500, msg = "Unknown error occured" }); + return; + } + ctx.SendJson(new { code = 200 }); + } + + private void BeginGetContext() => Listener?.BeginGetContext(new AsyncCallback(ListenerCallback), Listener); + + private void ListenerCallback(IAsyncResult result) + { + try + { + if (Listener == null) + { + return; + } + HandleRequest(Listener.EndGetContext(result)); + } + catch (ObjectDisposedException) + { + return; + } + catch (Exception ex) + { + Log("Unknown error:" + ex); + } + BeginGetContext(); + } + } +} diff --git a/SnipeIT-bPAC/ServerForm.resx b/SnipeIT-bPAC/ServerForm.resx new file mode 100644 index 0000000..50794d4 --- /dev/null +++ b/SnipeIT-bPAC/ServerForm.resx @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + \ No newline at end of file diff --git a/SnipeIT-bPAC/SnipeIT-bPAC.csproj b/SnipeIT-bPAC/SnipeIT-bPAC.csproj new file mode 100644 index 0000000..e16884b --- /dev/null +++ b/SnipeIT-bPAC/SnipeIT-bPAC.csproj @@ -0,0 +1,43 @@ + + + + WinExe + net6.0-windows + SnipeIT_bPAC + enable + true + enable + x64;x86 + xWTF + Convenient bPAC print daemon for Snipe-IT asset management software + Copyright (c) 2023 xWTF + + + + + tlbimp + 3 + 1 + 90359d74-b7d9-467f-b938-3883f4cab582 + 0 + false + False + + + + + + True + True + Settings.settings + + + + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + + \ No newline at end of file