Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions js/qz-tray.js
Original file line number Diff line number Diff line change
Expand Up @@ -1369,6 +1369,39 @@ var qz = (function() {
return _qz.websocket.dataPromise('printers.find', { query: query }, signature, signingTimestamp);
},

/**
* @param {Object} [server] Server object returned from qz.printers.addServer(...)
* @param {string} [query] Search for a specific printer. All printers are returned if not provided.
*
* @returns {Promise<Array<Object>|Object|Error>} The matched printer object if <code>query</code> is provided.
* Otherwise an array of printer objects names found on the remote system.
*
* @since 2.2.6
* @see qz.printers.addServer
*
* @memberof qz.printers
*/
findRemote: function(server, query) {
return _qz.websocket.dataPromise('printers.findRemote', { server: server, query: query });
},

/**
* @param {Object} [options]
* @param {string} [options.uri=null] Address of the remote ipp server. Defaults to localhost if not provided.
* @param {string} [options.username=null] Username for ipp connection
* @param {string} [options.password=null] Password for ipp connection
*
*
* @returns {Promise<Object<{type: string, uuid: string, uri: string}>|Error>} Remote server connection info
*
* @since 2.2.6
*
* @memberof qz.printers
*/
addServer: function(options) {
return _qz.websocket.dataPromise('printers.addServer', options);
},

/**
* Provides a list, with additional information, for each printer available to QZ.
*
Expand Down
Binary file added lib/communication/ipp-client-3.2.jar
Binary file not shown.
Binary file added lib/kotlin-stdlib-2.0.0.jar
Binary file not shown.
4 changes: 2 additions & 2 deletions src/qz/common/SecurityInfo.java
Original file line number Diff line number Diff line change
Expand Up @@ -107,12 +107,12 @@ public static SortedMap<String,String> getLibVersions() {
// Fallback to maven manifest information
HashMap<String,String> mavenVersions = getMavenVersions();

String[] mavenLibs = {"jetty-servlet", "jetty-io", "websocket-common",
String[] mavenLibs = {"jetty-servlet", "jetty-io", "websocket-common", "kotlin-stdlib",
"usb4java-javax", "java-semver", "commons-pool2",
"websocket-server", "jettison", "commons-codec", "log4j-api", "log4j-core",
"websocket-servlet", "jetty-http", "commons-lang3", "javax-websocket-server-impl",
"javax.servlet-api", "hid4java", "usb4java", "websocket-api", "jetty-util", "websocket-client",
"javax.websocket-api", "commons-io", "jetty-security"};
"javax.websocket-api", "commons-io", "jetty-security", "ipp-client-kotlin"};

for(String lib : mavenLibs) {
libVersions.put(lib, mavenVersions.get(lib));
Expand Down
31 changes: 31 additions & 0 deletions src/qz/printer/PrintOutput.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@

import org.codehaus.jettison.json.JSONException;
import org.codehaus.jettison.json.JSONObject;
import qz.printer.action.ipp.Ipp;
import qz.printer.info.NativePrinter;
import qz.utils.FileUtilities;

import javax.print.PrintService;
import javax.print.attribute.standard.Media;
import java.io.File;
import java.net.URI;
import java.nio.file.Paths;
import java.util.UUID;

public class PrintOutput {

Expand All @@ -17,6 +20,9 @@ public class PrintOutput {
private File file = null;

private String host = null;
private UUID serverUuid = null;
private URI printerUri = null;
private Ipp.ServerEntry server;
private int port = -1;


Expand All @@ -30,6 +36,12 @@ public PrintOutput(JSONObject configPrinter) throws JSONException, IllegalArgume
}
}

if (configPrinter.has("serverUuid")) {
serverUuid = UUID.fromString(configPrinter.getString("serverUuid"));
//todo basic error handeling. make this error helpful
printerUri = URI.create(configPrinter.getString("uri"));
}

if (configPrinter.has("file")) {
String filename = configPrinter.getString("file");
if (!FileUtilities.isGoodExtension(Paths.get(filename))) {
Expand Down Expand Up @@ -77,10 +89,22 @@ public boolean isSetHost() {
return host != null;
}

public boolean isRemoteIpp() {
return serverUuid != null;
}

public String getHost() {
return host;
}

public UUID getServerUuid() {
return serverUuid;
}

public URI getPrinterUri() {
return printerUri;
}

public int getPort() {
return port;
}
Expand All @@ -89,4 +113,11 @@ public Media[] getSupportedMedia() {
return (Media[])getPrintService().getSupportedAttributeValues(Media.class, null, null);
}

public Ipp.ServerEntry getServer() {
return server;
}

public void setServer(Ipp.ServerEntry server) {
this.server = server;
}
}
85 changes: 85 additions & 0 deletions src/qz/printer/action/PrintIPP.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package qz.printer.action;

import de.gmuth.ipp.attributes.TemplateAttributes;
import de.gmuth.ipp.client.CupsClient;
import de.gmuth.ipp.client.IppClient;
import de.gmuth.ipp.client.IppJob;
import de.gmuth.ipp.client.IppPrinter;
import org.codehaus.jettison.json.JSONArray;
import org.codehaus.jettison.json.JSONException;
import qz.printer.action.ipp.Ipp;
import qz.printer.PrintOptions;
import qz.printer.PrintOutput;
import qz.utils.PrintingUtilities;

import javax.print.PrintException;
import java.awt.print.PrinterException;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.nio.charset.StandardCharsets;

public class PrintIPP implements PrintProcessor{
private JSONArray data;
@Override
public PrintingUtilities.Format getFormat() {
return PrintingUtilities.Format.IPP;
}

@Override
public void parseData(JSONArray printData, PrintOptions options) throws UnsupportedOperationException {
data = printData;
}

@Override
public void print(PrintOutput output, PrintOptions options) throws PrintException, PrinterException {
URI requestedUri = output.getPrinterUri();

IppClient ippClient = new IppClient();
Ipp.ServerEntry serverEntry = output.getServer();
CupsClient cupsClient = new CupsClient(serverEntry.serverUri, ippClient);

// requestedUri is user provided, we must make sure it belongs to the claimed server
if(!serverEntry.serverUri.getScheme().equals(requestedUri.getScheme()) ||
!serverEntry.serverUri.getAuthority().equals(requestedUri.getAuthority())) {
throw new PrinterException(serverEntry.serverUri + " Is not a printer of the server " + requestedUri);

}

//todo: this would also be a good time to raise a prompt

IppPrinter ippPrinter = new IppPrinter(requestedUri.toString());

// todo: match this to PrintServiceMatcher.getPrintersJSON syntax
if (!serverEntry.uname.isEmpty() && !serverEntry.pass.isEmpty()) {
cupsClient.basicAuth(serverEntry.uname, serverEntry.pass);
}

// todo: for testing, assume all data is just plaintext. There are a lot of things to discuss about filetype and format.

IppJob job = ippPrinter.createJob(TemplateAttributes.jobName("test"));
String dataString = null;
try {
dataString = data.getJSONObject(0).getString("data");
}
catch(JSONException e) {
throw new RuntimeException(e);
}

byte[] dataBytes = dataString.getBytes(StandardCharsets.UTF_8);
try (InputStream in = new ByteArrayInputStream(dataBytes)) {
job.sendDocument(in);
}
catch(IOException e) {
throw new RuntimeException(e);
}
// todo: I assume we wait?
job.waitForTermination();
}

@Override
public void cleanup() {

}
}
1 change: 1 addition & 0 deletions src/qz/printer/action/ProcessorFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ public PooledObject<PrintProcessor> makeObject(PrintingUtilities.Format key) thr
case IMAGE: processor = new PrintImage(); break;
case PDF: processor = new PrintPDF(); break;
case DIRECT: processor = new PrintDirect(); break;
case IPP: processor = new PrintIPP(); break;
case COMMAND: default: processor = new PrintRaw(); break;
}

Expand Down
Loading
Loading