commit a3a415d5c8ebe385989d1bd463efe445f42554fc
parent d4776dd8498cda8ddb31670fdcf471add6b8fd24
Author: Tomas Hlavaty <tom@logand.com>
Date:   Sun, 11 Aug 2013 16:31:05 +0200
cups-get-default and cups-get-printers implemented
- reading improved, group-reader introduced
- writing improved
Diffstat:
| M | ipp.lisp |  |  | 209 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------- | 
1 file changed, 166 insertions(+), 43 deletions(-)
diff --git a/ipp.lisp b/ipp.lisp
@@ -142,9 +142,15 @@
               for (k) in attributes
               collect (cons (string-downcase (symbol-name k)) k))))
     (defun attribute-keyword (string)
+      (cdr (assoc string x :test #'equal))
+      #+nil
       (or (cdr (assoc string x :test #'equal))
           (error "unknown IPP attribute ~s" string)))))
 
+#+nil
+(with-open-file (s "response2.dat" :element-type '(unsigned-byte 8))
+  (read-ipp (rw:byte-reader s) 314))
+
 ;;(attribute-tag :printer-uri)
 ;;(attribute-keyword "printer-uri")
 
@@ -154,9 +160,11 @@
 ;;(attribute-name :attributes-charset)
 
 (defun read-text (reader)
-  (octets-to-string (rw:next-octets reader (rw:next-u16 reader))))
+  (let ((n (rw:next-u16 reader)))
+    (when (plusp n)
+      (octets-to-string (rw:next-octets reader n)))))
 
-(defun read-value (reader tag)
+(defun read-value (reader tag) ;; TODO signed integers!
   (ecase tag
     (:no-value
      (assert (= 0 (rw:next-u16 reader))))
@@ -165,22 +173,32 @@
      (rw:next-u32 reader))
     (:boolean
      (assert (= 1 (rw:next-u16 reader)))
-     (not (zerop (rw:next-u32 reader))))
-    ;; :octetString
+     (not (zerop (rw:next-u8 reader))))
+    (:octetString
+     (let ((n (rw:next-u16 reader)))
+       (when (plusp n)
+         (let ((x (rw:next-octets reader n)))
+           (assert x)
+           x))))
     (:dateTime
      (assert (= 11 (rw:next-u16 reader)))
-     `(:dateTime ,(rw:next-u16 reader)
-                 ,(rw:next-u8 reader)
-                 ,(rw:next-u8 reader)
-                 ,(rw:next-u8 reader)
-                 ,(rw:next-u8 reader)
-                 ,(rw:next-u8 reader)
-                 ,(rw:next-u8 reader)
-                 ,(rw:next-u8 reader)
-                 ,(rw:next-u8 reader)
-                 ,(rw:next-u8 reader)))
-    ;; :resolution
-    ;; :rangeOfInteger
+     (list tag
+           (rw:next-u16 reader)
+           (rw:next-u8 reader)
+           (rw:next-u8 reader)
+           (rw:next-u8 reader)
+           (rw:next-u8 reader)
+           (rw:next-u8 reader)
+           (rw:next-u8 reader)
+           (rw:next-u8 reader)
+           (rw:next-u8 reader)
+           (rw:next-u8 reader)))
+    (:resolution
+     (assert (= 9 (rw:next-u16 reader)))
+     (list tag (rw:next-u32 reader) (rw:next-u32 reader) (rw:next-u8 reader)))
+    (:rangeOfInteger
+     (assert (= 8 (rw:next-u16 reader)))
+     (list tag (rw:next-u32 reader) (rw:next-u32 reader)))
     ((:textWithLanguage
       :nameWithLanguage
       :textWithoutLanguage
@@ -193,48 +211,99 @@
       :mimeMediaType)
      (read-text reader))))
 
-(defun read-attribute (reader)
-  (let ((tag (tag (rw:next-u8 reader))))
-    (if (member tag '(:operation-attributes-tag
-                      :job-attributes-tag
-                      :end-of-attributes-tag
-                      :printer-attributes-tag
-                      :unsupported-attributes-tag))
-        tag
-        (list (attribute-keyword (read-text reader))
-              (read-value reader tag)))))
-
-(defun read-groups (reader)
-  (let ((x (tag (rw:next-u8 reader))))
-    (loop
-       until (eq :end-of-attributes-tag x)
-       collect `(,x
-                 ,@(loop
-                      while (consp (setq x (read-attribute reader)))
-                      collect x)))))
+(defun group-reader (reader)
+  (let (done tag group-tag attributes attribute)
+    (lambda ()
+      (unless done
+        (block found
+          (flet ((yield ()
+                   ;;(print (list :@@@ done tag group-tag attributes attribute))
+                   (let ((z (when (and group-tag (or attributes attribute))
+                              (when attribute
+                                (push attribute attributes))
+                              (cons group-tag (nreverse attributes)))))
+                     (setq group-tag tag attributes nil attribute nil)
+                     (return-from found z))))
+            (loop
+               (setq tag (tag (rw:next-u8 reader)))
+               ;;(print (list :!!! tag))
+               (when (eq :end-of-attributes-tag tag)
+                 (setq done t)
+                 (yield))
+               (if (member tag '(:operation-attributes-tag
+                                 :job-attributes-tag
+                                 ;;:end-of-attributes-tag
+                                 :printer-attributes-tag
+                                 :unsupported-attributes-tag))
+                   (if (and group-tag (or attributes attribute))
+                       (yield)
+                       (setq group-tag tag))
+                   (let ((k (read-text reader)))
+                     (if k
+                         (progn
+                           (when attribute
+                             (push attribute attributes))
+                           (setq attribute (list tag
+                                                 (or (attribute-keyword k) k)
+                                                 (read-value reader tag))))
+                         (setq attribute (nconc
+                                          attribute
+                                          (list (read-value reader tag)))))
+                     #+nil(print (list :%%% attribute)))))))))))
 
 #+nil
 (with-open-file (s "response.dat" :element-type '(unsigned-byte 8))
   (read-ipp (rw:byte-reader s) 314))
 
+#+nil
+(with-open-file (s "response2.dat" :element-type '(unsigned-byte 8))
+  (read-ipp (rw:byte-reader s) 314))
+
 (defun write-text (writer x)
   (let ((y (string-to-octets x)))
     (rw:write-u16 writer (length y))
     (rw:write-octets writer y)))
 
-(defun write-value (writer tag x)
+(defun write-value (writer tag x) ;; TODO signed integers!
   (ecase tag
-    ;; :no-value
+    (:no-value
+     (rw:write-u16 writer 0))
     ((:integer :enum)
      (rw:write-u16 writer 4)
      (rw:write-u32 writer x))
     (:boolean
      (rw:write-u16 writer 1)
      (rw:write-u8 writer (if x 1 0)))
-    ;; :octetString
-    ;; :dateTime
-    ;; :resolution
-    ;; :rangeOfInteger
+    (:octetString
+     (rw:write-u16 writer (length x))
+     (rw:write-octets writer x))
+    (:dateTime
+     (rw:write-u16 writer 11)
+     (destructuring-bind (tag2 a b c d e f g h i j) x
+       (assert (eq tag tag2))
+       (rw:write-u16 writer a)
+       (rw:write-u8 writer b)
+       (rw:write-u8 writer c)
+       (rw:write-u8 writer d)
+       (rw:write-u8 writer e)
+       (rw:write-u8 writer f)
+       (rw:write-u8 writer g)
+       (rw:write-u8 writer h)
+       (rw:write-u8 writer i)
+       (rw:write-u8 writer j)))
+    (:resolution
+     (rw:write-u16 writer 9)
+     (destructuring-bind (tag2 a b c) x
+       (assert (eq tag tag2))
+       (rw:write-u32 writer a)
+       (rw:write-u32 writer b)
+       (rw:write-u8 writer c)))
+    (:rangeOfInteger
+     (rw:write-u16 writer 8)
+     (destructuring-bind (tag2 a b) x
+       (assert (eq tag tag2))
+       (rw:write-u32 writer a)
+       (rw:write-u32 writer b)))
     ((:textWithLanguage
       :nameWithLanguage
       :textWithoutLanguage
@@ -335,7 +404,7 @@
     :request-id , (let ((x (rw:next-u32 reader)))
                     (assert (= x request-id))
                     x)
-    :groups ,(read-groups reader)))
+    :groups ,(rw:till (group-reader reader))))
 
 #+nil
 (with-open-file (s "response.dat" :element-type '(unsigned-byte 8))
@@ -610,7 +679,47 @@
 ;; TODO enable-printer
 ;; TODO disable-printer
 ;; TODO cups-get-default
-;; TODO cups-get-printers
+
+(defun cups-get-default (ipp-client
+                         printer-uri
+                         request-file
+                         response-file
+                         request-id
+                         &key
+                           (attributes-charset "utf-8")
+                           (attributes-natural-language "en"))
+  (ipp ipp-client
+       printer-uri
+       request-file
+       response-file
+       nil
+       request-id
+       :cups-get-default
+       `((,(tag :operation-attributes-tag)
+           :attributes-charset ,attributes-charset
+           :attributes-natural-language ,attributes-natural-language
+           :printer-uri ,printer-uri))))
+
+(defun cups-get-printers (ipp-client
+                          printer-uri
+                          request-file
+                          response-file
+                          request-id
+                          &key
+                            (attributes-charset "utf-8")
+                            (attributes-natural-language "en"))
+  (ipp ipp-client
+       printer-uri
+       request-file
+       response-file
+       nil
+       request-id
+       :cups-get-printers
+       `((,(tag :operation-attributes-tag)
+           :attributes-charset ,attributes-charset
+           :attributes-natural-language ,attributes-natural-language
+           :printer-uri ,printer-uri))))
+
 ;; TODO cups-add-modify-printer
 ;; TODO cups-delete-printer
 ;; TODO cups-get-classes
@@ -814,6 +923,20 @@
               :requested-attributes '(:job-id))
 
 #+nil
+(ipp::cups-get-default 'ipp-client
+                       "http://localhost:631/printers/Virtual_PDF_Printer"
+                       "request2.dat"
+                       "response2.dat"
+                       314)
+
+#+nil
+(ipp::cups-get-printers 'ipp-client
+                        "http://localhost:631/printers/Virtual_PDF_Printer"
+                        "request2.dat"
+                        "response2.dat"
+                        314)
+
+#+nil
 (ipp:list-printers 'ipp-client
                    "http://localhost:631/printers/"
                    "printers.html")