From 70ca3fef77ee8bdc6e3ac28589a6fa08c024cc69 Mon Sep 17 00:00:00 2001 From: AlexanderCurl Date: Sat, 18 Apr 2026 17:46:06 +0100 Subject: Replaced file structures for themes in the correct format --- .../DankMaterialShell/core/pkg/ipp/response.go | 383 +++++++++++++++++++++ 1 file changed, 383 insertions(+) create mode 100644 raveos-hyprland-theme/theme-data/DankMaterialShell/core/pkg/ipp/response.go (limited to 'raveos-hyprland-theme/theme-data/DankMaterialShell/core/pkg/ipp/response.go') 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) + } +} -- cgit v1.3