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
}
예제 #12
0
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
}
예제 #13
0
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
}
예제 #14
0
// 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()
	}
}