func TestTrPrintQuality(t *testing.T) { ppd := `*PPD-Adobe: "4.3" *OpenUI *HPPrintQuality/Print Quality: PickOne *DefaultHPPrintQuality: FastRes1200 *HPPrintQuality FastRes1200/FastRes 1200: "" *HPPrintQuality 600dpi/600 dpi: "" *HPPrintQuality ProRes1200/ProRes 1200: "" *CloseUI: *HPPrintQuality` expected := testdata{ &cdd.PrinterDescriptionSection{ VendorCapability: &[]cdd.VendorCapability{ cdd.VendorCapability{ ID: "HPPrintQuality", Type: cdd.VendorCapabilitySelect, DisplayNameLocalized: cdd.NewLocalizedString("Print Quality"), SelectCap: &cdd.SelectCapability{ Option: []cdd.SelectCapabilityOption{ cdd.SelectCapabilityOption{"FastRes1200", "", true, cdd.NewLocalizedString("FastRes 1200")}, cdd.SelectCapabilityOption{"600dpi", "", false, cdd.NewLocalizedString("600 dpi")}, cdd.SelectCapabilityOption{"ProRes1200", "", false, cdd.NewLocalizedString("ProRes 1200")}, }, }, }, }, }, nil, } translationTest(t, ppd, []string{}, expected) }
func convertPagesPerSheet(printerTags map[string][]string) *cdd.VendorCapability { numberUpSupported, exists := printerTags[attrNumberUpSupported] if !exists { return nil } c := cdd.VendorCapability{ ID: attrNumberUp, Type: cdd.VendorCapabilitySelect, SelectCap: &cdd.SelectCapability{}, DisplayNameLocalized: cdd.NewLocalizedString("Pages per sheet"), } def, exists := printerTags[attrNumberUpDefault] if !exists { def = []string{"1"} } for _, number := range numberUpSupported { option := cdd.SelectCapabilityOption{ Value: number, IsDefault: reflect.DeepEqual(number, def[0]), DisplayNameLocalized: cdd.NewLocalizedString(number), } c.SelectCap.Option = append(c.SelectCap.Option, option) } return &c }
func TestConvertColorAttrs(t *testing.T) { c := convertColorAttrs(nil) if c != nil { t.Logf("expected nil") t.Fail() } pt := map[string][]string{} c = convertColorAttrs(pt) if c != nil { t.Logf("expected nil") t.Fail() } pt = map[string][]string{ "print-color-mode-default": []string{"auto"}, "print-color-mode-supported": []string{"color", "monochrome", "auto", "zebra"}, } expected := &cdd.Color{ Option: []cdd.ColorOption{ cdd.ColorOption{"print-color-mode:color", cdd.ColorTypeStandardColor, "", false, cdd.NewLocalizedString("Color")}, cdd.ColorOption{"print-color-mode:monochrome", cdd.ColorTypeStandardMonochrome, "", false, cdd.NewLocalizedString("Monochrome")}, cdd.ColorOption{"print-color-mode:auto", cdd.ColorTypeAuto, "", true, cdd.NewLocalizedString("Auto")}, cdd.ColorOption{"print-color-mode:zebra", cdd.ColorTypeCustomColor, "", false, cdd.NewLocalizedString("zebra")}, }, } c = convertColorAttrs(pt) if !reflect.DeepEqual(expected, c) { t.Logf("expected %+v, got %+v", expected, c) t.Fail() } }
func TestTrInputSlot(t *testing.T) { ppd := `*PPD-Adobe: "4.3" *OpenUI *OutputBin/Destination: PickOne *OrderDependency: 210 AnySetup *OutputBin *DefaultOutputBin: FinProof *OutputBin Standard/Internal Tray 1: "" *OutputBin Bin1/Internal Tray 2: "" *OutputBin External/External Tray: "" *CloseUI: *OutputBin` expected := testdata{ &cdd.PrinterDescriptionSection{ VendorCapability: &[]cdd.VendorCapability{ cdd.VendorCapability{ ID: "OutputBin", Type: cdd.VendorCapabilitySelect, DisplayNameLocalized: cdd.NewLocalizedString("Destination"), SelectCap: &cdd.SelectCapability{ Option: []cdd.SelectCapabilityOption{ cdd.SelectCapabilityOption{"Standard", "", true, cdd.NewLocalizedString("Internal Tray 1")}, cdd.SelectCapabilityOption{"Bin1", "", false, cdd.NewLocalizedString("Internal Tray 2")}, cdd.SelectCapabilityOption{"External", "", false, cdd.NewLocalizedString("External Tray")}, }, }, }, }, }, nil, } translationTest(t, ppd, []string{}, expected) }
func TestGetVendorState(t *testing.T) { vs := getVendorState(nil) if nil != vs { t.Logf("expected nil") t.Fail() } pt := map[string][]string{} vs = getVendorState(pt) if nil != vs { t.Logf("expected nil") t.Fail() } pt = map[string][]string{ attrPrinterStateReasons: []string{"broken-arrow", "peanut-butter-jam-warning"}, } expected := &cdd.VendorState{ Item: []cdd.VendorStateItem{ cdd.VendorStateItem{ DescriptionLocalized: cdd.NewLocalizedString("broken-arrow"), State: cdd.VendorStateError, }, cdd.VendorStateItem{ DescriptionLocalized: cdd.NewLocalizedString("peanut-butter-jam-warning"), State: cdd.VendorStateWarning, }, }, } vs = getVendorState(pt) if !reflect.DeepEqual(expected, vs) { t.Logf("expected\n %+v\ngot\n %+v", expected, vs) t.Fail() } }
func TestConvertPagesPerSheet(t *testing.T) { vc := convertPagesPerSheet(nil) if vc != nil { t.Logf("expected nil") t.Fail() } pt := map[string][]string{} vc = convertPagesPerSheet(pt) if vc != nil { t.Logf("expected nil") t.Fail() } pt = map[string][]string{ "number-up-default": []string{"4"}, "number-up-supported": []string{"1", "2", "4"}, } expected := &cdd.VendorCapability{ ID: "number-up", Type: cdd.VendorCapabilitySelect, SelectCap: &cdd.SelectCapability{ Option: []cdd.SelectCapabilityOption{ cdd.SelectCapabilityOption{ Value: "1", IsDefault: false, DisplayNameLocalized: cdd.NewLocalizedString("1"), }, cdd.SelectCapabilityOption{ Value: "2", IsDefault: false, DisplayNameLocalized: cdd.NewLocalizedString("2"), }, cdd.SelectCapabilityOption{ Value: "4", IsDefault: true, DisplayNameLocalized: cdd.NewLocalizedString("4"), }, }, }, DisplayNameLocalized: cdd.NewLocalizedString("Pages per sheet"), } vc = convertPagesPerSheet(pt) if !reflect.DeepEqual(expected, vc) { e, _ := json.Marshal(expected) f, _ := json.Marshal(vc) t.Logf("expected\n %s\ngot\n %s", e, f) t.Fail() } }
func convertColorAttrs(printerTags map[string][]string) *cdd.Color { colorSupported, exists := printerTags[attrPrintColorModeSupported] if !exists { return nil } c := cdd.Color{} colorDefault, exists := printerTags[attrPrintColorModeDefault] if !exists || len(colorDefault) != 1 { colorDefault = colorSupported[:1] } for _, color := range colorSupported { var co cdd.ColorOption var exists bool if co, exists = colorByKeyword[color]; !exists { co = cdd.ColorOption{ VendorID: attrPrintColorMode + internalKeySeparator + color, Type: cdd.ColorTypeCustomColor, CustomDisplayNameLocalized: cdd.NewLocalizedString(color), } } if color == colorDefault[0] { co.IsDefault = true } c.Option = append(c.Option, co) } return &c }
func TestTrVendorPPDOptions(t *testing.T) { ppd := `*PPD-Adobe: "4.3" *OpenUI *CustomKey/Custom Translation: PickOne *DefaultCustomKey: Some *CustomKey None/Off: "" *CustomKey Some/On: "" *CustomKey Yes/Petunia: "" *CloseUI: *CustomKey` expected := testdata{ &cdd.PrinterDescriptionSection{ VendorCapability: &[]cdd.VendorCapability{ cdd.VendorCapability{ ID: "CustomKey", Type: cdd.VendorCapabilitySelect, DisplayNameLocalized: cdd.NewLocalizedString("Custom Translation"), SelectCap: &cdd.SelectCapability{ Option: []cdd.SelectCapabilityOption{ cdd.SelectCapabilityOption{"None", "", false, cdd.NewLocalizedString("Off")}, cdd.SelectCapabilityOption{"Some", "", true, cdd.NewLocalizedString("On")}, cdd.SelectCapabilityOption{"Yes", "", false, cdd.NewLocalizedString("Petunia")}, }, }, }, }, }, nil, } translationTest(t, ppd, []string{"CustomKey", "AnyOtherKey"}, expected) translationTest(t, ppd, []string{"all"}, expected) translationTest(t, ppd, []string{"CustomKey", "all"}, expected) translationTest(t, ppd, []string{"AnyOtherKey", "all"}, expected) expected = testdata{ &cdd.PrinterDescriptionSection{}, nil, } translationTest(t, ppd, []string{}, expected) translationTest(t, ppd, []string{"AnyOtherKey"}, expected) }
func TestTrDPI(t *testing.T) { ppd := `*PPD-Adobe: "4.3" *OpenUI *Resolution/Resolution: PickOne *DefaultResolution: 600dpi *Resolution 600dpi/600 dpi: "" *Resolution 1200x600dpi/1200x600 dpi: "" *Resolution 1200x1200dpi/1200 dpi: "" *CloseUI: *Resolution` expected := testdata{ &cdd.PrinterDescriptionSection{ DPI: &cdd.DPI{ Option: []cdd.DPIOption{ cdd.DPIOption{600, 600, true, "", "600dpi", cdd.NewLocalizedString("600 dpi")}, cdd.DPIOption{1200, 600, false, "", "1200x600dpi", cdd.NewLocalizedString("1200x600 dpi")}, cdd.DPIOption{1200, 1200, false, "", "1200x1200dpi", cdd.NewLocalizedString("1200 dpi")}, }, }, }, nil, } translationTest(t, ppd, []string{}, expected) }
func TestRicohLockedPrint(t *testing.T) { ppd := `*PPD-Adobe: "4.3" *OpenUI *JobType/JobType: PickOne *FoomaticRIPOption JobType: enum CmdLine B *OrderDependency: 255 AnySetup *JobType *DefaultJobType: Normal *JobType Normal/Normal: "%% FoomaticRIPOptionSetting: JobType=Normal" *JobType SamplePrint/Sample Print: "%% FoomaticRIPOptionSetting: JobType=SamplePrint" *JobType LockedPrint/Locked Print: "" *JobType DocServer/Document Server: "" *CloseUI: *JobType *OpenUI *LockedPrintPassword/Locked Print Password (4-8 digits): PickOne *FoomaticRIPOption LockedPrintPassword: password CmdLine C *FoomaticRIPOptionMaxLength LockedPrintPassword:8 *FoomaticRIPOptionAllowedChars LockedPrintPassword: "******" *OrderDependency: 255 AnySetup *LockedPrintPassword *DefaultLockedPrintPassword: None *LockedPrintPassword None/None: "" *LockedPrintPassword 4001/4001: "%% FoomaticRIPOptionSetting: LockedPrintPassword=4001" *LockedPrintPassword 4002/4002: "%% FoomaticRIPOptionSetting: LockedPrintPassword=4002" *LockedPrintPassword 4003/4003: "%% FoomaticRIPOptionSetting: LockedPrintPassword=4003" *CloseUI: *LockedPrintPassword *CustomLockedPrintPassword True/Custom Password: "" *ParamCustomLockedPrintPassword Password: 1 passcode 4 8 ` expected := testdata{ &cdd.PrinterDescriptionSection{ VendorCapability: &[]cdd.VendorCapability{ cdd.VendorCapability{ ID: "JobType:LockedPrint/LockedPrintPassword", Type: cdd.VendorCapabilityTypedValue, DisplayNameLocalized: cdd.NewLocalizedString("Password (4 numbers)"), TypedValueCap: &cdd.TypedValueCapability{ ValueType: cdd.TypedValueCapabilityTypeString, }, }, }, }, nil, } translationTest(t, ppd, []string{}, expected) }
func getVendorState(printerTags map[string][]string) *cdd.VendorState { reasons, exists := printerTags[attrPrinterStateReasons] if !exists || len(reasons) < 1 { return nil } sort.Strings(reasons) vendorState := &cdd.VendorState{Item: make([]cdd.VendorStateItem, len(reasons))} for i, reason := range reasons { vs := cdd.VendorStateItem{DescriptionLocalized: cdd.NewLocalizedString(reason)} if strings.HasSuffix(reason, "-error") { vs.State = cdd.VendorStateError } else if strings.HasSuffix(reason, "-warning") { vs.State = cdd.VendorStateWarning } else if strings.HasSuffix(reason, "-report") { vs.State = cdd.VendorStateInfo } else { vs.State = cdd.VendorStateError } vendorState.Item[i] = vs } return vendorState }
func convertPrinterState(wsStatus uint32, wsAttributes uint32) *cdd.PrinterStateSection { state := cdd.PrinterStateSection{ State: cdd.CloudDeviceStateIdle, VendorState: &cdd.VendorState{}, } if wsStatus&(PRINTER_STATUS_PRINTING|PRINTER_STATUS_PROCESSING) != 0 { state.State = cdd.CloudDeviceStateProcessing } if wsStatus&PRINTER_STATUS_PAUSED != 0 { state.State = cdd.CloudDeviceStateStopped vs := cdd.VendorStateItem{ State: cdd.VendorStateWarning, DescriptionLocalized: cdd.NewLocalizedString("printer paused"), } state.VendorState.Item = append(state.VendorState.Item, vs) } if wsStatus&PRINTER_STATUS_ERROR != 0 { state.State = cdd.CloudDeviceStateStopped vs := cdd.VendorStateItem{ State: cdd.VendorStateError, DescriptionLocalized: cdd.NewLocalizedString("printer error"), } state.VendorState.Item = append(state.VendorState.Item, vs) } if wsStatus&PRINTER_STATUS_PENDING_DELETION != 0 { state.State = cdd.CloudDeviceStateStopped vs := cdd.VendorStateItem{ State: cdd.VendorStateError, DescriptionLocalized: cdd.NewLocalizedString("printer is being deleted"), } state.VendorState.Item = append(state.VendorState.Item, vs) } if wsStatus&PRINTER_STATUS_PAPER_JAM != 0 { state.State = cdd.CloudDeviceStateStopped vs := cdd.VendorStateItem{ State: cdd.VendorStateError, DescriptionLocalized: cdd.NewLocalizedString("paper jam"), } state.VendorState.Item = append(state.VendorState.Item, vs) } if wsStatus&PRINTER_STATUS_PAPER_OUT != 0 { state.State = cdd.CloudDeviceStateStopped vs := cdd.VendorStateItem{ State: cdd.VendorStateError, DescriptionLocalized: cdd.NewLocalizedString("paper out"), } state.VendorState.Item = append(state.VendorState.Item, vs) } if wsStatus&PRINTER_STATUS_MANUAL_FEED != 0 { vs := cdd.VendorStateItem{ State: cdd.VendorStateInfo, DescriptionLocalized: cdd.NewLocalizedString("manual feed mode"), } state.VendorState.Item = append(state.VendorState.Item, vs) } if wsStatus&PRINTER_STATUS_PAPER_PROBLEM != 0 { state.State = cdd.CloudDeviceStateStopped vs := cdd.VendorStateItem{ State: cdd.VendorStateError, DescriptionLocalized: cdd.NewLocalizedString("paper problem"), } state.VendorState.Item = append(state.VendorState.Item, vs) } // If PRINTER_ATTRIBUTE_WORK_OFFLINE is set // spooler won't despool any jobs to the printer. // At least for some USB printers, this flag is controlled // automatically by the system depending on the state of physical connection. if wsStatus&PRINTER_STATUS_OFFLINE != 0 || wsAttributes&PRINTER_ATTRIBUTE_WORK_OFFLINE != 0 { state.State = cdd.CloudDeviceStateStopped vs := cdd.VendorStateItem{ State: cdd.VendorStateError, DescriptionLocalized: cdd.NewLocalizedString("printer is offline"), } state.VendorState.Item = append(state.VendorState.Item, vs) } if wsStatus&PRINTER_STATUS_IO_ACTIVE != 0 { vs := cdd.VendorStateItem{ State: cdd.VendorStateInfo, DescriptionLocalized: cdd.NewLocalizedString("active I/O state"), } state.VendorState.Item = append(state.VendorState.Item, vs) } if wsStatus&PRINTER_STATUS_BUSY != 0 { vs := cdd.VendorStateItem{ State: cdd.VendorStateInfo, DescriptionLocalized: cdd.NewLocalizedString("busy"), } state.VendorState.Item = append(state.VendorState.Item, vs) } if wsStatus&PRINTER_STATUS_OUTPUT_BIN_FULL != 0 { state.State = cdd.CloudDeviceStateStopped vs := cdd.VendorStateItem{ State: cdd.VendorStateError, DescriptionLocalized: cdd.NewLocalizedString("output bin is full"), } state.VendorState.Item = append(state.VendorState.Item, vs) } if wsStatus&PRINTER_STATUS_NOT_AVAILABLE != 0 { state.State = cdd.CloudDeviceStateStopped vs := cdd.VendorStateItem{ State: cdd.VendorStateError, DescriptionLocalized: cdd.NewLocalizedString("printer not available"), } state.VendorState.Item = append(state.VendorState.Item, vs) } if wsStatus&PRINTER_STATUS_WAITING != 0 { vs := cdd.VendorStateItem{ State: cdd.VendorStateError, DescriptionLocalized: cdd.NewLocalizedString("waiting"), } state.VendorState.Item = append(state.VendorState.Item, vs) } if wsStatus&PRINTER_STATUS_INITIALIZING != 0 { vs := cdd.VendorStateItem{ State: cdd.VendorStateInfo, DescriptionLocalized: cdd.NewLocalizedString("intitializing"), } state.VendorState.Item = append(state.VendorState.Item, vs) } if wsStatus&PRINTER_STATUS_WARMING_UP != 0 { vs := cdd.VendorStateItem{ State: cdd.VendorStateInfo, DescriptionLocalized: cdd.NewLocalizedString("warming up"), } state.VendorState.Item = append(state.VendorState.Item, vs) } if wsStatus&PRINTER_STATUS_TONER_LOW != 0 { vs := cdd.VendorStateItem{ State: cdd.VendorStateWarning, DescriptionLocalized: cdd.NewLocalizedString("toner low"), } state.VendorState.Item = append(state.VendorState.Item, vs) } if wsStatus&PRINTER_STATUS_NO_TONER != 0 { state.State = cdd.CloudDeviceStateStopped vs := cdd.VendorStateItem{ State: cdd.VendorStateError, DescriptionLocalized: cdd.NewLocalizedString("no toner"), } state.VendorState.Item = append(state.VendorState.Item, vs) } if wsStatus&PRINTER_STATUS_PAGE_PUNT != 0 { state.State = cdd.CloudDeviceStateStopped vs := cdd.VendorStateItem{ State: cdd.VendorStateError, DescriptionLocalized: cdd.NewLocalizedString("cannot print the current page"), } state.VendorState.Item = append(state.VendorState.Item, vs) } if wsStatus&PRINTER_STATUS_USER_INTERVENTION != 0 { state.State = cdd.CloudDeviceStateStopped vs := cdd.VendorStateItem{ State: cdd.VendorStateError, DescriptionLocalized: cdd.NewLocalizedString("user intervention required"), } state.VendorState.Item = append(state.VendorState.Item, vs) } if wsStatus&PRINTER_STATUS_OUT_OF_MEMORY != 0 { state.State = cdd.CloudDeviceStateStopped vs := cdd.VendorStateItem{ State: cdd.VendorStateError, DescriptionLocalized: cdd.NewLocalizedString("out of memory"), } state.VendorState.Item = append(state.VendorState.Item, vs) } if wsStatus&PRINTER_STATUS_DOOR_OPEN != 0 { state.State = cdd.CloudDeviceStateStopped vs := cdd.VendorStateItem{ State: cdd.VendorStateError, DescriptionLocalized: cdd.NewLocalizedString("door open"), } state.VendorState.Item = append(state.VendorState.Item, vs) } if wsStatus&PRINTER_STATUS_SERVER_UNKNOWN != 0 { vs := cdd.VendorStateItem{ State: cdd.VendorStateError, DescriptionLocalized: cdd.NewLocalizedString("printer status unknown"), } state.VendorState.Item = append(state.VendorState.Item, vs) } if wsStatus&PRINTER_STATUS_POWER_SAVE != 0 { vs := cdd.VendorStateItem{ State: cdd.VendorStateInfo, DescriptionLocalized: cdd.NewLocalizedString("power save mode"), } state.VendorState.Item = append(state.VendorState.Item, vs) } if len(state.VendorState.Item) == 0 { state.VendorState = nil } return &state }
func convertMediaSize(printerName, portName string, devMode *DevMode) (*cdd.MediaSize, error) { defSize, defSizeOK := devMode.GetPaperSize() defLength, defLengthOK := devMode.GetPaperLength() defWidth, defWidthOK := devMode.GetPaperWidth() names, err := DeviceCapabilitiesStrings(printerName, portName, DC_PAPERNAMES, 64*2) if err != nil { return nil, err } papers, err := DeviceCapabilitiesUint16Array(printerName, portName, DC_PAPERS) if err != nil { return nil, err } sizes, err := DeviceCapabilitiesInt32Pairs(printerName, portName, DC_PAPERSIZE) if err != nil { return nil, err } if len(names) != len(papers) || len(names) != len(sizes)/2 { return nil, nil } ms := cdd.MediaSize{ Option: make([]cdd.MediaSizeOption, 0, len(names)), } var foundDef bool for i := range names { if names[i] == "" { continue } // Convert from tenths-of-mm to micrometers width, length := sizes[2*i]*100, sizes[2*i+1]*100 var def bool if !foundDef { if defSizeOK { if uint16(defSize) == papers[i] { def = true foundDef = true } } else if defLengthOK && int32(defLength) == length && defWidthOK && int32(defWidth) == width { def = true foundDef = true } } o := cdd.MediaSizeOption{ Name: cdd.MediaSizeCustom, WidthMicrons: width, HeightMicrons: length, IsDefault: def, VendorID: strconv.FormatUint(uint64(papers[i]), 10), CustomDisplayNameLocalized: cdd.NewLocalizedString(names[i]), } ms.Option = append(ms.Option, o) } if !foundDef && len(ms.Option) > 0 { ms.Option[0].IsDefault = true } return &ms, nil }
// GetPrinters gets all Windows printers found on this computer. func (ws *WinSpool) GetPrinters() ([]lib.Printer, error) { pi2s, err := EnumPrinters2() if err != nil { return nil, err } printers := make([]lib.Printer, 0, len(pi2s)) for _, pi2 := range pi2s { printerName := pi2.GetPrinterName() portName := pi2.GetPortName() devMode := pi2.GetDevMode() manufacturer, model := getManModel(pi2.GetDriverName()) printer := lib.Printer{ Name: printerName, DefaultDisplayName: ws.displayNamePrefix + printerName, UUID: printerName, // TODO: Add something unique from host. Manufacturer: manufacturer, Model: model, State: convertPrinterState(pi2.GetStatus(), pi2.GetAttributes()), Description: &cdd.PrinterDescriptionSection{}, Tags: map[string]string{ "printer-location": pi2.GetLocation(), }, } // Advertise color based on default value, which should be a solid indicator // of color-ness, because the source of this devMode object is EnumPrinters. if def, ok := devMode.GetColor(); ok { if def == DMCOLOR_COLOR { printer.Description.Color = &cdd.Color{ Option: []cdd.ColorOption{ cdd.ColorOption{ VendorID: strconv.FormatInt(int64(DMCOLOR_COLOR), 10), Type: cdd.ColorTypeStandardColor, IsDefault: true, CustomDisplayNameLocalized: cdd.NewLocalizedString("Color"), }, cdd.ColorOption{ VendorID: strconv.FormatInt(int64(DMCOLOR_MONOCHROME), 10), Type: cdd.ColorTypeStandardMonochrome, IsDefault: false, CustomDisplayNameLocalized: cdd.NewLocalizedString("Monochrome"), }, }, } } else if def == DMCOLOR_MONOCHROME { printer.Description.Color = &cdd.Color{ Option: []cdd.ColorOption{ cdd.ColorOption{ VendorID: strconv.FormatInt(int64(DMCOLOR_MONOCHROME), 10), Type: cdd.ColorTypeStandardMonochrome, IsDefault: true, CustomDisplayNameLocalized: cdd.NewLocalizedString("Monochrome"), }, }, } } } if def, ok := devMode.GetDuplex(); ok { duplex, err := DeviceCapabilitiesInt32(printerName, portName, DC_DUPLEX) if err != nil { return nil, err } if duplex == 1 { printer.Description.Duplex = &cdd.Duplex{ Option: []cdd.DuplexOption{ cdd.DuplexOption{ Type: cdd.DuplexNoDuplex, IsDefault: def == DMDUP_SIMPLEX, }, cdd.DuplexOption{ Type: cdd.DuplexLongEdge, IsDefault: def == DMDUP_VERTICAL, }, cdd.DuplexOption{ Type: cdd.DuplexShortEdge, IsDefault: def == DMDUP_HORIZONTAL, }, }, } } } if def, ok := devMode.GetOrientation(); ok { orientation, err := DeviceCapabilitiesInt32(printerName, portName, DC_ORIENTATION) if err != nil { return nil, err } if orientation == 90 || orientation == 270 { printer.Description.PageOrientation = &cdd.PageOrientation{ Option: []cdd.PageOrientationOption{ cdd.PageOrientationOption{ Type: cdd.PageOrientationPortrait, IsDefault: def == DMORIENT_PORTRAIT, }, cdd.PageOrientationOption{ Type: cdd.PageOrientationLandscape, IsDefault: def == DMORIENT_LANDSCAPE, }, }, } } } if def, ok := devMode.GetCopies(); ok { copies, err := DeviceCapabilitiesInt32(printerName, portName, DC_COPIES) if err != nil { return nil, err } if copies > 1 { printer.Description.Copies = &cdd.Copies{ Default: int32(def), Max: copies, } } } printer.Description.MediaSize, err = convertMediaSize(printerName, portName, devMode) if err != nil { return nil, err } if def, ok := devMode.GetCollate(); ok { collate, err := DeviceCapabilitiesInt32(printerName, portName, DC_COLLATE) if err != nil { return nil, err } if collate == 1 { printer.Description.Collate = &cdd.Collate{ Default: def == DMCOLLATE_TRUE, } } } printers = append(printers, printer) } printers = lib.FilterBlacklistPrinters(printers, ws.printerBlacklist) printers = lib.FilterWhitelistPrinters(printers, ws.printerWhitelist) printers = addStaticDescriptionToPrinters(printers) printers = ws.addSystemTagsToPrinters(printers) return printers, nil }
func TestTrColor(t *testing.T) { ppd := `*PPD-Adobe: "4.3" *OpenUI *ColorModel/Color Mode: PickOne *DefaultColorModel: Gray *ColorModel CMYK/Color: "(cmyk) RCsetdevicecolor" *ColorModel Gray/Black and White: "(gray) RCsetdevicecolor" *CloseUI: *ColorModel` expected := testdata{ &cdd.PrinterDescriptionSection{ Color: &cdd.Color{ Option: []cdd.ColorOption{ cdd.ColorOption{"ColorModel:CMYK", cdd.ColorTypeStandardColor, "", false, cdd.NewLocalizedString("Color")}, cdd.ColorOption{"ColorModel:Gray", cdd.ColorTypeStandardMonochrome, "", true, cdd.NewLocalizedString("Black and White")}, }, }, }, nil, } translationTest(t, ppd, []string{}, expected) ppd = `*PPD-Adobe: "4.3" *OpenUI *CMAndResolution/Print Color as Gray: PickOne *OrderDependency: 20 AnySetup *CMAndResolution *DefaultCMAndResolution: CMYKImageRET3600 *CMAndResolution CMYKImageRET3600/Off: " <</ProcessColorModel /DeviceCMYK /HWResolution [600 600] /PreRenderingEnhance false >> setpagedevice" *End *CMAndResolution Gray600x600dpi/On: " <</ProcessColorModel /DeviceGray /HWResolution [600 600] >> setpagedevice" *End *CloseUI: *CMAndResolution ` expected = testdata{ &cdd.PrinterDescriptionSection{ Color: &cdd.Color{ Option: []cdd.ColorOption{ cdd.ColorOption{"CMAndResolution:CMYKImageRET3600", cdd.ColorTypeStandardColor, "", true, cdd.NewLocalizedString("Color")}, cdd.ColorOption{"CMAndResolution:Gray600x600dpi", cdd.ColorTypeStandardMonochrome, "", false, cdd.NewLocalizedString("Gray")}, }, }, }, nil, } translationTest(t, ppd, []string{}, expected) ppd = `*PPD-Adobe: "4.3" *OpenUI *CMAndResolution/Print Color as Gray: PickOne *OrderDependency: 20 AnySetup *CMAndResolution *DefaultCMAndResolution: CMYKImageRET2400 *CMAndResolution CMYKImageRET2400/Off - ImageRET 2400: "<< /ProcessColorModel /DeviceCMYK /HWResolution [600 600] >> setpagedevice" *CMAndResolution Gray1200x1200dpi/On - ProRes 1200: "<</ProcessColorModel /DeviceGray /HWResolution [1200 1200] /PreRenderingEnhance false>> setpagedevice" *CMAndResolution Gray600x600dpi/On - 600 dpi: "<</ProcessColorModel /DeviceGray /HWResolution [600 600] /PreRenderingEnhance false>> setpagedevice" *CloseUI: *CMAndResolution ` expected = testdata{ &cdd.PrinterDescriptionSection{ Color: &cdd.Color{ Option: []cdd.ColorOption{ cdd.ColorOption{"CMAndResolution:CMYKImageRET2400", cdd.ColorTypeStandardColor, "", true, cdd.NewLocalizedString("Color, ImageRET 2400")}, cdd.ColorOption{"CMAndResolution:Gray1200x1200dpi", cdd.ColorTypeCustomMonochrome, "", false, cdd.NewLocalizedString("Gray, ProRes 1200")}, cdd.ColorOption{"CMAndResolution:Gray600x600dpi", cdd.ColorTypeCustomMonochrome, "", false, cdd.NewLocalizedString("Gray, 600 dpi")}, }, }, }, nil, } translationTest(t, ppd, []string{}, expected) ppd = `*PPD-Adobe: "4.3" *OpenUI *SelectColor/Select Color: PickOne *OrderDependency: 10 AnySetup *SelectColor *DefaultSelectColor: Color *SelectColor Color/Color: "<</ProcessColorModel /DeviceCMYK>> setpagedevice" *SelectColor Grayscale/Grayscale: "<</ProcessColorModel /DeviceGray>> setpagedevice" *CloseUI: *SelectColor ` expected = testdata{ &cdd.PrinterDescriptionSection{ Color: &cdd.Color{ Option: []cdd.ColorOption{ cdd.ColorOption{"SelectColor:Color", cdd.ColorTypeStandardColor, "", true, cdd.NewLocalizedString("Color")}, cdd.ColorOption{"SelectColor:Grayscale", cdd.ColorTypeStandardMonochrome, "", false, cdd.NewLocalizedString("Grayscale")}, }, }, }, nil, } translationTest(t, ppd, []string{}, expected) }
func TestTrMediaSize(t *testing.T) { ppd := `*PPD-Adobe: "4.3" *OpenUI *PageSize: PickOne *DefaultPageSize: Letter *PageSize A3/A3: "" *PageSize ISOB5/B5 - ISO: "" *PageSize B5/B5 - JIS: "" *PageSize Letter/Letter: "" *PageSize HalfLetter/5.5x8.5: "" *PageSize w81h252/Address - 1 1/8 x 3 1/2": "<</PageSize[81 252]/ImagingBBox null>>setpagedevice" *CloseUI: *PageSize` expected := testdata{ &cdd.PrinterDescriptionSection{ MediaSize: &cdd.MediaSize{ Option: []cdd.MediaSizeOption{ cdd.MediaSizeOption{cdd.MediaSizeISOA3, mmToMicrons(297), mmToMicrons(420), false, false, "", "A3", cdd.NewLocalizedString("A3")}, cdd.MediaSizeOption{cdd.MediaSizeISOB5, mmToMicrons(176), mmToMicrons(250), false, false, "", "ISOB5", cdd.NewLocalizedString("B5 (ISO)")}, cdd.MediaSizeOption{cdd.MediaSizeJISB5, mmToMicrons(182), mmToMicrons(257), false, false, "", "B5", cdd.NewLocalizedString("B5 (JIS)")}, cdd.MediaSizeOption{cdd.MediaSizeNALetter, inchesToMicrons(8.5), inchesToMicrons(11), false, true, "", "Letter", cdd.NewLocalizedString("Letter")}, cdd.MediaSizeOption{cdd.MediaSizeCustom, inchesToMicrons(5.5), inchesToMicrons(8.5), false, false, "", "HalfLetter", cdd.NewLocalizedString("5.5x8.5")}, cdd.MediaSizeOption{cdd.MediaSizeCustom, pointsToMicrons(81), pointsToMicrons(252), false, false, "", "w81h252", cdd.NewLocalizedString(`Address - 1 1/8 x 3 1/2"`)}, }, }, }, nil, } translationTest(t, ppd, []string{}, expected) }
if err != nil { return nil } } return &cdd.Copies{ Default: int32(def), Max: int32(max), } } var colorByKeyword = map[string]cdd.ColorOption{ "auto": cdd.ColorOption{ VendorID: attrPrintColorMode + internalKeySeparator + "auto", Type: cdd.ColorTypeAuto, CustomDisplayNameLocalized: cdd.NewLocalizedString("Auto"), }, "color": cdd.ColorOption{ VendorID: attrPrintColorMode + internalKeySeparator + "color", Type: cdd.ColorTypeStandardColor, CustomDisplayNameLocalized: cdd.NewLocalizedString("Color"), }, "monochrome": cdd.ColorOption{ VendorID: attrPrintColorMode + internalKeySeparator + "monochrome", Type: cdd.ColorTypeStandardMonochrome, CustomDisplayNameLocalized: cdd.NewLocalizedString("Monochrome"), }, } func convertColorAttrs(printerTags map[string][]string) *cdd.Color { colorSupported, exists := printerTags[attrPrintColorModeSupported]
// convertMarkers converts CUPS marker-(names|types|levels) to *[]cdd.Marker and *cdd.MarkerState. // // Normalizes marker type: toner(Cartridge|-cartridge) => toner, // ink(Cartridge|-cartridge|Ribbon|-ribbon) => ink func convertMarkers(printerTags map[string][]string) (*[]cdd.Marker, *cdd.MarkerState) { names, types, levels := printerTags[attrMarkerNames], printerTags[attrMarkerTypes], printerTags[attrMarkerLevels] if len(names) == 0 || len(types) == 0 || len(levels) == 0 { return nil, nil } if len(names) != len(levels) { newNames := fixMarkers(names) if len(newNames) != len(levels) { log.Warningf("Received badly-formatted marker-names from CUPS: %s, %s, %s", strings.Join(names, ";"), strings.Join(types, ";"), strings.Join(levels, ";")) return nil, nil } names = newNames } { nameSet := make(map[string]struct{}, len(names)) for _, name := range names { if _, exists := nameSet[name]; exists { return nil, nil } nameSet[name] = struct{}{} } } if len(types) != len(levels) { newTypes := fixMarkers(types) if len(newTypes) != len(levels) { log.Warningf("Received badly-formatted marker-types from CUPS: %s, %s, %s", strings.Join(names, ";"), strings.Join(types, ";"), strings.Join(levels, ";")) return nil, nil } types = newTypes } markers := make([]cdd.Marker, 0, len(names)) states := cdd.MarkerState{make([]cdd.MarkerStateItem, 0, len(names))} for i := 0; i < len(names); i++ { if len(names[i]) == 0 { return nil, nil } var markerType cdd.MarkerType switch strings.ToLower(types[i]) { case "toner", "tonercartridge", "toner-cartridge": markerType = cdd.MarkerToner case "ink", "inkcartridge", "ink-cartridge", "ink-ribbon", "inkribbon": markerType = cdd.MarkerInk case "staples": markerType = cdd.MarkerStaples default: continue } var color *cdd.MarkerColor if markerType == cdd.MarkerToner || markerType == cdd.MarkerInk { nameStripped := strings.Replace(strings.Replace(strings.ToLower(names[i]), " ", "", -1), "-", "", -1) colorType := cdd.MarkerColorCustom for k, v := range cupsMarkerNameToGCP { if strings.HasPrefix(nameStripped, k) { colorType = v break } } color = &cdd.MarkerColor{Type: colorType} if colorType == cdd.MarkerColorCustom { name := names[i] name = strings.TrimSuffix(name, " Cartridge") name = strings.TrimSuffix(name, " cartridge") name = strings.TrimSuffix(name, " Ribbon") name = strings.TrimSuffix(name, " ribbon") name = strings.TrimSuffix(name, " Toner") name = strings.TrimSuffix(name, " toner") name = strings.TrimSuffix(name, " Ink") name = strings.TrimSuffix(name, " ink") name = strings.Replace(name, "-", " ", -1) color.CustomDisplayNameLocalized = cdd.NewLocalizedString(name) } } marker := cdd.Marker{ VendorID: names[i], Type: markerType, Color: color, } level, err := strconv.ParseInt(levels[i], 10, 32) if err != nil { log.Warningf("Failed to parse CUPS marker state %s=%s: %s", names[i], levels[i], err) return nil, nil } if level > 100 { // Lop off extra (proprietary?) bits. level = level & 0x7f } if level < 0 || level > 100 { return nil, nil } var state cdd.MarkerStateType if level > 10 { state = cdd.MarkerStateOK } else { state = cdd.MarkerStateExhausted } level32 := int32(level) markerState := cdd.MarkerStateItem{ VendorID: names[i], State: state, LevelPercent: &level32, } markers = append(markers, marker) states.Item = append(states.Item, markerState) } return &markers, &states }
func TestConvertMarkers(t *testing.T) { log.SetLevel(log.ERROR) m, ms := convertMarkers(nil) if m != nil { t.Logf("expected nil") t.Fail() } if ms != nil { t.Logf("expected nil") t.Fail() } pt := map[string][]string{} m, ms = convertMarkers(pt) if m != nil { t.Logf("expected nil") t.Fail() } if ms != nil { t.Logf("expected nil") t.Fail() } pt = map[string][]string{ attrMarkerNames: []string{"black", "black", "black"}, attrMarkerTypes: []string{"toner", "toner", "ink"}, attrMarkerLevels: []string{"10", "11", "12"}, } m, ms = convertMarkers(pt) if m != nil { t.Logf("expected nil") t.Fail() } if ms != nil { t.Logf("expected nil") t.Fail() } pt = map[string][]string{ attrMarkerNames: []string{"black", "color"}, attrMarkerTypes: []string{"toner", "toner", "ink"}, attrMarkerLevels: []string{"10", "11", "12"}, } m, ms = convertMarkers(pt) if m != nil { t.Logf("expected nil") t.Fail() } if ms != nil { t.Logf("expected nil") t.Fail() } pt = map[string][]string{ attrMarkerNames: []string{"black", "color", "rainbow"}, attrMarkerTypes: []string{"toner", "toner"}, attrMarkerLevels: []string{"10", "11", "12"}, } m, ms = convertMarkers(pt) if m != nil { t.Logf("expected nil") t.Fail() } if ms != nil { t.Logf("expected nil") t.Fail() } pt = map[string][]string{ attrMarkerNames: []string{"black", " Reorder Part #12345", "color", "rainbow", "zebra", "pony"}, attrMarkerTypes: []string{"toner", "toner", "ink", "staples", "water", " Reorder H2O"}, attrMarkerLevels: []string{"10", "11", "12", "208", "13"}, } mExpected := &[]cdd.Marker{ cdd.Marker{ VendorID: "black, Reorder Part #12345", Type: cdd.MarkerToner, Color: &cdd.MarkerColor{Type: cdd.MarkerColorBlack}, }, cdd.Marker{ VendorID: "color", Type: cdd.MarkerToner, Color: &cdd.MarkerColor{Type: cdd.MarkerColorColor}, }, cdd.Marker{ VendorID: "rainbow", Type: cdd.MarkerInk, Color: &cdd.MarkerColor{ Type: cdd.MarkerColorCustom, CustomDisplayNameLocalized: cdd.NewLocalizedString("rainbow"), }, }, cdd.Marker{ VendorID: "zebra", Type: cdd.MarkerStaples, }, } ten, eleven, twelve, eighty := int32(10), int32(11), int32(12), int32(80) msExpected := &cdd.MarkerState{ Item: []cdd.MarkerStateItem{ cdd.MarkerStateItem{ VendorID: "black, Reorder Part #12345", State: cdd.MarkerStateExhausted, LevelPercent: &ten, }, cdd.MarkerStateItem{ VendorID: "color", State: cdd.MarkerStateOK, LevelPercent: &eleven, }, cdd.MarkerStateItem{ VendorID: "rainbow", State: cdd.MarkerStateOK, LevelPercent: &twelve, }, cdd.MarkerStateItem{ VendorID: "zebra", State: cdd.MarkerStateOK, LevelPercent: &eighty, }, }, } m, ms = convertMarkers(pt) if !reflect.DeepEqual(mExpected, m) { e, _ := json.Marshal(mExpected) f, _ := json.Marshal(m) t.Logf("expected\n %s\ngot\n %s", e, f) t.Fail() } if !reflect.DeepEqual(msExpected, ms) { e, _ := json.Marshal(msExpected) f, _ := json.Marshal(ms) t.Logf("expected\n %s\ngot\n %s", e, f) t.Fail() } pt = map[string][]string{ attrMarkerNames: []string{"black", "color", "rainbow", "zebra", "pony"}, attrMarkerTypes: []string{"toner", "toner", "ink", "staples", "water"}, attrMarkerLevels: []string{"10", "11", "12", "208", "13"}, } mExpected = &[]cdd.Marker{ cdd.Marker{ VendorID: "black", Type: cdd.MarkerToner, Color: &cdd.MarkerColor{Type: cdd.MarkerColorBlack}, }, cdd.Marker{ VendorID: "color", Type: cdd.MarkerToner, Color: &cdd.MarkerColor{Type: cdd.MarkerColorColor}, }, cdd.Marker{ VendorID: "rainbow", Type: cdd.MarkerInk, Color: &cdd.MarkerColor{ Type: cdd.MarkerColorCustom, CustomDisplayNameLocalized: cdd.NewLocalizedString("rainbow"), }, }, cdd.Marker{ VendorID: "zebra", Type: cdd.MarkerStaples, }, } msExpected = &cdd.MarkerState{ Item: []cdd.MarkerStateItem{ cdd.MarkerStateItem{ VendorID: "black", State: cdd.MarkerStateExhausted, LevelPercent: &ten, }, cdd.MarkerStateItem{ VendorID: "color", State: cdd.MarkerStateOK, LevelPercent: &eleven, }, cdd.MarkerStateItem{ VendorID: "rainbow", State: cdd.MarkerStateOK, LevelPercent: &twelve, }, cdd.MarkerStateItem{ VendorID: "zebra", State: cdd.MarkerStateOK, LevelPercent: &eighty, }, }, } m, ms = convertMarkers(pt) if !reflect.DeepEqual(mExpected, m) { e, _ := json.Marshal(mExpected) f, _ := json.Marshal(m) t.Logf("expected\n %s\ngot\n %s", e, f) t.Fail() } if !reflect.DeepEqual(msExpected, ms) { e, _ := json.Marshal(msExpected) f, _ := json.Marshal(ms) t.Logf("expected\n %s\ngot\n %s", e, f) t.Fail() } }