// GetPrinters gets all CUPS printers found on the CUPS server.
func (c *CUPS) GetPrinters() ([]lib.Printer, error) {
	pa := C.newArrayOfStrings(C.int(len(c.printerAttributes)))
	defer C.freeStringArrayAndStrings(pa, C.int(len(c.printerAttributes)))
	for i, a := range c.printerAttributes {
		C.setStringArrayValue(pa, C.int(i), C.CString(a))
	}

	response, err := c.cc.getPrinters(pa, C.int(len(c.printerAttributes)))
	if err != nil {
		return nil, err
	}

	// cupsDoRequest() returns ipp_t pointer which needs explicit free.
	defer C.ippDelete(response)

	if C.getIPPRequestStatusCode(response) == C.IPP_STATUS_ERROR_NOT_FOUND {
		// Normal error when there are no printers.
		return make([]lib.Printer, 0), nil
	}

	printers := c.responseToPrinters(response)
	printers = lib.FilterBlacklistPrinters(printers, c.printerBlacklist)
	printers = lib.FilterWhitelistPrinters(printers, c.printerWhitelist)

	if c.ignoreRawPrinters {
		printers = filterRawPrinters(printers)
	}
	if c.ignoreClassPrinters {
		printers = filterClassPrinters(printers)
	}
	printers = c.addPPDDescriptionToPrinters(printers)
	printers = addStaticDescriptionToPrinters(printers)
	printers = c.addSystemTagsToPrinters(printers)

	return printers, 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
}