package org.cups;
import java.io.*;
import java.util.*;
import java.net.*;
public class Cups
{
static final int REQ_STATE_CREATE_HTTP = 0;
static final int REQ_STATE_WRITE_HTTP_HEADER = 1;
static final int REQ_STATE_WRITE_IPP_HEADER = 2;
static final int REQ_STATE_WRITE_IPP_ATTRS = 3;
static final int REQ_STATE_FINISH_IPP_ATTRS = 4;
static final int REQ_STATE_READ_RESPONSE = 5;
static final int REQ_STATE_DONE = 6;
static final String[] req_state_names =
{ "Create HTTP",
"Write Http Header",
"Write IPP Header",
"Write IPP Attrs",
"Finish IPP Attrs",
"Read Response",
"Done"
};
static final int FILEREQ_STATE_CREATE_HTTP = 0;
static final int FILEREQ_STATE_WRITE_HTTP_HEADER = 1;
static final int FILEREQ_STATE_WRITE_IPP_HEADER = 2;
static final int FILEREQ_STATE_WRITE_IPP_ATTRS = 3;
static final int FILEREQ_STATE_FINISH_IPP_ATTRS = 4;
static final int FILEREQ_STATE_WRITE_FILE_DATA = 5;
static final int FILEREQ_STATE_READ_RESPONSE = 6;
static final int FILEREQ_STATE_DONE = 7;
static final String[] filereq_state_names =
{ "Create HTTP",
"Write Http Header",
"Write IPP Header",
"Write IPP Attrs",
"Finish IPP Attrs",
"Write File Data",
"Read Response",
"Done"
};
IPP ipp; IPPHttp http;
String protocol; String address; int port; String path; String dest; String instance;
boolean encrypt; String user; String passwd;
String site;
int last_error; String error_text;
public Cups()
{
http = null;
ipp = null;
protocol = "http";
address = "localhost";
port = 631;
path = "/";
site = "http://localhost:631/";
dest = "";
instance = "";
user = "";
passwd = "";
encrypt = false;
}
public Cups( URL p_url )
{
http = null;
ipp = null;
protocol = p_url.getProtocol() + "://";
address = p_url.getHost();
port = p_url.getPort();
path = p_url.getPath();
site = protocol + address;
if (port > 0)
site = site + ":" + port;
if (path.length() > 0)
site = site + path;
dest = "";
instance = "";
user = "";
passwd = "";
encrypt = false;
}
public void setProtocol( String p_protocol )
{
protocol = p_protocol;
site = protocol + "://" + address + ":" + port + path;
}
public void setServer( String p_server )
{
address = p_server;
site = protocol + "://" + address + ":" + port + path;
}
public void setPort( int p_port )
{
port = p_port;
site = protocol + "://" + address + ":" + port + path;
}
public void setUser( String p_user )
{
user = p_user;
}
public void setPasswd( String p_passwd )
{
passwd = p_passwd;
}
public void setDest( String p_dest )
{
dest = p_dest;
}
public void setInstance( String p_instance)
{
instance = p_instance;
}
public void setEncrypt( boolean p_encrypt )
{
encrypt = p_encrypt;
}
public boolean getEncrypt()
{
return(encrypt);
}
public void setPath( String p_path )
{
path = p_path;
site = protocol + "://" + address + ":" + port + path;
}
public boolean doRequest(String from) throws IOException
{
return(doRequest());
}
public boolean doRequest() throws IOException
{
IPPAttribute attr;
int state = REQ_STATE_CREATE_HTTP;
int errors = 0;
while (true)
{
switch( state )
{
case REQ_STATE_CREATE_HTTP:
String url_str = site + dest;
try
{
if (user.length() > 0 && passwd.length() > 0)
http = new IPPHttp(url_str, "", user, passwd );
else
http = new IPPHttp(url_str);
state++;
}
catch (IOException e)
{
throw(e);
}
break;
case REQ_STATE_WRITE_HTTP_HEADER:
switch( http.writeHeader( http.path, ipp.sizeInBytes() ))
{
case IPPHttp.HTTP_FORBIDDEN:
case IPPHttp.HTTP_NOT_FOUND:
case IPPHttp.HTTP_BAD_REQUEST:
case IPPHttp.HTTP_METHOD_NOT_ALLOWED:
case IPPHttp.HTTP_PAYMENT_REQUIRED:
case IPPHttp.HTTP_UPGRADE_REQUIRED:
case IPPHttp.HTTP_ERROR:
case IPPHttp.HTTP_UNAUTHORIZED:
errors++;
if (errors < 5)
{
if (!http.reConnect())
{
System.out.println("Could not reConnect(0)!");
return(false);
}
}
else
{
return(false);
}
break;
default: state++;
}
break;
case REQ_STATE_WRITE_IPP_HEADER:
byte[] header = new byte[8];
header[0] = (byte)1;
header[1] = (byte)1;
header[2] = (byte)((ipp.request.operation_id & 0xff00) >> 8);
header[3] = (byte)(ipp.request.operation_id & 0xff);
header[4] = (byte)((ipp.request.request_id & 0xff000000) >> 24);
header[5] = (byte)((ipp.request.request_id & 0xff0000) >> 16);
header[6] = (byte)((ipp.request.request_id & 0xff00) >> 8);
header[7] = (byte)(ipp.request.request_id & 0xff);
http.write( header );
if (http.checkForResponse() >= IPPHttp.HTTP_BAD_REQUEST)
{
errors++;
if (errors < 5)
{
if (http.reConnect())
state = REQ_STATE_WRITE_HTTP_HEADER;
else
{
System.out.println("Could not reConnect(1)\n");
return(false);
}
}
else
{
return(false);
}
}
else state++;
break;
case REQ_STATE_WRITE_IPP_ATTRS:
byte[] bytes;
int sz;
int last_group = -1;
boolean auth_error = false;
for (int i=0; i < ipp.attrs.size() && !auth_error; i++)
{
attr = (IPPAttribute)ipp.attrs.get(i);
sz = attr.sizeInBytes(last_group);
bytes = attr.getBytes(sz,last_group);
last_group = attr.group_tag;
http.write(bytes);
if (http.checkForResponse() >= IPPHttp.HTTP_BAD_REQUEST)
{
errors++;
if (errors < 5)
{
if (!http.reConnect())
{
System.out.println("Could not reConnect(2)");
return(false);
}
state = REQ_STATE_WRITE_HTTP_HEADER;
auth_error = true;
}
else
{
return(false);
}
}
}
if (!auth_error)
state++;
break;
case REQ_STATE_FINISH_IPP_ATTRS:
byte[] footer = new byte[1];
footer[0] = (byte)IPPDefs.TAG_END;
http.write( footer );
if (http.checkForResponse() >= IPPHttp.HTTP_BAD_REQUEST)
{
errors++;
if (errors < 5)
{
if (!http.reConnect())
{
System.out.println("Could not reConnect(3)");
return(false);
}
state = REQ_STATE_WRITE_HTTP_HEADER;
}
else
{
return(false);
}
}
else state++;
break;
case REQ_STATE_READ_RESPONSE:
int read_length;
read_length = http.read_header();
switch( http.status )
{
case IPPHttp.HTTP_OK:
break;
case IPPHttp.HTTP_UNAUTHORIZED:
http.reConnect();
state = REQ_STATE_WRITE_HTTP_HEADER;
errors = 0;
break;
default:
errors++;
if (errors < 5)
{
if (!http.reConnect())
{
System.out.println("Could not reConnect(4)");
return(false);
}
state = REQ_STATE_WRITE_HTTP_HEADER;
}
else
{
System.out.println("Too many errors: " + errors );
return(false);
}
break;
}
if ((read_length > 0) && (state == REQ_STATE_READ_RESPONSE))
{
http.read_buffer = http.read(read_length);
ipp = http.processResponse();
state++;
}
break;
case REQ_STATE_DONE:
http.conn.close();
http = null;
return(true);
}
}
}
public boolean doRequest(File file) throws IOException
{
IPPAttribute attr;
int state = FILEREQ_STATE_CREATE_HTTP;
int errors = 0;
FileInputStream fis = null;
while (true)
{
switch( state )
{
case FILEREQ_STATE_CREATE_HTTP:
String url_str = site + dest;
try
{
if (user.length() > 0 && passwd.length() > 0)
http = new IPPHttp(url_str, "", user, passwd );
else
http = new IPPHttp(url_str);
state++;
}
catch (IOException e)
{
throw(e);
}
break;
case FILEREQ_STATE_WRITE_HTTP_HEADER:
if (fis != null)
{
fis.close();
}
try
{
fis = new FileInputStream(file);
}
catch (IOException e)
{
last_error = -1;
error_text = "Error opening file input stream.";
throw(e);
}
int ippSz = ipp.sizeInBytes() + (int)file.length();
switch( http.writeHeader( http.path, ippSz ))
{
case IPPHttp.HTTP_FORBIDDEN:
case IPPHttp.HTTP_NOT_FOUND:
case IPPHttp.HTTP_BAD_REQUEST:
case IPPHttp.HTTP_METHOD_NOT_ALLOWED:
case IPPHttp.HTTP_PAYMENT_REQUIRED:
case IPPHttp.HTTP_UPGRADE_REQUIRED:
case IPPHttp.HTTP_ERROR:
case IPPHttp.HTTP_UNAUTHORIZED:
errors++;
if (errors < 5)
{
http.reConnect();
}
else
return(false);
break;
default: state++;
}
break;
case FILEREQ_STATE_WRITE_IPP_HEADER:
byte[] header = new byte[8];
header[0] = (byte)1;
header[1] = (byte)1;
header[2] = (byte)((ipp.request.operation_id & 0xff00) >> 8);
header[3] = (byte)(ipp.request.operation_id & 0xff);
header[4] = (byte)((ipp.request.request_id & 0xff000000) >> 24);
header[5] = (byte)((ipp.request.request_id & 0xff0000) >> 16);
header[6] = (byte)((ipp.request.request_id & 0xff00) >> 8);
header[7] = (byte)(ipp.request.request_id & 0xff);
http.write( header );
if (http.checkForResponse() >= IPPHttp.HTTP_BAD_REQUEST)
{
errors++;
if (errors < 5)
{
http.reConnect();
state = FILEREQ_STATE_WRITE_HTTP_HEADER;
}
else
return(false);
}
else state++;
break;
case FILEREQ_STATE_WRITE_IPP_ATTRS:
byte[] bytes;
int sz;
int last_group = -1;
boolean auth_error = false;
for (int i=0; i < ipp.attrs.size() && !auth_error; i++)
{
attr = (IPPAttribute)ipp.attrs.get(i);
sz = attr.sizeInBytes(last_group);
bytes = attr.getBytes(sz,last_group);
last_group = attr.group_tag;
http.write(bytes);
if (http.checkForResponse() >= IPPHttp.HTTP_BAD_REQUEST)
{
errors++;
if (errors < 5)
{
http.reConnect();
state = FILEREQ_STATE_WRITE_HTTP_HEADER;
auth_error = true;
}
else
return(false);
}
}
if (!auth_error)
state++;
break;
case FILEREQ_STATE_FINISH_IPP_ATTRS:
byte[] footer = new byte[1];
footer[0] = (byte)IPPDefs.TAG_END;
http.write( footer );
if (http.checkForResponse() >= IPPHttp.HTTP_BAD_REQUEST)
{
errors++;
if (errors < 5)
{
http.reConnect();
state = FILEREQ_STATE_WRITE_HTTP_HEADER;
}
else
return(false);
}
else state++;
break;
case FILEREQ_STATE_WRITE_FILE_DATA:
int count;
byte[] b = new byte[1024];
while ((state == FILEREQ_STATE_WRITE_FILE_DATA) &&
((count = fis.read(b)) != -1))
{
if (http.checkForResponse() >= IPPHttp.HTTP_BAD_REQUEST)
{
errors++;
if (errors < 5)
{
http.reConnect();
state = FILEREQ_STATE_WRITE_HTTP_HEADER;
}
else
{
return(false);
}
}
else
{
if (count > 0)
http.write( b, count );
}
}
if (state == FILEREQ_STATE_WRITE_FILE_DATA)
{
fis.close();
fis = null;
state++;
}
break;
case FILEREQ_STATE_READ_RESPONSE:
int read_length;
read_length = http.read_header();
switch( http.status )
{
case IPPHttp.HTTP_OK:
break;
case IPPHttp.HTTP_UNAUTHORIZED:
http.reConnect();
state = FILEREQ_STATE_WRITE_HTTP_HEADER;
errors = 0;
break;
default:
errors++;
if (errors < 5)
{
http.reConnect();
state = FILEREQ_STATE_WRITE_HTTP_HEADER;
}
else
{
return(false);
}
break;
}
if ((read_length > 0) && (state == FILEREQ_STATE_READ_RESPONSE))
{
http.read_buffer = http.read(read_length);
ipp = http.processResponse();
state++;
}
break;
case FILEREQ_STATE_DONE:
http.conn.close();
http = null;
return(true);
}
}
}
public CupsJob[] cupsGetJobs( boolean showMyJobs, boolean showCompleted )
throws IOException
{
IPPAttribute a;
String req_attrs[] =
{
"job-id",
"job-priority",
"job-k-octets",
"job-state",
"time-at-completed",
"time-at-creation",
"time-at-processing",
"job-printer-uri",
"document-format",
"job-name",
"job-originating-user-name"
};
ipp = new IPP();
ipp.request = new IPPRequest( 1, (short)IPPDefs.GET_JOBS );
a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_CHARSET,
"attributes-charset" );
a.addString( "", "iso-8859-1" );
ipp.addAttribute(a);
a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_LANGUAGE,
"attributes-natural-language" );
a.addString( "", "en" );
ipp.addAttribute(a);
a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_URI,
"printer-uri" );
if (site != null)
a.addString( "", site );
else
a.addString( "", "ipp://localhost/jobs" ); ipp.addAttribute(a);
a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_NAME,
"requesting-user-name" );
a.addString( "", "root" );
ipp.addAttribute(a);
if (showMyJobs)
{
a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_BOOLEAN,
"my-jobs" );
a.addBoolean( true );
ipp.addAttribute(a);
}
if (showCompleted)
{
a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_KEYWORD,
"which-jobs" );
a.addString( "", "completed" );
ipp.addAttribute(a);
}
if (doRequest("cupsGetJobs"))
{
int i = 0;
int group_tag = -1;
while ((i < ipp.attrs.size()) && (group_tag != IPPDefs.TAG_JOB))
{
a = (IPPAttribute)ipp.attrs.get(i);
group_tag = a.group_tag;
if (group_tag != IPPDefs.TAG_JOB)
i++;
}
int num_jobs = 0;
group_tag = IPPDefs.TAG_JOB;
while ((i < ipp.attrs.size()) && (group_tag == IPPDefs.TAG_JOB))
{
a = (IPPAttribute)ipp.attrs.get(i++);
if ((a != null) && (a.name.compareTo("job-id") == 0))
num_jobs++;
}
if (num_jobs < 1)
return(null);
int n = 0;
CupsJob[] jobs = new CupsJob[num_jobs];
for (n=0; n < num_jobs; n++)
{
jobs[n] = new CupsJob();
}
group_tag = -1;
i = 0;
while ((i < ipp.attrs.size()) && (group_tag != IPPDefs.TAG_JOB))
{
a = (IPPAttribute)ipp.attrs.get(i);
group_tag = a.group_tag;
if (group_tag != IPPDefs.TAG_JOB)
i++;
}
n = 0;
for (;i < ipp.attrs.size(); i++)
{
a = (IPPAttribute)ipp.attrs.get(i);
if (a.group_tag == IPPDefs.TAG_ZERO)
{
n++;
continue;
}
else
{
try
{
jobs[n].updateAttribute( a );
}
catch (ArrayIndexOutOfBoundsException e)
{
return(jobs);
}
}
}
return( jobs );
}
return(null);
}
public String[] cupsGetPrinters()
throws IOException
{
IPPAttribute a;
ipp = new IPP();
ipp.request = new IPPRequest( 1, (short)IPPDefs.CUPS_GET_PRINTERS );
a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_CHARSET,
"attributes-charset" );
a.addString( "", "iso-8859-1" );
ipp.addAttribute(a);
a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_LANGUAGE,
"attributes-natural-language" );
a.addString( "", "en" );
ipp.addAttribute(a);
if (doRequest("cupsGetPrinters"))
{
int num_printers = 0;
for (int i=0; i < ipp.attrs.size(); i++)
{
a = (IPPAttribute)ipp.attrs.get(i);
if ((a.name.compareTo("printer-name") == 0) &&
(a.value_tag == IPPDefs.TAG_NAME))
{
num_printers++;
}
}
if (num_printers < 1)
return(null);
String[] printers = new String[num_printers];
IPPValue val;
int n = 0;
for (int i=0; i < ipp.attrs.size(); i++)
{
a = (IPPAttribute)ipp.attrs.get(i);
if (a.group_tag < 2)
continue;
if ((a.name.compareTo("printer-name") == 0) &&
(a.value_tag == IPPDefs.TAG_NAME))
{
val = (IPPValue)a.values.get(0);
if (val != null)
{
printers[n] = val.text;
n++;
}
}
}
return( printers );
}
return(null);
}
public String cupsGetDefault()
throws IOException
{
IPPAttribute a;
ipp = new IPP();
ipp.request = new IPPRequest( 1, (short)IPPDefs.CUPS_GET_DEFAULT);
a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_CHARSET,
"attributes-charset" );
a.addString( "", "iso-8859-1" );
ipp.addAttribute(a);
a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_LANGUAGE,
"attributes-natural-language" );
a.addString( "", "en" );
ipp.addAttribute(a);
if (doRequest("cupsGetDefault"))
{
if ((ipp == null) || (ipp.attrs == null))
return(null);
int num_printers = 0;
for (int i=0; i < ipp.attrs.size(); i++)
{
a = (IPPAttribute)ipp.attrs.get(i);
if ((a.name.compareTo("printer-name") == 0) &&
(a.value_tag == IPPDefs.TAG_NAME))
{
IPPValue val = (IPPValue)a.values.get(0);
if (val != null)
{
return( val.text );
}
}
}
}
return(null);
}
public List cupsGetPrinterAttributes( String printer_name )
throws IOException
{
IPPAttribute a;
ipp = new IPP();
ipp.request = new IPPRequest( 1, (short)IPPDefs.GET_PRINTER_ATTRIBUTES );
a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_CHARSET,
"attributes-charset" );
a.addString( "", "iso-8859-1" );
ipp.addAttribute(a);
a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_LANGUAGE,
"attributes-natural-language" );
a.addString( "", "en" );
ipp.addAttribute(a);
a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_URI,
"printer-uri" );
a.addString( "", site + "/printers/" + printer_name );
ipp.addAttribute(a);
if (doRequest("cupsGetPrinterAttributes"))
{
return(ipp.attrs);
}
return(null);
}
public CupsJob cupsPrintFile( String p_filename,
IPPAttribute p_attrs[] )
throws IOException
{
CupsJob job;
IPPAttribute a;
File file;
file = new File(p_filename);
if (!file.exists())
{
last_error = -1;
error_text = "File does not exist.";
return(null);
}
if (!file.canRead())
{
last_error = -1;
error_text = "File cannot be read.";
return(null);
}
ipp = new IPP();
ipp.request = new IPPRequest( 1, (short)IPPDefs.PRINT_JOB );
a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_CHARSET,
"attributes-charset" );
a.addString( "", "iso-8859-1" );
ipp.addAttribute(a);
a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_LANGUAGE,
"attributes-natural-language" );
a.addString( "", "en" );
ipp.addAttribute(a);
a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_URI,
"printer-uri" );
a.addString( "", site + dest );
ipp.addAttribute(a);
a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_NAME,
"job-name" );
a.addString( "", file.getName() );
ipp.addAttribute(a);
if (p_attrs != null)
{
for (int i=0; i < p_attrs.length; i++)
{
a = p_attrs[i];
ipp.addAttribute(a);
}
}
if (doRequest(file))
{
job = new CupsJob();
for (int i=0; i < ipp.attrs.size(); i++)
{
a = (IPPAttribute)ipp.attrs.get(i);
job.updateAttribute(a);
}
return(job);
}
return(null);
}
public int cupsCancelJob( String printer_name,
int p_job_id,
String p_user_name )
throws IOException
{
IPPAttribute a;
ipp = new IPP();
ipp.request = new IPPRequest( 1, (short)IPPDefs.CANCEL_JOB );
a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_CHARSET,
"attributes-charset" );
a.addString( "", "iso-8859-1" );
ipp.addAttribute(a);
a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_LANGUAGE,
"attributes-natural-language" );
a.addString( "", "en" );
ipp.addAttribute(a);
a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_URI,
"printer-uri" );
a.addString( "", site + dest );
ipp.addAttribute(a);
a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_INTEGER,
"job-id" );
a.addInteger( p_job_id );
ipp.addAttribute(a);
a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_NAME,
"requesting-user-name" );
a.addString( "", p_user_name );
ipp.addAttribute(a);
if (doRequest("cupsCancelJob"))
{
for (int i=0; i < ipp.attrs.size(); i++)
{
a = (IPPAttribute)ipp.attrs.get(i);
a.dump_values();
}
return(0);
}
return(0);
}
public List cupsGetPrinterStatus(String printer_name)
throws IOException
{
IPPAttribute a;
String p_uri;
ipp = new IPP();
ipp.request = new IPPRequest(1,(short)IPPDefs.GET_PRINTER_ATTRIBUTES);
a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_CHARSET,
"attributes-charset" );
a.addString( "", "iso-8859-1" );
ipp.addAttribute(a);
a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_LANGUAGE,
"attributes-natural-language" );
a.addString( "", "en" );
ipp.addAttribute(a);
a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_URI,
"printer-uri" );
p_uri = "ipp://" + address + ":" +
port + "/printers/" + printer_name;
a.addString( "", p_uri );
ipp.addAttribute(a);
if (doRequest("cupsGetPrinterStatus"))
{
return(ipp.attrs);
}
return(null);
}
}