Skip to content

Commit

Permalink
Merge pull request #8 from KittyDotNet/master
Browse files Browse the repository at this point in the history
Added support for listing cups printers
  • Loading branch information
Zelenov authored May 13, 2022
2 parents bba8bda + d1241ee commit 70a359e
Show file tree
Hide file tree
Showing 9 changed files with 212 additions and 3 deletions.
117 changes: 117 additions & 0 deletions SharpIpp/Model/CUPSGetPrintersRequest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
using System;
using System.Collections.Generic;

namespace SharpIpp.Model
{
/// <summary>
/// Request to get a list of printers from a CUPS IPP server
/// <seealso href="http://www.cups.org/doc/spec-ipp.html#CUPS_GET_PRINTERS"/>
/// </summary>
public class CUPSGetPrintersRequest : IIppPrinterRequest
{
///<summary>
/// The client OPTIONALLY supplies this attribute to select the
/// first printer that is returned.
/// </summary>
public string? FirstPrinterName { get; set; }

///<summary>
/// The client OPTIONALLY supplies this attribute. The Printer
/// object MUST support this attribute. It is an integer value that
/// determines the maximum number of jobs that a client will
/// receive from the Printer even if "which-jobs" or "my-jobs"
/// constrain which jobs are returned. The limit is a "stateless
/// limit" in that if the value supplied by the client is 'N', then
/// only the first 'N' jobs are returned in the Get-Jobs Response.
/// There is no mechanism to allow for the next 'M' jobs after the
/// first 'N' jobs. If the client does not supply this attribute,
/// the Printer object responds with all applicable jobs.
///</summary>
public int? Limit { get; set; }

///<summary>
///The client OPTIONALLY supplies this attribute to select which printer is returned.
///</summary>
public int? PrinterID { get; set; }

///<summary>
///The client OPTIONALLY supplies this attribute to select which printers are returned.
///</summary>
public string? PrinterLocation { get; set; }

///<summary>
///The client OPTIONALLY supplies a printer type enumeration to select which printers are returned.
///</summary>
public PrinterType? PrinterType { get; set; }

///<summary>
///The client OPTIONALLY supplies a printer type mask enumeration to select which bits are used in the "printer-type" attribute.
///</summary>
public PrinterType? PrinterTypeMask { get; set; }

/// <summary>
/// The client OPTIONALLY supplies this attribute. The Printer
/// object MUST support this attribute. It is a set of Job
/// attribute names and/or attribute groups names in whose values
/// the requester is interested. This set of attributes is
/// returned for each Job object that is returned. The allowed
/// attribute group names are the same as those defined in the
/// Get-Job-Attributes operation in section 3.3.4. If the client
/// does not supply this attribute, the Printer MUST respond as if
/// the client had supplied this attribute with two values: 'job-
/// uri' and 'job-id'.
/// </summary>
public string[]? RequestedAttributes { get; set; }

public IppVersion Version { get; set; } = IppVersion.CUPS10;
public int RequestId { get; set; } = 1;
public Uri PrinterUri { get; set; } = null!;

/// <summary>
/// The "requesting-user-name" (name(MAX)) attribute SHOULD be
/// supplied by the client
/// </summary>
public string? RequestingUserName { get; set; }

public IEnumerable<IppAttribute>? AdditionalOperationAttributes { get; set; }
public IEnumerable<IppAttribute>? AdditionalJobAttributes { get; set; }
}

///<summary>
///<para>Type flags for requesting specific types of printers.</para>
///<para><see href="https://www.cups.org/doc/spec-ipp.html#printer-type">See here</see> for docs</para>
///</summary>
///
[Flags]
public enum PrinterType
{
PrinterClass = 0x1,
RemoteDestination = 0x2,
PrintsBlack = 0x4,
PrintsColor = 0x8,
TwoSidedPrinting = 0x10,
Stapler = 0x20,
FastCopies = 0x40,
FastCopyCollation = 0x80,
HolePunch = 0x100,
Cover = 0x200,
Binding = 0x400,
Sorting = 0x800,
MediaToUSLegalA4 = 0x1000,
MediaLegalToISOcA2 = 0x2000,
MediaOverA2= 0x4000,
MediaUserDefined = 0x8000,
ImplicitClass = 0x10000,
DefaultPrinter = 20000,
FacsimileDevice = 0x40000,
RejectingJobs = 0x80000,
DeleteQueue = 0x100000,
QueueNotShared = 0x200000,
RequiresAuthentication = 0x400000,
SupportsCUPSCommandFiles = 0x800000,
AutomaticallyDescovered = 0x1000000,
ScannerNoPrint = 0x2000000,
ScannerPrints = 0x4000000,
PrinterIs3D = 80000000
}
}
13 changes: 13 additions & 0 deletions SharpIpp/Model/CUPSGetPrintersResponse.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using System.Collections.Generic;

namespace SharpIpp.Model
{
public class CUPSGetPrintersResponse : IIppResponseMessage
{
public JobAttributes[] Jobs { get; set; } = null!;
public IppVersion Version { get; set; } = IppVersion.CUPS10;
public IppStatusCode StatusCode { get; set; }
public int RequestId { get; set; } = 1;
public List<IppSection> Sections { get; } = new List<IppSection>();
}
}
3 changes: 2 additions & 1 deletion SharpIpp/Model/IppOperation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ public enum IppOperation : short
ReservedForAFutureOperation = 0x000F,
PausePrinter = 0x0010,
ResumePrinter = 0x0011,
PurgeJobs = 0x0012
PurgeJobs = 0x0012,
GetCUPSPrinters = 0x4002
}
}
3 changes: 2 additions & 1 deletion SharpIpp/Model/IppVersion.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
/// </summary>
public enum IppVersion : short
{
V11 = 0x0101
V11 = 0x0101,
CUPS10 = 0x0201
}
}
2 changes: 2 additions & 0 deletions SharpIpp/Protocol/IIppProtocol.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ internal interface IIppProtocol
GetJobAttributesResponse ConstructGetJobAttributesResponse(IIppResponseMessage ippResponse);
IppRequestMessage Construct(GetJobsRequest request);
GetJobsResponse ConstructGetJobsResponse(IIppResponseMessage ippResponse);
IppRequestMessage Construct(CUPSGetPrintersRequest request);
CUPSGetPrintersResponse ConstructGetCUPSPrintersResponse(IIppResponseMessage ippResponse);
IppRequestMessage Construct(GetPrinterAttributesRequest request);
GetPrinterAttributesResponse ConstructGetPrinterAttributesResponse(IIppResponseMessage ippResponse);
IppRequestMessage Construct(HoldJobRequest request);
Expand Down
60 changes: 60 additions & 0 deletions SharpIpp/Protocol/IppProtocol.GetCUPSPrinters.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
using System.Collections.Generic;
using System.Linq;
using SharpIpp.Model;
using SharpIpp.Protocol.Extensions;

namespace SharpIpp.Protocol
{
internal partial class IppProtocol
{
/// <summary>
/// CUPS-get-printers Request
/// http://www.cups.org/doc/spec-ipp.html#CUPS_GET_PRINTERS
/// </summary>
/// <param name="request"></param>
public IppRequestMessage Construct(CUPSGetPrintersRequest request) => ConstructIppRequest(request);

/// <summary>
/// CUPS-get-printers Response
/// http://www.cups.org/doc/spec-ipp.html#CUPS_GET_PRINTERS
/// </summary>
public CUPSGetPrintersResponse ConstructGetCUPSPrintersResponse(IIppResponseMessage ippResponse) =>
Construct<CUPSGetPrintersResponse>(ippResponse);

private static void ConfigureGetCUPSPrintersResponse(SimpleMapper mapper)
{
mapper.CreateMap<CUPSGetPrintersRequest, IppRequestMessage>((src, map) =>
{
var dst = new IppRequestMessage {IppOperation = IppOperation.GetCUPSPrinters};
mapper.Map<IIppPrinterRequest, IppRequestMessage>(src, dst);
var operation = dst.OperationAttributes;
if (src.Limit != null)
operation.Add(new IppAttribute(Tag.Integer, "requesting-user-name", src.Limit.Value));
if (src.FirstPrinterName != null)
operation.Add(new IppAttribute(Tag.Keyword, "first-printer-name", mapper.Map<string>(src.FirstPrinterName)));
if (src.PrinterID != null)
operation.Add(new IppAttribute(Tag.Integer, "printer-id", mapper.Map<string>(src.PrinterID)));
if (src.PrinterLocation != null)
operation.Add(new IppAttribute(Tag.Keyword, "printer-location", mapper.Map<string>(src.PrinterLocation)));
if (src.RequestedAttributes != null)
operation.AddRange(src.RequestedAttributes.Select(requestedAttribute =>
new IppAttribute(Tag.Keyword, "requested-attributes", requestedAttribute)));

dst.OperationAttributes.Populate(src.AdditionalOperationAttributes);
dst.JobAttributes.Populate(src.AdditionalJobAttributes);
return dst;
});
mapper.CreateMap<IppResponseMessage, CUPSGetPrintersResponse>((src, map) =>
{
var dst = new CUPSGetPrintersResponse { Jobs = map.Map<List<IppSection>, JobAttributes[]>(src.Sections)};
map.Map<IppResponseMessage, IIppResponseMessage>(src, dst);
return dst;
});
//https://tools.ietf.org/html/rfc2911#section-4.4
//mapper.CreateMap<List<IppSection>, JobAttributes[]>((src, map) =>
// src.Where(x => x.Tag == SectionTag.JobAttributesTag)
// .Select(x => map.Map<JobAttributes>(x.AllAttributes()))
// .ToArray());
}
}
}
2 changes: 2 additions & 0 deletions SharpIpp/Protocol/IppProtocol.Mapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ static IppProtocol()
Mapper.CreateIppMap<int, PrinterState>((src, map) => (PrinterState) src);
Mapper.CreateIppMap<int, PrintQuality>((src, map) => (PrintQuality) src);
Mapper.CreateIppMap<int, ResolutionUnit>((src, map) => (ResolutionUnit) src);
Mapper.CreateIppMap<int, PrinterType>((src, map) => (PrinterType)src);

//All name parameters can come as StringWithLanguage or string
//Mappers for string\language mapping
Expand Down Expand Up @@ -55,6 +56,7 @@ static IppProtocol()
ConfigureGetPrinterAttributesResponse(Mapper);
ConfigureGetJobAttributesResponse(Mapper);
ConfigureGetJobsResponse(Mapper);
ConfigureGetCUPSPrintersResponse(Mapper);
ConfigurePrintUriRequest(Mapper);
ConfigureCreateJobRequest(Mapper);
ConfigureValidateJobRequest(Mapper);
Expand Down
3 changes: 2 additions & 1 deletion SharpIpp/Protocol/IppProtocol.cs
Original file line number Diff line number Diff line change
Expand Up @@ -288,5 +288,6 @@ public void Write(IppRequestMessage requestMessage, BinaryWriter writer)
//end-of-attributes-tag https://tools.ietf.org/html/rfc8010#section-3.5.1
writer.Write((byte) SectionTag.EndOfAttributesTag);
}

}
}
}
12 changes: 12 additions & 0 deletions SharpIpp/SharpIppClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,18 @@ public async Task<GetJobsResponse> GetJobsAsync(GetJobsRequest request)
ippResponse => _ippProtocol.ConstructGetJobsResponse(ippResponse));
}

/// <summary>
/// CUPS Get-Printers Operation
/// http://www.cups.org/doc/spec-ipp.html
/// </summary>
/// <param name="request">The CUPSGetPrintersRequest object</param>
/// <returns></returns>
public async Task<CUPSGetPrintersResponse> GetCUPSPrintersAsync(CUPSGetPrintersRequest request)
{
return await SendAsync(request.PrinterUri, () => _ippProtocol.Construct(request),
ippResponse => _ippProtocol.ConstructGetCUPSPrintersResponse(ippResponse));
}

/// <summary>
/// Custom Operation, not defined in the standard
/// </summary>
Expand Down

0 comments on commit 70a359e

Please sign in to comment.