diff --git a/ipp-usb.8 b/ipp-usb.8
index 89dfc12..015b91d 100644
--- a/ipp-usb.8
+++ b/ipp-usb.8
@@ -1,6 +1,6 @@
.\" generated with Ronn-NG/v0.10.1
.\" http://github.com/apjanke/ronn-ng/tree/0.10.1
-.TH "IPP\-USB" "8" "November 2024" "" "ipp-usb.8"
+.TH "IPP\-USB" "8" "December 2024" "" "ipp-usb.8"
.SH "NAME"
\fBipp\-usb\fR \- Daemon for IPP over USB printer support
.SH "DESCRIPTION"
@@ -278,33 +278,35 @@ Some devices send buggy (malformed) IPP responses that violate IPP specification
.IP "\(bu" 4
\fBdisable\-fax = true | false\fR
.br
-If \fBtrue\fR, the matching device's fax capability is ignored
+If \fBtrue\fR, the matching device's fax capability is ignored\.
.IP "\(bu" 4
\fBhttp\-XXX = YYY\fR
.br
-Set XXX header of the HTTP requests forwarded to device to YYY\. If YYY is empty string, XXX header is removed
+Set XXX header of the HTTP requests forwarded to device to YYY\. If YYY is empty string, XXX header is removed\.
.IP "\(bu" 4
\fBignore\-ipp\-status = true | false\fR
.br
If \fBtrue\fR, IPP status of IPP requests sent by the \fBipp\-usb\fR by itself will be ignored\. This quirk is useful, when device correctly handles IPP request but returned status is not reliable\. Affects only \fBipp\-usb\fR initialization\.
.IP "\(bu" 4
-\fBinit\-delay = NNN\fR
+\fBinit\-delay = DELAY\fR
.br
-Delay, in milliseconds, between device is opened and, optionally, reset, and the first request is sent to device
+Delay, between device is opened and, optionally, reset, and the first request is sent to device\.
.IP "\(bu" 4
\fBinit\-reset = none | soft | hard\fR
.br
How to reset device during initialization\. Default is \fBnone\fR
.IP "\(bu" 4
-\fBrequest\-delay\fR = NNN
+\fBrequest\-delay\fR = DELAY
.br
-Delay, in milliseconds, between subsequent requests
+Delay, between subsequent requests\.
.IP "\(bu" 4
\fBusb\-max\-interfaces = N\fR
.br
-Don't use more that N USB interfaces, even if more is available
+Don't use more that N USB interfaces, even if more is available\.
.IP "" 0
.P
+The DELAY parameter can be specified either as an unsigned integer (in milliseconds) or as a sequence of decimal numbers with an optional fraction and a unit suffix, such as "300ms," "0\.5s," or "2m30s\." Valid time units are "ns," "us" (or "µs"), "ms," "s," "m," and "h\."
+.P
If you found out about your device that it needs a quirk to work properly or it does not work with \fBipp\-usb\fR at all, although it provides IPP\-over\-USB interface, please report the issue at https://github\.com/OpenPrinting/ipp\-usb\. It will let us to update our collection of quirks, so helping other owners of such a device\.
.SH "FILES"
.IP "\(bu" 4
diff --git a/ipp-usb.8.md b/ipp-usb.8.md
index 00b1c67..a05db18 100644
--- a/ipp-usb.8.md
+++ b/ipp-usb.8.md
@@ -359,11 +359,11 @@ The following parameters are defined:
as well) or `sanitize` them (fix IPP specs violations).
* `disable-fax = true | false`
- If `true`, the matching device's fax capability is ignored
+ If `true`, the matching device's fax capability is ignored.
* `http-XXX = YYY`
Set XXX header of the HTTP requests forwarded to device to YYY.
- If YYY is empty string, XXX header is removed
+ If YYY is empty string, XXX header is removed.
* `ignore-ipp-status = true | false`
If `true`, IPP status of IPP requests sent by the `ipp-usb` by
@@ -371,18 +371,23 @@ The following parameters are defined:
handles IPP request but returned status is not reliable. Affects
only `ipp-usb` initialization.
- * `init-delay = NNN`
- Delay, in milliseconds, between device is opened and, optionally,
- reset, and the first request is sent to device
+ * `init-delay = DELAY `
+ Delay, between device is opened and, optionally, reset, and the
+ first request is sent to device.
* `init-reset = none | soft | hard`
How to reset device during initialization. Default is `none`
- * `request-delay` = NNN
- Delay, in milliseconds, between subsequent requests
+ * `request-delay` = DELAY
+ Delay, between subsequent requests.
* `usb-max-interfaces = N`
- Don't use more that N USB interfaces, even if more is available
+ Don't use more that N USB interfaces, even if more is available.
+
+The DELAY parameter can be specified either as an unsigned integer (in
+milliseconds) or as a sequence of decimal numbers with an optional
+fraction and a unit suffix, such as "300ms," "0.5s," or "2m30s." Valid
+time units are "ns," "us" (or "µs"), "ms," "s," "m," and "h."
If you found out about your device that it needs a quirk to work properly or it
does not work with `ipp-usb` at all, although it provides IPP-over-USB
diff --git a/quirks.go b/quirks.go
index cc6953c..d10fbe8 100644
--- a/quirks.go
+++ b/quirks.go
@@ -118,13 +118,30 @@ func (q *Quirk) parseUint() error {
// parseDuration parses [Quirk.RawValue] as time.Duration.
func (q *Quirk) parseDuration() error {
+ // Try to parse as uint. If OK, interpret it
+ // as a millisecond time.
ms, err := strconv.ParseUint(q.RawValue, 10, 32)
- if err != nil {
+ if err == nil {
+ q.Parsed = time.Millisecond * time.Duration(ms)
+ return nil
+ }
+
+ // Try to use time.ParseDuration.
+ //
+ if strings.HasPrefix(q.RawValue, "+") ||
+ strings.HasPrefix(q.RawValue, "-") {
+ // Note, time.ParseDuration allows signed duration,
+ // but we don't.
return fmt.Errorf("%q: invalid duration", q.RawValue)
}
- q.Parsed = time.Millisecond * time.Duration(ms)
- return nil
+ v, err := time.ParseDuration(q.RawValue)
+ if err == nil && v >= 0 {
+ q.Parsed = v
+ return nil
+ }
+
+ return fmt.Errorf("%q: invalid duration", q.RawValue)
}
// parseQuirkBuggyIppRsp parses [Quirk.RawValue] as QuirkBuggyIppRsp.
diff --git a/quirks_test.go b/quirks_test.go
index f5734a6..a53c9c9 100644
--- a/quirks_test.go
+++ b/quirks_test.go
@@ -239,12 +239,44 @@ func TestQuirksParsers(t *testing.T) {
value: time.Duration(0),
},
+ {
+ parser: (*Quirk).parseDuration,
+ input: "0s",
+ value: time.Duration(0),
+ },
+
{
parser: (*Quirk).parseDuration,
input: "12345",
value: 12345 * time.Millisecond,
},
+ {
+ parser: (*Quirk).parseDuration,
+ input: "1h2m3s",
+ value: time.Hour +
+ 2*time.Minute +
+ 3*time.Second,
+ },
+
+ {
+ parser: (*Quirk).parseDuration,
+ input: "0.5s",
+ value: time.Second / 2,
+ },
+
+ {
+ parser: (*Quirk).parseDuration,
+ input: "+0s",
+ err: `"+0s": invalid duration`,
+ },
+
+ {
+ parser: (*Quirk).parseDuration,
+ input: "-0s",
+ err: `"-0s": invalid duration`,
+ },
+
{
parser: (*Quirk).parseDuration,
input: "hello",