// GetJobState gets the current state of the job indicated by jobID. func (c *CUPS) GetJobState(jobID uint32) (cdd.PrintJobStateDiff, error) { ja := C.newArrayOfStrings(C.int(len(jobAttributes))) defer C.freeStringArrayAndStrings(ja, C.int(len(jobAttributes))) for i, attribute := range jobAttributes { C.setStringArrayValue(ja, C.int(i), C.CString(attribute)) } response, err := c.cc.getJobAttributes(C.int(jobID), ja) if err != nil { return cdd.PrintJobStateDiff{}, err } // cupsDoRequest() returned ipp_t pointer needs explicit free. defer C.ippDelete(response) s := C.ippFindAttribute(response, C.JOB_STATE, C.IPP_TAG_ENUM) state := int32(C.ippGetInteger(s, C.int(0))) p := C.ippFindAttribute(response, C.JOB_MEDIA_SHEETS_COMPLETED, C.IPP_TAG_INTEGER) var pages int32 if p != nil { pages = int32(C.ippGetInteger(p, C.int(0))) } return convertJobState(state, pages), nil }
// attributesToTags converts a slice of C.ipp_attribute_t to a // string:string "tag" map. Outside of this package, "printer attributes" are // known as "tags". func attributesToTags(attributes []*C.ipp_attribute_t) map[string][]string { tags := make(map[string][]string) for _, a := range attributes { key := C.GoString(C.ippGetName(a)) count := int(C.ippGetCount(a)) values := make([]string, count) switch C.ippGetValueTag(a) { case C.IPP_TAG_NOVALUE, C.IPP_TAG_NOTSETTABLE: // No value means no value. case C.IPP_TAG_INTEGER, C.IPP_TAG_ENUM: for i := 0; i < count; i++ { values[i] = strconv.FormatInt(int64(C.ippGetInteger(a, C.int(i))), 10) } case C.IPP_TAG_BOOLEAN: for i := 0; i < count; i++ { if int(C.ippGetInteger(a, C.int(i))) == 0 { values[i] = "false" } else { values[i] = "true" } } case C.IPP_TAG_STRING, C.IPP_TAG_TEXT, C.IPP_TAG_NAME, C.IPP_TAG_KEYWORD, C.IPP_TAG_URI, C.IPP_TAG_CHARSET, C.IPP_TAG_LANGUAGE, C.IPP_TAG_MIMETYPE: for i := 0; i < count; i++ { values[i] = C.GoString(C.ippGetString(a, C.int(i), nil)) } case C.IPP_TAG_DATE: for i := 0; i < count; i++ { date := C.ippGetDate(a, C.int(i)) t := convertIPPDateToTime(date) values[i] = strconv.FormatInt(t.Unix(), 10) } case C.IPP_TAG_RESOLUTION: for i := 0; i < count; i++ { yres := C.int(-1) unit := C.int(-1) xres := C.ippGetResolutionWrapper(a, C.int(i), &yres, &unit) if unit == C.IPP_RES_PER_CM { values[i] = fmt.Sprintf("%dx%dpp%s", int(xres), int(yres), "cm") } else { values[i] = fmt.Sprintf("%dx%dpp%s", int(xres), int(yres), "i") } } case C.IPP_TAG_RANGE: for i := 0; i < count; i++ { uppervalue := C.int(-1) lowervalue := C.ippGetRange(a, C.int(i), &uppervalue) values[i] = fmt.Sprintf("%d~%d", int(lowervalue), int(uppervalue)) } default: if count > 0 { values = []string{"unknown or unsupported type"} } } if len(values) == 1 && values[0] == "none" { values = []string{} } // This block fixes some drivers' marker types, which list an extra // type containing a comma, which CUPS interprets as an extra type. // The extra type starts with a space, so it's easy to detect. if len(values) > 1 && len(values[len(values)-1]) > 1 && values[len(values)-1][0:1] == " " { newValues := make([]string, len(values)-1) for i := 0; i < len(values)-2; i++ { newValues[i] = values[i] } newValues[len(newValues)-1] = strings.Join(values[len(values)-2:], ",") values = newValues } tags[key] = values } return tags }