summaryrefslogtreecommitdiff
path: root/raveos-hyprland-theme/theme-data/DankMaterialShell/core/pkg/ipp/response.go
diff options
context:
space:
mode:
authorAlexanderCurl <alexc@alexc.hu>2026-04-18 17:46:06 +0100
committerAlexanderCurl <alexc@alexc.hu>2026-04-18 17:46:06 +0100
commit70ca3fef77ee8bdc6e3ac28589a6fa08c024cc69 (patch)
treeab1123d4067c1b086dd6faa7ee4ea643236b565a /raveos-hyprland-theme/theme-data/DankMaterialShell/core/pkg/ipp/response.go
parent5d94c0a7d44a2255b81815a52a7056a94a39842d (diff)
downloadRaveOS-PKGBUILD-70ca3fef77ee8bdc6e3ac28589a6fa08c024cc69.tar.gz
RaveOS-PKGBUILD-70ca3fef77ee8bdc6e3ac28589a6fa08c024cc69.zip
Replaced file structures for themes in the correct format
Diffstat (limited to 'raveos-hyprland-theme/theme-data/DankMaterialShell/core/pkg/ipp/response.go')
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/core/pkg/ipp/response.go383
1 files changed, 383 insertions, 0 deletions
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/pkg/ipp/response.go b/raveos-hyprland-theme/theme-data/DankMaterialShell/core/pkg/ipp/response.go
new file mode 100644
index 0000000..e7cbd75
--- /dev/null
+++ b/raveos-hyprland-theme/theme-data/DankMaterialShell/core/pkg/ipp/response.go
@@ -0,0 +1,383 @@
+package ipp
+
+import (
+ "bytes"
+ "encoding/binary"
+ "io"
+)
+
+// Attributes is a wrapper for a set of attributes
+type Attributes map[string][]Attribute
+
+// Response defines a ipp response
+type Response struct {
+ ProtocolVersionMajor int8
+ ProtocolVersionMinor int8
+
+ StatusCode int16
+ RequestId int32
+
+ OperationAttributes Attributes
+ PrinterAttributes []Attributes
+ JobAttributes []Attributes
+ SubscriptionAttributes []Attributes // Added for subscription responses
+}
+
+// CheckForErrors checks the status code and returns a error if it is not zero. it also returns the status message if provided by the server
+func (r *Response) CheckForErrors() error {
+ if r.StatusCode != StatusOk {
+ err := IPPError{
+ Status: r.StatusCode,
+ Message: "no status message returned",
+ }
+
+ if len(r.OperationAttributes["status-message"]) > 0 {
+ err.Message = r.OperationAttributes["status-message"][0].Value.(string)
+ }
+
+ return err
+ }
+
+ return nil
+}
+
+// NewResponse creates a new ipp response
+func NewResponse(statusCode int16, reqID int32) *Response {
+ return &Response{
+ ProtocolVersionMajor: ProtocolVersionMajor,
+ ProtocolVersionMinor: ProtocolVersionMinor,
+ StatusCode: statusCode,
+ RequestId: reqID,
+ OperationAttributes: make(Attributes),
+ PrinterAttributes: make([]Attributes, 0),
+ JobAttributes: make([]Attributes, 0),
+ }
+}
+
+// Encode encodes the response to a byte slice
+func (r *Response) Encode() ([]byte, error) {
+ buf := new(bytes.Buffer)
+ enc := NewAttributeEncoder(buf)
+
+ if err := binary.Write(buf, binary.BigEndian, r.ProtocolVersionMajor); err != nil {
+ return nil, err
+ }
+
+ if err := binary.Write(buf, binary.BigEndian, r.ProtocolVersionMinor); err != nil {
+ return nil, err
+ }
+
+ if err := binary.Write(buf, binary.BigEndian, r.StatusCode); err != nil {
+ return nil, err
+ }
+
+ if err := binary.Write(buf, binary.BigEndian, r.RequestId); err != nil {
+ return nil, err
+ }
+
+ if err := binary.Write(buf, binary.BigEndian, TagOperation); err != nil {
+ return nil, err
+ }
+
+ if r.OperationAttributes == nil {
+ r.OperationAttributes = make(Attributes, 0)
+ }
+
+ if _, found := r.OperationAttributes[AttributeCharset]; !found {
+ r.OperationAttributes[AttributeCharset] = []Attribute{
+ {
+ Value: Charset,
+ },
+ }
+ }
+
+ if _, found := r.OperationAttributes[AttributeNaturalLanguage]; !found {
+ r.OperationAttributes[AttributeNaturalLanguage] = []Attribute{
+ {
+ Value: CharsetLanguage,
+ },
+ }
+ }
+
+ if err := r.encodeOperationAttributes(enc); err != nil {
+ return nil, err
+ }
+
+ if len(r.PrinterAttributes) > 0 {
+ for _, printerAttr := range r.PrinterAttributes {
+ if err := binary.Write(buf, binary.BigEndian, TagPrinter); err != nil {
+ return nil, err
+ }
+
+ for name, attr := range printerAttr {
+ if len(attr) == 0 {
+ continue
+ }
+
+ values := make([]any, len(attr))
+ for i, v := range attr {
+ values[i] = v.Value
+ }
+
+ if len(values) == 1 {
+ if err := enc.Encode(name, values[0]); err != nil {
+ return nil, err
+ }
+ } else {
+ if err := enc.Encode(name, values); err != nil {
+ return nil, err
+ }
+ }
+ }
+ }
+ }
+
+ if len(r.JobAttributes) > 0 {
+ for _, jobAttr := range r.JobAttributes {
+ if err := binary.Write(buf, binary.BigEndian, TagJob); err != nil {
+ return nil, err
+ }
+
+ for name, attr := range jobAttr {
+ if len(attr) == 0 {
+ continue
+ }
+
+ values := make([]any, len(attr))
+ for i, v := range attr {
+ values[i] = v.Value
+ }
+
+ if len(values) == 1 {
+ if err := enc.Encode(name, values[0]); err != nil {
+ return nil, err
+ }
+ } else {
+ if err := enc.Encode(name, values); err != nil {
+ return nil, err
+ }
+ }
+ }
+ }
+ }
+
+ if err := binary.Write(buf, binary.BigEndian, TagEnd); err != nil {
+ return nil, err
+ }
+
+ return buf.Bytes(), nil
+}
+
+func (r *Response) encodeOperationAttributes(enc *AttributeEncoder) error {
+ ordered := []string{
+ AttributeCharset,
+ AttributeNaturalLanguage,
+ AttributePrinterURI,
+ AttributeJobID,
+ }
+
+ for _, name := range ordered {
+ if attr, ok := r.OperationAttributes[name]; ok {
+ delete(r.OperationAttributes, name)
+ if err := encodeOperationAttribute(enc, name, attr); err != nil {
+ return err
+ }
+ }
+ }
+
+ for name, attr := range r.OperationAttributes {
+ if err := encodeOperationAttribute(enc, name, attr); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+func encodeOperationAttribute(enc *AttributeEncoder, name string, attr []Attribute) error {
+ if len(attr) == 0 {
+ return nil
+ }
+
+ values := make([]any, len(attr))
+ for i, v := range attr {
+ values[i] = v.Value
+ }
+
+ if len(values) == 1 {
+ return enc.Encode(name, values[0])
+ }
+
+ return enc.Encode(name, values)
+}
+
+// ResponseDecoder reads and decodes a response from a stream
+type ResponseDecoder struct {
+ reader io.Reader
+}
+
+// NewResponseDecoder returns a new decoder that reads from r
+func NewResponseDecoder(r io.Reader) *ResponseDecoder {
+ return &ResponseDecoder{
+ reader: r,
+ }
+}
+
+// Decode decodes a ipp response into a response struct. additional data will be written to an io.Writer if data is not nil
+func (d *ResponseDecoder) Decode(data io.Writer) (*Response, error) {
+ /*
+ 1 byte: Protocol Major Version - b
+ 1 byte: Protocol Minor Version - b
+ 2 byte: Status ID - h
+ 4 byte: Request ID - i
+ 1 byte: Operation Attribute Byte (\0x01)
+ N times: Attributes
+ 1 byte: Attribute End Byte (\0x03)
+ */
+
+ resp := new(Response)
+
+ // wrap the reader so we have more functionality
+ // reader := bufio.NewReader(d.reader)
+
+ if err := binary.Read(d.reader, binary.BigEndian, &resp.ProtocolVersionMajor); err != nil {
+ return nil, err
+ }
+
+ if err := binary.Read(d.reader, binary.BigEndian, &resp.ProtocolVersionMinor); err != nil {
+ return nil, err
+ }
+
+ if err := binary.Read(d.reader, binary.BigEndian, &resp.StatusCode); err != nil {
+ return nil, err
+ }
+
+ if err := binary.Read(d.reader, binary.BigEndian, &resp.RequestId); err != nil {
+ return nil, err
+ }
+
+ startByteSlice := make([]byte, 1)
+
+ tag := TagCupsInvalid
+ previousAttributeName := ""
+ tempAttributes := make(Attributes)
+ tagSet := false
+
+ attribDecoder := NewAttributeDecoder(d.reader)
+
+ // decode attribute buffer
+ for {
+ if _, err := d.reader.Read(startByteSlice); err != nil {
+ // when we read from a stream, we may get an EOF if we want to read the end tag
+ // all data should be read and we can ignore the error
+ if err == io.EOF {
+ break
+ }
+ return nil, err
+ }
+
+ startByte := int8(startByteSlice[0])
+
+ // check if attributes are completed
+ if startByte == TagEnd {
+ break
+ }
+
+ if startByte == TagOperation {
+ if len(tempAttributes) > 0 && tag != TagCupsInvalid {
+ appendAttributeToResponse(resp, tag, tempAttributes)
+ tempAttributes = make(Attributes)
+ }
+
+ tag = TagOperation
+ tagSet = true
+ }
+
+ if startByte == TagJob {
+ if len(tempAttributes) > 0 && tag != TagCupsInvalid {
+ appendAttributeToResponse(resp, tag, tempAttributes)
+ tempAttributes = make(Attributes)
+ }
+
+ tag = TagJob
+ tagSet = true
+ }
+
+ if startByte == TagPrinter {
+ if len(tempAttributes) > 0 && tag != TagCupsInvalid {
+ appendAttributeToResponse(resp, tag, tempAttributes)
+ tempAttributes = make(Attributes)
+ }
+
+ tag = TagPrinter
+ tagSet = true
+ }
+
+ if startByte == TagSubscription {
+ if len(tempAttributes) > 0 && tag != TagCupsInvalid {
+ appendAttributeToResponse(resp, tag, tempAttributes)
+ tempAttributes = make(Attributes)
+ }
+
+ tag = TagSubscription
+ tagSet = true
+ }
+
+ if startByte == TagEventNotification {
+ if len(tempAttributes) > 0 && tag != TagCupsInvalid {
+ appendAttributeToResponse(resp, tag, tempAttributes)
+ tempAttributes = make(Attributes)
+ }
+
+ tag = TagEventNotification
+ tagSet = true
+ }
+
+ if tagSet {
+ if _, err := d.reader.Read(startByteSlice); err != nil {
+ return nil, err
+ }
+ startByte = int8(startByteSlice[0])
+ }
+
+ attrib, err := attribDecoder.Decode(startByte)
+ if err != nil {
+ return nil, err
+ }
+
+ if attrib.Name != "" {
+ tempAttributes[attrib.Name] = append(tempAttributes[attrib.Name], *attrib)
+ previousAttributeName = attrib.Name
+ } else {
+ tempAttributes[previousAttributeName] = append(tempAttributes[previousAttributeName], *attrib)
+ }
+
+ tagSet = false
+ }
+
+ if len(tempAttributes) > 0 && tag != TagCupsInvalid {
+ appendAttributeToResponse(resp, tag, tempAttributes)
+ }
+
+ if data != nil {
+ if _, err := io.Copy(data, d.reader); err != nil {
+ return nil, err
+ }
+ }
+
+ return resp, nil
+}
+
+func appendAttributeToResponse(resp *Response, tag int8, attr map[string][]Attribute) {
+ switch tag {
+ case TagOperation:
+ resp.OperationAttributes = attr
+ case TagPrinter:
+ resp.PrinterAttributes = append(resp.PrinterAttributes, attr)
+ case TagJob:
+ resp.JobAttributes = append(resp.JobAttributes, attr)
+ case TagSubscription, TagEventNotification:
+ // Both subscription and event notification attributes go to SubscriptionAttributes
+ resp.SubscriptionAttributes = append(resp.SubscriptionAttributes, attr)
+ }
+}