xref: /aosp_15_r20/external/libcups/cups/testclient.c (revision 5e7646d21f1134fb0638875d812ef646c12ab91e)
1*5e7646d2SAndroid Build Coastguard Worker /*
2*5e7646d2SAndroid Build Coastguard Worker  * Simulated client test program for CUPS.
3*5e7646d2SAndroid Build Coastguard Worker  *
4*5e7646d2SAndroid Build Coastguard Worker  * Copyright © 2017-2019 by Apple Inc.
5*5e7646d2SAndroid Build Coastguard Worker  *
6*5e7646d2SAndroid Build Coastguard Worker  * Licensed under Apache License v2.0.  See the file "LICENSE" for more
7*5e7646d2SAndroid Build Coastguard Worker  * information.
8*5e7646d2SAndroid Build Coastguard Worker  */
9*5e7646d2SAndroid Build Coastguard Worker 
10*5e7646d2SAndroid Build Coastguard Worker /*
11*5e7646d2SAndroid Build Coastguard Worker  * Include necessary headers...
12*5e7646d2SAndroid Build Coastguard Worker  */
13*5e7646d2SAndroid Build Coastguard Worker 
14*5e7646d2SAndroid Build Coastguard Worker #include <config.h>
15*5e7646d2SAndroid Build Coastguard Worker #include <stdio.h>
16*5e7646d2SAndroid Build Coastguard Worker #include <stdlib.h>
17*5e7646d2SAndroid Build Coastguard Worker #include <cups/cups.h>
18*5e7646d2SAndroid Build Coastguard Worker #include <cups/raster.h>
19*5e7646d2SAndroid Build Coastguard Worker #include <cups/string-private.h>
20*5e7646d2SAndroid Build Coastguard Worker #include <cups/thread-private.h>
21*5e7646d2SAndroid Build Coastguard Worker 
22*5e7646d2SAndroid Build Coastguard Worker 
23*5e7646d2SAndroid Build Coastguard Worker /*
24*5e7646d2SAndroid Build Coastguard Worker  * Constants...
25*5e7646d2SAndroid Build Coastguard Worker  */
26*5e7646d2SAndroid Build Coastguard Worker 
27*5e7646d2SAndroid Build Coastguard Worker #define MAX_CLIENTS	100		/* Maximum number of client threads */
28*5e7646d2SAndroid Build Coastguard Worker 
29*5e7646d2SAndroid Build Coastguard Worker 
30*5e7646d2SAndroid Build Coastguard Worker /*
31*5e7646d2SAndroid Build Coastguard Worker  * Local types...
32*5e7646d2SAndroid Build Coastguard Worker  */
33*5e7646d2SAndroid Build Coastguard Worker 
34*5e7646d2SAndroid Build Coastguard Worker typedef struct _client_data_s
35*5e7646d2SAndroid Build Coastguard Worker {
36*5e7646d2SAndroid Build Coastguard Worker   const char		*uri,		/* Printer URI */
37*5e7646d2SAndroid Build Coastguard Worker 			*hostname,	/* Hostname */
38*5e7646d2SAndroid Build Coastguard Worker 			*user,		/* Username */
39*5e7646d2SAndroid Build Coastguard Worker 			*resource;	/* Resource path */
40*5e7646d2SAndroid Build Coastguard Worker   int			port;		/* Port number */
41*5e7646d2SAndroid Build Coastguard Worker   http_encryption_t	encryption;	/* Use encryption? */
42*5e7646d2SAndroid Build Coastguard Worker   const char		*docfile,	/* Document file */
43*5e7646d2SAndroid Build Coastguard Worker 			*docformat;	/* Document format */
44*5e7646d2SAndroid Build Coastguard Worker   int			grayscale,	/* Force grayscale? */
45*5e7646d2SAndroid Build Coastguard Worker 			keepfile;	/* Keep temporary file? */
46*5e7646d2SAndroid Build Coastguard Worker   ipp_pstate_t		printer_state;	/* Current printer state */
47*5e7646d2SAndroid Build Coastguard Worker   char			printer_state_reasons[1024];
48*5e7646d2SAndroid Build Coastguard Worker 					/* Current printer-state-reasons */
49*5e7646d2SAndroid Build Coastguard Worker   int			job_id; 	/* Job ID for submitted job */
50*5e7646d2SAndroid Build Coastguard Worker   ipp_jstate_t		job_state;	/* Current job state */
51*5e7646d2SAndroid Build Coastguard Worker   char			job_state_reasons[1024];
52*5e7646d2SAndroid Build Coastguard Worker 					/* Current job-state-reasons */
53*5e7646d2SAndroid Build Coastguard Worker } _client_data_t;
54*5e7646d2SAndroid Build Coastguard Worker 
55*5e7646d2SAndroid Build Coastguard Worker 
56*5e7646d2SAndroid Build Coastguard Worker /*
57*5e7646d2SAndroid Build Coastguard Worker  * Local globals...
58*5e7646d2SAndroid Build Coastguard Worker  */
59*5e7646d2SAndroid Build Coastguard Worker 
60*5e7646d2SAndroid Build Coastguard Worker static int		client_count = 0;
61*5e7646d2SAndroid Build Coastguard Worker static _cups_mutex_t	client_mutex = _CUPS_MUTEX_INITIALIZER;
62*5e7646d2SAndroid Build Coastguard Worker static int		verbosity = 0;
63*5e7646d2SAndroid Build Coastguard Worker 
64*5e7646d2SAndroid Build Coastguard Worker 
65*5e7646d2SAndroid Build Coastguard Worker /*
66*5e7646d2SAndroid Build Coastguard Worker  * Local functions...
67*5e7646d2SAndroid Build Coastguard Worker  */
68*5e7646d2SAndroid Build Coastguard Worker 
69*5e7646d2SAndroid Build Coastguard Worker static const char	*make_raster_file(ipp_t *response, int grayscale, char *tempname, size_t tempsize, const char **format);
70*5e7646d2SAndroid Build Coastguard Worker static void		*monitor_printer(_client_data_t *data);
71*5e7646d2SAndroid Build Coastguard Worker static void		*run_client(_client_data_t *data);
72*5e7646d2SAndroid Build Coastguard Worker static void		show_attributes(const char *title, int request, ipp_t *ipp);
73*5e7646d2SAndroid Build Coastguard Worker static void		show_capabilities(ipp_t *response);
74*5e7646d2SAndroid Build Coastguard Worker static void		usage(void);
75*5e7646d2SAndroid Build Coastguard Worker 
76*5e7646d2SAndroid Build Coastguard Worker 
77*5e7646d2SAndroid Build Coastguard Worker /*
78*5e7646d2SAndroid Build Coastguard Worker  * 'main()' - Main entry.
79*5e7646d2SAndroid Build Coastguard Worker  */
80*5e7646d2SAndroid Build Coastguard Worker 
81*5e7646d2SAndroid Build Coastguard Worker int					/* O - Exit status */
main(int argc,char * argv[])82*5e7646d2SAndroid Build Coastguard Worker main(int  argc,				/* I - Number of command-line arguments */
83*5e7646d2SAndroid Build Coastguard Worker      char *argv[])			/* I - Command-line arguments */
84*5e7646d2SAndroid Build Coastguard Worker {
85*5e7646d2SAndroid Build Coastguard Worker   int			i;		/* Looping var */
86*5e7646d2SAndroid Build Coastguard Worker   const char		*opt;		/* Current option */
87*5e7646d2SAndroid Build Coastguard Worker   int			num_clients = 0,/* Number of clients to simulate */
88*5e7646d2SAndroid Build Coastguard Worker 			clients_started = 0;
89*5e7646d2SAndroid Build Coastguard Worker 					/* Number of clients that have been started */
90*5e7646d2SAndroid Build Coastguard Worker   char			scheme[32],     /* URI scheme */
91*5e7646d2SAndroid Build Coastguard Worker 			userpass[256],  /* Username:password */
92*5e7646d2SAndroid Build Coastguard Worker 			hostname[256],  /* Hostname */
93*5e7646d2SAndroid Build Coastguard Worker 			resource[256];  /* Resource path */
94*5e7646d2SAndroid Build Coastguard Worker   _client_data_t	data;		/* Client data */
95*5e7646d2SAndroid Build Coastguard Worker 
96*5e7646d2SAndroid Build Coastguard Worker 
97*5e7646d2SAndroid Build Coastguard Worker  /*
98*5e7646d2SAndroid Build Coastguard Worker   * Parse command-line options...
99*5e7646d2SAndroid Build Coastguard Worker   */
100*5e7646d2SAndroid Build Coastguard Worker 
101*5e7646d2SAndroid Build Coastguard Worker   if (argc == 1)
102*5e7646d2SAndroid Build Coastguard Worker     return (0);
103*5e7646d2SAndroid Build Coastguard Worker 
104*5e7646d2SAndroid Build Coastguard Worker   memset(&data, 0, sizeof(data));
105*5e7646d2SAndroid Build Coastguard Worker 
106*5e7646d2SAndroid Build Coastguard Worker   for (i = 1; i < argc; i ++)
107*5e7646d2SAndroid Build Coastguard Worker   {
108*5e7646d2SAndroid Build Coastguard Worker     if (argv[i][0] == '-')
109*5e7646d2SAndroid Build Coastguard Worker     {
110*5e7646d2SAndroid Build Coastguard Worker       for (opt = argv[i] + 1; *opt; opt ++)
111*5e7646d2SAndroid Build Coastguard Worker       {
112*5e7646d2SAndroid Build Coastguard Worker         switch (*opt)
113*5e7646d2SAndroid Build Coastguard Worker         {
114*5e7646d2SAndroid Build Coastguard Worker           case 'c' : /* -c num-clients */
115*5e7646d2SAndroid Build Coastguard Worker               if (num_clients)
116*5e7646d2SAndroid Build Coastguard Worker               {
117*5e7646d2SAndroid Build Coastguard Worker                 puts("Number of clients can only be specified once.");
118*5e7646d2SAndroid Build Coastguard Worker                 usage();
119*5e7646d2SAndroid Build Coastguard Worker                 return (1);
120*5e7646d2SAndroid Build Coastguard Worker               }
121*5e7646d2SAndroid Build Coastguard Worker 
122*5e7646d2SAndroid Build Coastguard Worker               i ++;
123*5e7646d2SAndroid Build Coastguard Worker               if (i >= argc)
124*5e7646d2SAndroid Build Coastguard Worker               {
125*5e7646d2SAndroid Build Coastguard Worker                 puts("Expected client count after '-c'.");
126*5e7646d2SAndroid Build Coastguard Worker                 usage();
127*5e7646d2SAndroid Build Coastguard Worker                 return (1);
128*5e7646d2SAndroid Build Coastguard Worker               }
129*5e7646d2SAndroid Build Coastguard Worker 
130*5e7646d2SAndroid Build Coastguard Worker               if ((num_clients = atoi(argv[i])) < 1)
131*5e7646d2SAndroid Build Coastguard Worker               {
132*5e7646d2SAndroid Build Coastguard Worker                 puts("Number of clients must be one or more.");
133*5e7646d2SAndroid Build Coastguard Worker                 usage();
134*5e7646d2SAndroid Build Coastguard Worker                 return (1);
135*5e7646d2SAndroid Build Coastguard Worker               }
136*5e7646d2SAndroid Build Coastguard Worker               break;
137*5e7646d2SAndroid Build Coastguard Worker 
138*5e7646d2SAndroid Build Coastguard Worker           case 'd' : /* -d document-format */
139*5e7646d2SAndroid Build Coastguard Worker               if (data.docformat)
140*5e7646d2SAndroid Build Coastguard Worker               {
141*5e7646d2SAndroid Build Coastguard Worker                 puts("Document format can only be specified once.");
142*5e7646d2SAndroid Build Coastguard Worker                 usage();
143*5e7646d2SAndroid Build Coastguard Worker                 return (1);
144*5e7646d2SAndroid Build Coastguard Worker               }
145*5e7646d2SAndroid Build Coastguard Worker 
146*5e7646d2SAndroid Build Coastguard Worker               i ++;
147*5e7646d2SAndroid Build Coastguard Worker               if (i >= argc)
148*5e7646d2SAndroid Build Coastguard Worker               {
149*5e7646d2SAndroid Build Coastguard Worker                 puts("Expected document format after '-d'.");
150*5e7646d2SAndroid Build Coastguard Worker                 usage();
151*5e7646d2SAndroid Build Coastguard Worker                 return (1);
152*5e7646d2SAndroid Build Coastguard Worker               }
153*5e7646d2SAndroid Build Coastguard Worker 
154*5e7646d2SAndroid Build Coastguard Worker               data.docformat = argv[i];
155*5e7646d2SAndroid Build Coastguard Worker               break;
156*5e7646d2SAndroid Build Coastguard Worker 
157*5e7646d2SAndroid Build Coastguard Worker           case 'f' : /* -f print-file */
158*5e7646d2SAndroid Build Coastguard Worker               if (data.docfile)
159*5e7646d2SAndroid Build Coastguard Worker               {
160*5e7646d2SAndroid Build Coastguard Worker                 puts("Print file can only be specified once.");
161*5e7646d2SAndroid Build Coastguard Worker                 usage();
162*5e7646d2SAndroid Build Coastguard Worker                 return (1);
163*5e7646d2SAndroid Build Coastguard Worker               }
164*5e7646d2SAndroid Build Coastguard Worker 
165*5e7646d2SAndroid Build Coastguard Worker               i ++;
166*5e7646d2SAndroid Build Coastguard Worker               if (i >= argc)
167*5e7646d2SAndroid Build Coastguard Worker               {
168*5e7646d2SAndroid Build Coastguard Worker                 puts("Expected print file after '-f'.");
169*5e7646d2SAndroid Build Coastguard Worker                 usage();
170*5e7646d2SAndroid Build Coastguard Worker                 return (1);
171*5e7646d2SAndroid Build Coastguard Worker               }
172*5e7646d2SAndroid Build Coastguard Worker 
173*5e7646d2SAndroid Build Coastguard Worker               data.docfile = argv[i];
174*5e7646d2SAndroid Build Coastguard Worker               break;
175*5e7646d2SAndroid Build Coastguard Worker 
176*5e7646d2SAndroid Build Coastguard Worker           case 'g' :
177*5e7646d2SAndroid Build Coastguard Worker               data.grayscale = 1;
178*5e7646d2SAndroid Build Coastguard Worker               break;
179*5e7646d2SAndroid Build Coastguard Worker 
180*5e7646d2SAndroid Build Coastguard Worker           case 'k' :
181*5e7646d2SAndroid Build Coastguard Worker               data.keepfile = 1;
182*5e7646d2SAndroid Build Coastguard Worker               break;
183*5e7646d2SAndroid Build Coastguard Worker 
184*5e7646d2SAndroid Build Coastguard Worker           case 'v' :
185*5e7646d2SAndroid Build Coastguard Worker               verbosity ++;
186*5e7646d2SAndroid Build Coastguard Worker               break;
187*5e7646d2SAndroid Build Coastguard Worker 
188*5e7646d2SAndroid Build Coastguard Worker           default :
189*5e7646d2SAndroid Build Coastguard Worker               printf("Unknown option '-%c'.\n", *opt);
190*5e7646d2SAndroid Build Coastguard Worker               usage();
191*5e7646d2SAndroid Build Coastguard Worker               return (1);
192*5e7646d2SAndroid Build Coastguard Worker         }
193*5e7646d2SAndroid Build Coastguard Worker       }
194*5e7646d2SAndroid Build Coastguard Worker     }
195*5e7646d2SAndroid Build Coastguard Worker     else if (data.uri || (strncmp(argv[i], "ipp://", 6) && strncmp(argv[i], "ipps://", 7)))
196*5e7646d2SAndroid Build Coastguard Worker     {
197*5e7646d2SAndroid Build Coastguard Worker       printf("Unknown command-line argument '%s'.\n", argv[i]);
198*5e7646d2SAndroid Build Coastguard Worker       usage();
199*5e7646d2SAndroid Build Coastguard Worker       return (1);
200*5e7646d2SAndroid Build Coastguard Worker     }
201*5e7646d2SAndroid Build Coastguard Worker     else
202*5e7646d2SAndroid Build Coastguard Worker       data.uri = argv[i];
203*5e7646d2SAndroid Build Coastguard Worker   }
204*5e7646d2SAndroid Build Coastguard Worker 
205*5e7646d2SAndroid Build Coastguard Worker  /*
206*5e7646d2SAndroid Build Coastguard Worker   * Make sure we have everything we need.
207*5e7646d2SAndroid Build Coastguard Worker   */
208*5e7646d2SAndroid Build Coastguard Worker 
209*5e7646d2SAndroid Build Coastguard Worker   if (!data.uri)
210*5e7646d2SAndroid Build Coastguard Worker   {
211*5e7646d2SAndroid Build Coastguard Worker     puts("Expected printer URI.");
212*5e7646d2SAndroid Build Coastguard Worker     usage();
213*5e7646d2SAndroid Build Coastguard Worker     return (1);
214*5e7646d2SAndroid Build Coastguard Worker   }
215*5e7646d2SAndroid Build Coastguard Worker 
216*5e7646d2SAndroid Build Coastguard Worker   if (num_clients < 1)
217*5e7646d2SAndroid Build Coastguard Worker     num_clients = 1;
218*5e7646d2SAndroid Build Coastguard Worker 
219*5e7646d2SAndroid Build Coastguard Worker  /*
220*5e7646d2SAndroid Build Coastguard Worker   * Connect to the printer...
221*5e7646d2SAndroid Build Coastguard Worker   */
222*5e7646d2SAndroid Build Coastguard Worker 
223*5e7646d2SAndroid Build Coastguard Worker   if (httpSeparateURI(HTTP_URI_CODING_ALL, data.uri, scheme, sizeof(scheme), userpass, sizeof(userpass), hostname, sizeof(hostname), &data.port, resource, sizeof(resource)) < HTTP_URI_STATUS_OK)
224*5e7646d2SAndroid Build Coastguard Worker   {
225*5e7646d2SAndroid Build Coastguard Worker     printf("Bad printer URI '%s'.\n", data.uri);
226*5e7646d2SAndroid Build Coastguard Worker     return (1);
227*5e7646d2SAndroid Build Coastguard Worker   }
228*5e7646d2SAndroid Build Coastguard Worker 
229*5e7646d2SAndroid Build Coastguard Worker   if (!data.port)
230*5e7646d2SAndroid Build Coastguard Worker     data.port = IPP_PORT;
231*5e7646d2SAndroid Build Coastguard Worker 
232*5e7646d2SAndroid Build Coastguard Worker   if (!strcmp(scheme, "https") || !strcmp(scheme, "ipps"))
233*5e7646d2SAndroid Build Coastguard Worker     data.encryption = HTTP_ENCRYPTION_ALWAYS;
234*5e7646d2SAndroid Build Coastguard Worker   else
235*5e7646d2SAndroid Build Coastguard Worker     data.encryption = HTTP_ENCRYPTION_IF_REQUESTED;
236*5e7646d2SAndroid Build Coastguard Worker 
237*5e7646d2SAndroid Build Coastguard Worker  /*
238*5e7646d2SAndroid Build Coastguard Worker   * Start the client threads...
239*5e7646d2SAndroid Build Coastguard Worker   */
240*5e7646d2SAndroid Build Coastguard Worker 
241*5e7646d2SAndroid Build Coastguard Worker   data.hostname = hostname;
242*5e7646d2SAndroid Build Coastguard Worker   data.resource = resource;
243*5e7646d2SAndroid Build Coastguard Worker 
244*5e7646d2SAndroid Build Coastguard Worker   while (clients_started < num_clients)
245*5e7646d2SAndroid Build Coastguard Worker   {
246*5e7646d2SAndroid Build Coastguard Worker     _cupsMutexLock(&client_mutex);
247*5e7646d2SAndroid Build Coastguard Worker     if (client_count < MAX_CLIENTS)
248*5e7646d2SAndroid Build Coastguard Worker     {
249*5e7646d2SAndroid Build Coastguard Worker       _cups_thread_t	tid;		/* New thread */
250*5e7646d2SAndroid Build Coastguard Worker 
251*5e7646d2SAndroid Build Coastguard Worker       client_count ++;
252*5e7646d2SAndroid Build Coastguard Worker       _cupsMutexUnlock(&client_mutex);
253*5e7646d2SAndroid Build Coastguard Worker       tid = _cupsThreadCreate((_cups_thread_func_t)run_client, &data);
254*5e7646d2SAndroid Build Coastguard Worker       _cupsThreadDetach(tid);
255*5e7646d2SAndroid Build Coastguard Worker     }
256*5e7646d2SAndroid Build Coastguard Worker     else
257*5e7646d2SAndroid Build Coastguard Worker     {
258*5e7646d2SAndroid Build Coastguard Worker       _cupsMutexUnlock(&client_mutex);
259*5e7646d2SAndroid Build Coastguard Worker       sleep(1);
260*5e7646d2SAndroid Build Coastguard Worker     }
261*5e7646d2SAndroid Build Coastguard Worker   }
262*5e7646d2SAndroid Build Coastguard Worker 
263*5e7646d2SAndroid Build Coastguard Worker   while (client_count > 0)
264*5e7646d2SAndroid Build Coastguard Worker   {
265*5e7646d2SAndroid Build Coastguard Worker     _cupsMutexLock(&client_mutex);
266*5e7646d2SAndroid Build Coastguard Worker     printf("%d RUNNING CLIENTS\n", client_count);
267*5e7646d2SAndroid Build Coastguard Worker     _cupsMutexUnlock(&client_mutex);
268*5e7646d2SAndroid Build Coastguard Worker     sleep(1);
269*5e7646d2SAndroid Build Coastguard Worker   }
270*5e7646d2SAndroid Build Coastguard Worker 
271*5e7646d2SAndroid Build Coastguard Worker   return (0);
272*5e7646d2SAndroid Build Coastguard Worker }
273*5e7646d2SAndroid Build Coastguard Worker 
274*5e7646d2SAndroid Build Coastguard Worker 
275*5e7646d2SAndroid Build Coastguard Worker /*
276*5e7646d2SAndroid Build Coastguard Worker  * 'make_raster_file()' - Create a temporary raster file.
277*5e7646d2SAndroid Build Coastguard Worker  */
278*5e7646d2SAndroid Build Coastguard Worker 
279*5e7646d2SAndroid Build Coastguard Worker static const char *                     /* O - Print filename */
make_raster_file(ipp_t * response,int grayscale,char * tempname,size_t tempsize,const char ** format)280*5e7646d2SAndroid Build Coastguard Worker make_raster_file(ipp_t      *response,  /* I - Printer attributes */
281*5e7646d2SAndroid Build Coastguard Worker                  int        grayscale,  /* I - Force grayscale? */
282*5e7646d2SAndroid Build Coastguard Worker                  char       *tempname,  /* I - Temporary filename buffer */
283*5e7646d2SAndroid Build Coastguard Worker                  size_t     tempsize,   /* I - Size of temp file buffer */
284*5e7646d2SAndroid Build Coastguard Worker                  const char **format)   /* O - Print format */
285*5e7646d2SAndroid Build Coastguard Worker {
286*5e7646d2SAndroid Build Coastguard Worker   int                   i,              /* Looping var */
287*5e7646d2SAndroid Build Coastguard Worker                         count;          /* Number of values */
288*5e7646d2SAndroid Build Coastguard Worker   ipp_attribute_t       *attr;          /* Printer attribute */
289*5e7646d2SAndroid Build Coastguard Worker   const char            *type = NULL;   /* Raster type (colorspace + bits) */
290*5e7646d2SAndroid Build Coastguard Worker   pwg_media_t           *media = NULL;  /* Media size */
291*5e7646d2SAndroid Build Coastguard Worker   int                   xdpi = 0,       /* Horizontal resolution */
292*5e7646d2SAndroid Build Coastguard Worker                         ydpi = 0;       /* Vertical resolution */
293*5e7646d2SAndroid Build Coastguard Worker   int                   fd;             /* Temporary file */
294*5e7646d2SAndroid Build Coastguard Worker   cups_mode_t           mode;           /* Raster mode */
295*5e7646d2SAndroid Build Coastguard Worker   cups_raster_t         *ras;           /* Raster stream */
296*5e7646d2SAndroid Build Coastguard Worker   cups_page_header2_t   header;         /* Page header */
297*5e7646d2SAndroid Build Coastguard Worker   unsigned char         *line,          /* Line of raster data */
298*5e7646d2SAndroid Build Coastguard Worker                         *lineptr;       /* Pointer into line */
299*5e7646d2SAndroid Build Coastguard Worker   unsigned              y,              /* Current position on page */
300*5e7646d2SAndroid Build Coastguard Worker                         xcount, ycount, /* Current count for X and Y */
301*5e7646d2SAndroid Build Coastguard Worker                         xrep, yrep,     /* Repeat count for X and Y */
302*5e7646d2SAndroid Build Coastguard Worker                         xoff, yoff,     /* Offsets for X and Y */
303*5e7646d2SAndroid Build Coastguard Worker                         yend;           /* End Y value */
304*5e7646d2SAndroid Build Coastguard Worker   int                   temprow,        /* Row in template */
305*5e7646d2SAndroid Build Coastguard Worker                         tempcolor;      /* Template color */
306*5e7646d2SAndroid Build Coastguard Worker   const char            *template;      /* Pointer into template */
307*5e7646d2SAndroid Build Coastguard Worker   const unsigned char   *color;         /* Current color */
308*5e7646d2SAndroid Build Coastguard Worker   static const unsigned char colors[][3] =
309*5e7646d2SAndroid Build Coastguard Worker   {                                     /* Colors for test */
310*5e7646d2SAndroid Build Coastguard Worker     { 191, 191, 191 },
311*5e7646d2SAndroid Build Coastguard Worker     { 127, 127, 127 },
312*5e7646d2SAndroid Build Coastguard Worker     {  63,  63,  63 },
313*5e7646d2SAndroid Build Coastguard Worker     {   0,   0,   0 },
314*5e7646d2SAndroid Build Coastguard Worker     { 255,   0,   0 },
315*5e7646d2SAndroid Build Coastguard Worker     { 255, 127,   0 },
316*5e7646d2SAndroid Build Coastguard Worker     { 255, 255,   0 },
317*5e7646d2SAndroid Build Coastguard Worker     { 127, 255,   0 },
318*5e7646d2SAndroid Build Coastguard Worker     {   0, 255,   0 },
319*5e7646d2SAndroid Build Coastguard Worker     {   0, 255, 127 },
320*5e7646d2SAndroid Build Coastguard Worker     {   0, 255, 255 },
321*5e7646d2SAndroid Build Coastguard Worker     {   0, 127, 255 },
322*5e7646d2SAndroid Build Coastguard Worker     {   0,   0, 255 },
323*5e7646d2SAndroid Build Coastguard Worker     { 127,   0, 255 },
324*5e7646d2SAndroid Build Coastguard Worker     { 255,   0, 255 }
325*5e7646d2SAndroid Build Coastguard Worker   };
326*5e7646d2SAndroid Build Coastguard Worker   static const char * const templates[] =
327*5e7646d2SAndroid Build Coastguard Worker   {                                     /* Raster template */
328*5e7646d2SAndroid Build Coastguard Worker     " CCC   U   U  PPPP    SSS          TTTTT  EEEEE   SSS   TTTTT          000     1     222    333      4   55555   66    77777   888    999   ",
329*5e7646d2SAndroid Build Coastguard Worker     "C   C  U   U  P   P  S   S           T    E      S   S    T           0   0   11    2   2  3   3  4  4   5      6          7  8   8  9   9  ",
330*5e7646d2SAndroid Build Coastguard Worker     "C      U   U  P   P  S               T    E      S        T           0   0    1        2      3  4  4   5      6         7   8   8  9   9  ",
331*5e7646d2SAndroid Build Coastguard Worker     "C      U   U  PPPP    SSS   -----    T    EEEE    SSS     T           0 0 0    1      22    333   44444   555   6666      7    888    9999  ",
332*5e7646d2SAndroid Build Coastguard Worker     "C      U   U  P          S           T    E          S    T           0   0    1     2         3     4       5  6   6    7    8   8      9  ",
333*5e7646d2SAndroid Build Coastguard Worker     "C   C  U   U  P      S   S           T    E      S   S    T           0   0    1    2      3   3     4   5   5  6   6    7    8   8      9  ",
334*5e7646d2SAndroid Build Coastguard Worker     " CCC    UUU   P       SSS            T    EEEEE   SSS     T            000    111   22222   333      4    555    666     7     888     99   ",
335*5e7646d2SAndroid Build Coastguard Worker     "                                                                                                                                            "
336*5e7646d2SAndroid Build Coastguard Worker   };
337*5e7646d2SAndroid Build Coastguard Worker 
338*5e7646d2SAndroid Build Coastguard Worker 
339*5e7646d2SAndroid Build Coastguard Worker  /*
340*5e7646d2SAndroid Build Coastguard Worker   * Figure out the output format...
341*5e7646d2SAndroid Build Coastguard Worker   */
342*5e7646d2SAndroid Build Coastguard Worker 
343*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(response, "document-format-supported", IPP_TAG_MIMETYPE)) == NULL)
344*5e7646d2SAndroid Build Coastguard Worker   {
345*5e7646d2SAndroid Build Coastguard Worker     puts("No supported document formats, aborting.");
346*5e7646d2SAndroid Build Coastguard Worker     return (NULL);
347*5e7646d2SAndroid Build Coastguard Worker   }
348*5e7646d2SAndroid Build Coastguard Worker 
349*5e7646d2SAndroid Build Coastguard Worker   if (*format)
350*5e7646d2SAndroid Build Coastguard Worker   {
351*5e7646d2SAndroid Build Coastguard Worker     if (!ippContainsString(attr, *format))
352*5e7646d2SAndroid Build Coastguard Worker     {
353*5e7646d2SAndroid Build Coastguard Worker       printf("Printer does not support document-format '%s'.\n", *format);
354*5e7646d2SAndroid Build Coastguard Worker       return (NULL);
355*5e7646d2SAndroid Build Coastguard Worker     }
356*5e7646d2SAndroid Build Coastguard Worker 
357*5e7646d2SAndroid Build Coastguard Worker     if (!strcmp(*format, "image/urf"))
358*5e7646d2SAndroid Build Coastguard Worker       mode = CUPS_RASTER_WRITE_APPLE;
359*5e7646d2SAndroid Build Coastguard Worker     else if (!strcmp(*format, "image/pwg-raster"))
360*5e7646d2SAndroid Build Coastguard Worker       mode = CUPS_RASTER_WRITE_PWG;
361*5e7646d2SAndroid Build Coastguard Worker     else
362*5e7646d2SAndroid Build Coastguard Worker     {
363*5e7646d2SAndroid Build Coastguard Worker       printf("Unable to generate document-format '%s'.\n", *format);
364*5e7646d2SAndroid Build Coastguard Worker       return (NULL);
365*5e7646d2SAndroid Build Coastguard Worker     }
366*5e7646d2SAndroid Build Coastguard Worker   }
367*5e7646d2SAndroid Build Coastguard Worker   else if (ippContainsString(attr, "image/urf"))
368*5e7646d2SAndroid Build Coastguard Worker   {
369*5e7646d2SAndroid Build Coastguard Worker    /*
370*5e7646d2SAndroid Build Coastguard Worker     * Apple Raster format...
371*5e7646d2SAndroid Build Coastguard Worker     */
372*5e7646d2SAndroid Build Coastguard Worker 
373*5e7646d2SAndroid Build Coastguard Worker     *format = "image/urf";
374*5e7646d2SAndroid Build Coastguard Worker     mode    = CUPS_RASTER_WRITE_APPLE;
375*5e7646d2SAndroid Build Coastguard Worker   }
376*5e7646d2SAndroid Build Coastguard Worker   else if (ippContainsString(attr, "image/pwg-raster"))
377*5e7646d2SAndroid Build Coastguard Worker   {
378*5e7646d2SAndroid Build Coastguard Worker    /*
379*5e7646d2SAndroid Build Coastguard Worker     * PWG Raster format...
380*5e7646d2SAndroid Build Coastguard Worker     */
381*5e7646d2SAndroid Build Coastguard Worker 
382*5e7646d2SAndroid Build Coastguard Worker     *format = "image/pwg-raster";
383*5e7646d2SAndroid Build Coastguard Worker     mode    = CUPS_RASTER_WRITE_PWG;
384*5e7646d2SAndroid Build Coastguard Worker   }
385*5e7646d2SAndroid Build Coastguard Worker   else
386*5e7646d2SAndroid Build Coastguard Worker   {
387*5e7646d2SAndroid Build Coastguard Worker    /*
388*5e7646d2SAndroid Build Coastguard Worker     * No supported raster format...
389*5e7646d2SAndroid Build Coastguard Worker     */
390*5e7646d2SAndroid Build Coastguard Worker 
391*5e7646d2SAndroid Build Coastguard Worker     puts("Printer does not support Apple or PWG raster files, aborting.");
392*5e7646d2SAndroid Build Coastguard Worker     return (NULL);
393*5e7646d2SAndroid Build Coastguard Worker   }
394*5e7646d2SAndroid Build Coastguard Worker 
395*5e7646d2SAndroid Build Coastguard Worker  /*
396*5e7646d2SAndroid Build Coastguard Worker   * Figure out the the media, resolution, and color mode...
397*5e7646d2SAndroid Build Coastguard Worker   */
398*5e7646d2SAndroid Build Coastguard Worker 
399*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(response, "media-ready", IPP_TAG_KEYWORD)) != NULL)
400*5e7646d2SAndroid Build Coastguard Worker   {
401*5e7646d2SAndroid Build Coastguard Worker    /*
402*5e7646d2SAndroid Build Coastguard Worker     * Use ready media...
403*5e7646d2SAndroid Build Coastguard Worker     */
404*5e7646d2SAndroid Build Coastguard Worker 
405*5e7646d2SAndroid Build Coastguard Worker     if (ippContainsString(attr, "na_letter_8.5x11in"))
406*5e7646d2SAndroid Build Coastguard Worker       media = pwgMediaForPWG("na_letter_8.5x11in");
407*5e7646d2SAndroid Build Coastguard Worker     else if (ippContainsString(attr, "iso_a4_210x297mm"))
408*5e7646d2SAndroid Build Coastguard Worker       media = pwgMediaForPWG("iso_a4_210x297mm");
409*5e7646d2SAndroid Build Coastguard Worker     else
410*5e7646d2SAndroid Build Coastguard Worker       media = pwgMediaForPWG(ippGetString(attr, 0, NULL));
411*5e7646d2SAndroid Build Coastguard Worker   }
412*5e7646d2SAndroid Build Coastguard Worker   else if ((attr = ippFindAttribute(response, "media-default", IPP_TAG_KEYWORD)) != NULL)
413*5e7646d2SAndroid Build Coastguard Worker   {
414*5e7646d2SAndroid Build Coastguard Worker    /*
415*5e7646d2SAndroid Build Coastguard Worker     * Use default media...
416*5e7646d2SAndroid Build Coastguard Worker     */
417*5e7646d2SAndroid Build Coastguard Worker 
418*5e7646d2SAndroid Build Coastguard Worker     media = pwgMediaForPWG(ippGetString(attr, 0, NULL));
419*5e7646d2SAndroid Build Coastguard Worker   }
420*5e7646d2SAndroid Build Coastguard Worker   else
421*5e7646d2SAndroid Build Coastguard Worker   {
422*5e7646d2SAndroid Build Coastguard Worker     puts("No default or ready media reported by printer, aborting.");
423*5e7646d2SAndroid Build Coastguard Worker     return (NULL);
424*5e7646d2SAndroid Build Coastguard Worker   }
425*5e7646d2SAndroid Build Coastguard Worker 
426*5e7646d2SAndroid Build Coastguard Worker   if (mode == CUPS_RASTER_WRITE_APPLE && (attr = ippFindAttribute(response, "urf-supported", IPP_TAG_KEYWORD)) != NULL)
427*5e7646d2SAndroid Build Coastguard Worker   {
428*5e7646d2SAndroid Build Coastguard Worker     for (i = 0, count = ippGetCount(attr); i < count; i ++)
429*5e7646d2SAndroid Build Coastguard Worker     {
430*5e7646d2SAndroid Build Coastguard Worker       const char *val = ippGetString(attr, i, NULL);
431*5e7646d2SAndroid Build Coastguard Worker 
432*5e7646d2SAndroid Build Coastguard Worker       if (!strncmp(val, "RS", 2))
433*5e7646d2SAndroid Build Coastguard Worker         xdpi = ydpi = atoi(val + 2);
434*5e7646d2SAndroid Build Coastguard Worker       else if (!strncmp(val, "W8", 2) && !type)
435*5e7646d2SAndroid Build Coastguard Worker         type = "sgray_8";
436*5e7646d2SAndroid Build Coastguard Worker       else if (!strncmp(val, "SRGB24", 6) && !grayscale)
437*5e7646d2SAndroid Build Coastguard Worker         type = "srgb_8";
438*5e7646d2SAndroid Build Coastguard Worker     }
439*5e7646d2SAndroid Build Coastguard Worker   }
440*5e7646d2SAndroid Build Coastguard Worker   else if (mode == CUPS_RASTER_WRITE_PWG && (attr = ippFindAttribute(response, "pwg-raster-document-resolution-supported", IPP_TAG_RESOLUTION)) != NULL)
441*5e7646d2SAndroid Build Coastguard Worker   {
442*5e7646d2SAndroid Build Coastguard Worker     for (i = 0, count = ippGetCount(attr); i < count; i ++)
443*5e7646d2SAndroid Build Coastguard Worker     {
444*5e7646d2SAndroid Build Coastguard Worker       int tempxdpi, tempydpi;
445*5e7646d2SAndroid Build Coastguard Worker       ipp_res_t tempunits;
446*5e7646d2SAndroid Build Coastguard Worker 
447*5e7646d2SAndroid Build Coastguard Worker       tempxdpi = ippGetResolution(attr, 0, &tempydpi, &tempunits);
448*5e7646d2SAndroid Build Coastguard Worker 
449*5e7646d2SAndroid Build Coastguard Worker       if (i == 0 || tempxdpi < xdpi || tempydpi < ydpi)
450*5e7646d2SAndroid Build Coastguard Worker       {
451*5e7646d2SAndroid Build Coastguard Worker         xdpi = tempxdpi;
452*5e7646d2SAndroid Build Coastguard Worker         ydpi = tempydpi;
453*5e7646d2SAndroid Build Coastguard Worker       }
454*5e7646d2SAndroid Build Coastguard Worker     }
455*5e7646d2SAndroid Build Coastguard Worker 
456*5e7646d2SAndroid Build Coastguard Worker     if ((attr = ippFindAttribute(response, "pwg-raster-document-type-supported", IPP_TAG_KEYWORD)) != NULL)
457*5e7646d2SAndroid Build Coastguard Worker     {
458*5e7646d2SAndroid Build Coastguard Worker       if (!grayscale && ippContainsString(attr, "srgb_8"))
459*5e7646d2SAndroid Build Coastguard Worker         type = "srgb_8";
460*5e7646d2SAndroid Build Coastguard Worker       else if (ippContainsString(attr, "sgray_8"))
461*5e7646d2SAndroid Build Coastguard Worker         type = "sgray_8";
462*5e7646d2SAndroid Build Coastguard Worker     }
463*5e7646d2SAndroid Build Coastguard Worker   }
464*5e7646d2SAndroid Build Coastguard Worker 
465*5e7646d2SAndroid Build Coastguard Worker   if (xdpi < 72 || ydpi < 72)
466*5e7646d2SAndroid Build Coastguard Worker   {
467*5e7646d2SAndroid Build Coastguard Worker     puts("No supported raster resolutions, aborting.");
468*5e7646d2SAndroid Build Coastguard Worker     return (NULL);
469*5e7646d2SAndroid Build Coastguard Worker   }
470*5e7646d2SAndroid Build Coastguard Worker 
471*5e7646d2SAndroid Build Coastguard Worker   if (!type)
472*5e7646d2SAndroid Build Coastguard Worker   {
473*5e7646d2SAndroid Build Coastguard Worker     puts("No supported color spaces or bit depths, aborting.");
474*5e7646d2SAndroid Build Coastguard Worker     return (NULL);
475*5e7646d2SAndroid Build Coastguard Worker   }
476*5e7646d2SAndroid Build Coastguard Worker 
477*5e7646d2SAndroid Build Coastguard Worker  /*
478*5e7646d2SAndroid Build Coastguard Worker   * Make the raster context and details...
479*5e7646d2SAndroid Build Coastguard Worker   */
480*5e7646d2SAndroid Build Coastguard Worker 
481*5e7646d2SAndroid Build Coastguard Worker   if (!cupsRasterInitPWGHeader(&header, media, type, xdpi, ydpi, "one-sided", NULL))
482*5e7646d2SAndroid Build Coastguard Worker   {
483*5e7646d2SAndroid Build Coastguard Worker     printf("Unable to initialize raster context: %s\n", cupsRasterErrorString());
484*5e7646d2SAndroid Build Coastguard Worker     return (NULL);
485*5e7646d2SAndroid Build Coastguard Worker   }
486*5e7646d2SAndroid Build Coastguard Worker 
487*5e7646d2SAndroid Build Coastguard Worker   header.cupsInteger[CUPS_RASTER_PWG_TotalPageCount] = 1;
488*5e7646d2SAndroid Build Coastguard Worker 
489*5e7646d2SAndroid Build Coastguard Worker   if (header.cupsWidth > (2 * header.HWResolution[0]))
490*5e7646d2SAndroid Build Coastguard Worker   {
491*5e7646d2SAndroid Build Coastguard Worker     xoff = header.HWResolution[0] / 2;
492*5e7646d2SAndroid Build Coastguard Worker     yoff = header.HWResolution[1] / 2;
493*5e7646d2SAndroid Build Coastguard Worker   }
494*5e7646d2SAndroid Build Coastguard Worker   else
495*5e7646d2SAndroid Build Coastguard Worker   {
496*5e7646d2SAndroid Build Coastguard Worker     xoff = header.HWResolution[0] / 4;
497*5e7646d2SAndroid Build Coastguard Worker     yoff = header.HWResolution[1] / 4;
498*5e7646d2SAndroid Build Coastguard Worker   }
499*5e7646d2SAndroid Build Coastguard Worker 
500*5e7646d2SAndroid Build Coastguard Worker   xrep = (header.cupsWidth - 2 * xoff) / 140;
501*5e7646d2SAndroid Build Coastguard Worker   yrep = xrep * header.HWResolution[1] / header.HWResolution[0];
502*5e7646d2SAndroid Build Coastguard Worker   yend = header.cupsHeight - yoff;
503*5e7646d2SAndroid Build Coastguard Worker 
504*5e7646d2SAndroid Build Coastguard Worker  /*
505*5e7646d2SAndroid Build Coastguard Worker   * Prepare the raster file...
506*5e7646d2SAndroid Build Coastguard Worker   */
507*5e7646d2SAndroid Build Coastguard Worker 
508*5e7646d2SAndroid Build Coastguard Worker   if ((line = malloc(header.cupsBytesPerLine)) == NULL)
509*5e7646d2SAndroid Build Coastguard Worker   {
510*5e7646d2SAndroid Build Coastguard Worker     printf("Unable to allocate %u bytes for raster output: %s\n", header.cupsBytesPerLine, strerror(errno));
511*5e7646d2SAndroid Build Coastguard Worker     return (NULL);
512*5e7646d2SAndroid Build Coastguard Worker   }
513*5e7646d2SAndroid Build Coastguard Worker 
514*5e7646d2SAndroid Build Coastguard Worker   if ((fd = cupsTempFd(tempname, (int)tempsize)) < 0)
515*5e7646d2SAndroid Build Coastguard Worker   {
516*5e7646d2SAndroid Build Coastguard Worker     printf("Unable to create temporary print file: %s\n", strerror(errno));
517*5e7646d2SAndroid Build Coastguard Worker     free(line);
518*5e7646d2SAndroid Build Coastguard Worker     return (NULL);
519*5e7646d2SAndroid Build Coastguard Worker   }
520*5e7646d2SAndroid Build Coastguard Worker 
521*5e7646d2SAndroid Build Coastguard Worker   if ((ras = cupsRasterOpen(fd, mode)) == NULL)
522*5e7646d2SAndroid Build Coastguard Worker   {
523*5e7646d2SAndroid Build Coastguard Worker     printf("Unable to open raster stream: %s\n", cupsRasterErrorString());
524*5e7646d2SAndroid Build Coastguard Worker     close(fd);
525*5e7646d2SAndroid Build Coastguard Worker     free(line);
526*5e7646d2SAndroid Build Coastguard Worker     return (NULL);
527*5e7646d2SAndroid Build Coastguard Worker   }
528*5e7646d2SAndroid Build Coastguard Worker 
529*5e7646d2SAndroid Build Coastguard Worker  /*
530*5e7646d2SAndroid Build Coastguard Worker   * Write a single page consisting of the template dots repeated over the page.
531*5e7646d2SAndroid Build Coastguard Worker   */
532*5e7646d2SAndroid Build Coastguard Worker 
533*5e7646d2SAndroid Build Coastguard Worker   cupsRasterWriteHeader2(ras, &header);
534*5e7646d2SAndroid Build Coastguard Worker 
535*5e7646d2SAndroid Build Coastguard Worker   memset(line, 0xff, header.cupsBytesPerLine);
536*5e7646d2SAndroid Build Coastguard Worker 
537*5e7646d2SAndroid Build Coastguard Worker   for (y = 0; y < yoff; y ++)
538*5e7646d2SAndroid Build Coastguard Worker     cupsRasterWritePixels(ras, line, header.cupsBytesPerLine);
539*5e7646d2SAndroid Build Coastguard Worker 
540*5e7646d2SAndroid Build Coastguard Worker   for (temprow = 0, tempcolor = 0; y < yend;)
541*5e7646d2SAndroid Build Coastguard Worker   {
542*5e7646d2SAndroid Build Coastguard Worker     template = templates[temprow];
543*5e7646d2SAndroid Build Coastguard Worker     color    = colors[tempcolor];
544*5e7646d2SAndroid Build Coastguard Worker 
545*5e7646d2SAndroid Build Coastguard Worker     temprow ++;
546*5e7646d2SAndroid Build Coastguard Worker     if (temprow >= (int)(sizeof(templates) / sizeof(templates[0])))
547*5e7646d2SAndroid Build Coastguard Worker     {
548*5e7646d2SAndroid Build Coastguard Worker       temprow = 0;
549*5e7646d2SAndroid Build Coastguard Worker       tempcolor ++;
550*5e7646d2SAndroid Build Coastguard Worker       if (tempcolor >= (int)(sizeof(colors) / sizeof(colors[0])))
551*5e7646d2SAndroid Build Coastguard Worker         tempcolor = 0;
552*5e7646d2SAndroid Build Coastguard Worker       else if (tempcolor > 3 && header.cupsColorSpace == CUPS_CSPACE_SW)
553*5e7646d2SAndroid Build Coastguard Worker         tempcolor = 0;
554*5e7646d2SAndroid Build Coastguard Worker     }
555*5e7646d2SAndroid Build Coastguard Worker 
556*5e7646d2SAndroid Build Coastguard Worker     memset(line, 0xff, header.cupsBytesPerLine);
557*5e7646d2SAndroid Build Coastguard Worker 
558*5e7646d2SAndroid Build Coastguard Worker     if (header.cupsColorSpace == CUPS_CSPACE_SW)
559*5e7646d2SAndroid Build Coastguard Worker     {
560*5e7646d2SAndroid Build Coastguard Worker      /*
561*5e7646d2SAndroid Build Coastguard Worker       * Do grayscale output...
562*5e7646d2SAndroid Build Coastguard Worker       */
563*5e7646d2SAndroid Build Coastguard Worker 
564*5e7646d2SAndroid Build Coastguard Worker       for (lineptr = line + xoff; *template; template ++)
565*5e7646d2SAndroid Build Coastguard Worker       {
566*5e7646d2SAndroid Build Coastguard Worker         if (*template != ' ')
567*5e7646d2SAndroid Build Coastguard Worker         {
568*5e7646d2SAndroid Build Coastguard Worker           for (xcount = xrep; xcount > 0; xcount --)
569*5e7646d2SAndroid Build Coastguard Worker             *lineptr++ = *color;
570*5e7646d2SAndroid Build Coastguard Worker         }
571*5e7646d2SAndroid Build Coastguard Worker         else
572*5e7646d2SAndroid Build Coastguard Worker         {
573*5e7646d2SAndroid Build Coastguard Worker           lineptr += xrep;
574*5e7646d2SAndroid Build Coastguard Worker         }
575*5e7646d2SAndroid Build Coastguard Worker       }
576*5e7646d2SAndroid Build Coastguard Worker     }
577*5e7646d2SAndroid Build Coastguard Worker     else
578*5e7646d2SAndroid Build Coastguard Worker     {
579*5e7646d2SAndroid Build Coastguard Worker      /*
580*5e7646d2SAndroid Build Coastguard Worker       * Do color output...
581*5e7646d2SAndroid Build Coastguard Worker       */
582*5e7646d2SAndroid Build Coastguard Worker 
583*5e7646d2SAndroid Build Coastguard Worker       for (lineptr = line + 3 * xoff; *template; template ++)
584*5e7646d2SAndroid Build Coastguard Worker       {
585*5e7646d2SAndroid Build Coastguard Worker         if (*template != ' ')
586*5e7646d2SAndroid Build Coastguard Worker         {
587*5e7646d2SAndroid Build Coastguard Worker           for (xcount = xrep; xcount > 0; xcount --, lineptr += 3)
588*5e7646d2SAndroid Build Coastguard Worker             memcpy(lineptr, color, 3);
589*5e7646d2SAndroid Build Coastguard Worker         }
590*5e7646d2SAndroid Build Coastguard Worker         else
591*5e7646d2SAndroid Build Coastguard Worker         {
592*5e7646d2SAndroid Build Coastguard Worker           lineptr += 3 * xrep;
593*5e7646d2SAndroid Build Coastguard Worker         }
594*5e7646d2SAndroid Build Coastguard Worker       }
595*5e7646d2SAndroid Build Coastguard Worker     }
596*5e7646d2SAndroid Build Coastguard Worker 
597*5e7646d2SAndroid Build Coastguard Worker     for (ycount = yrep; ycount > 0 && y < yend; ycount --, y ++)
598*5e7646d2SAndroid Build Coastguard Worker       cupsRasterWritePixels(ras, line, header.cupsBytesPerLine);
599*5e7646d2SAndroid Build Coastguard Worker   }
600*5e7646d2SAndroid Build Coastguard Worker 
601*5e7646d2SAndroid Build Coastguard Worker   memset(line, 0xff, header.cupsBytesPerLine);
602*5e7646d2SAndroid Build Coastguard Worker 
603*5e7646d2SAndroid Build Coastguard Worker   for (y = 0; y < header.cupsHeight; y ++)
604*5e7646d2SAndroid Build Coastguard Worker     cupsRasterWritePixels(ras, line, header.cupsBytesPerLine);
605*5e7646d2SAndroid Build Coastguard Worker 
606*5e7646d2SAndroid Build Coastguard Worker   free(line);
607*5e7646d2SAndroid Build Coastguard Worker 
608*5e7646d2SAndroid Build Coastguard Worker   cupsRasterClose(ras);
609*5e7646d2SAndroid Build Coastguard Worker 
610*5e7646d2SAndroid Build Coastguard Worker   close(fd);
611*5e7646d2SAndroid Build Coastguard Worker 
612*5e7646d2SAndroid Build Coastguard Worker   printf("PRINT FILE: %s\n", tempname);
613*5e7646d2SAndroid Build Coastguard Worker 
614*5e7646d2SAndroid Build Coastguard Worker   return (tempname);
615*5e7646d2SAndroid Build Coastguard Worker }
616*5e7646d2SAndroid Build Coastguard Worker 
617*5e7646d2SAndroid Build Coastguard Worker 
618*5e7646d2SAndroid Build Coastguard Worker /*
619*5e7646d2SAndroid Build Coastguard Worker  * 'monitor_printer()' - Monitor the job and printer states.
620*5e7646d2SAndroid Build Coastguard Worker  */
621*5e7646d2SAndroid Build Coastguard Worker 
622*5e7646d2SAndroid Build Coastguard Worker static void *				/* O - Thread exit code */
monitor_printer(_client_data_t * data)623*5e7646d2SAndroid Build Coastguard Worker monitor_printer(
624*5e7646d2SAndroid Build Coastguard Worker     _client_data_t *data)		/* I - Client data */
625*5e7646d2SAndroid Build Coastguard Worker {
626*5e7646d2SAndroid Build Coastguard Worker   http_t	*http;			/* Connection to printer */
627*5e7646d2SAndroid Build Coastguard Worker   ipp_t		*request,		/* IPP request */
628*5e7646d2SAndroid Build Coastguard Worker 		*response;		/* IPP response */
629*5e7646d2SAndroid Build Coastguard Worker   ipp_attribute_t *attr;		/* Attribute in response */
630*5e7646d2SAndroid Build Coastguard Worker   ipp_pstate_t	printer_state;		/* Printer state */
631*5e7646d2SAndroid Build Coastguard Worker   char          printer_state_reasons[1024];
632*5e7646d2SAndroid Build Coastguard Worker                                         /* Printer state reasons */
633*5e7646d2SAndroid Build Coastguard Worker   ipp_jstate_t	job_state;		/* Job state */
634*5e7646d2SAndroid Build Coastguard Worker   char          job_state_reasons[1024];/* Printer state reasons */
635*5e7646d2SAndroid Build Coastguard Worker   static const char * const jattrs[] =  /* Job attributes we want */
636*5e7646d2SAndroid Build Coastguard Worker   {
637*5e7646d2SAndroid Build Coastguard Worker     "job-state",
638*5e7646d2SAndroid Build Coastguard Worker     "job-state-reasons"
639*5e7646d2SAndroid Build Coastguard Worker   };
640*5e7646d2SAndroid Build Coastguard Worker   static const char * const pattrs[] =  /* Printer attributes we want */
641*5e7646d2SAndroid Build Coastguard Worker   {
642*5e7646d2SAndroid Build Coastguard Worker     "printer-state",
643*5e7646d2SAndroid Build Coastguard Worker     "printer-state-reasons"
644*5e7646d2SAndroid Build Coastguard Worker   };
645*5e7646d2SAndroid Build Coastguard Worker 
646*5e7646d2SAndroid Build Coastguard Worker 
647*5e7646d2SAndroid Build Coastguard Worker  /*
648*5e7646d2SAndroid Build Coastguard Worker   * Open a connection to the printer...
649*5e7646d2SAndroid Build Coastguard Worker   */
650*5e7646d2SAndroid Build Coastguard Worker 
651*5e7646d2SAndroid Build Coastguard Worker   http = httpConnect2(data->hostname, data->port, NULL, AF_UNSPEC, data->encryption, 1, 0, NULL);
652*5e7646d2SAndroid Build Coastguard Worker 
653*5e7646d2SAndroid Build Coastguard Worker  /*
654*5e7646d2SAndroid Build Coastguard Worker   * Loop until the job is canceled, aborted, or completed.
655*5e7646d2SAndroid Build Coastguard Worker   */
656*5e7646d2SAndroid Build Coastguard Worker 
657*5e7646d2SAndroid Build Coastguard Worker   printer_state            = (ipp_pstate_t)0;
658*5e7646d2SAndroid Build Coastguard Worker   printer_state_reasons[0] = '\0';
659*5e7646d2SAndroid Build Coastguard Worker 
660*5e7646d2SAndroid Build Coastguard Worker   job_state            = (ipp_jstate_t)0;
661*5e7646d2SAndroid Build Coastguard Worker   job_state_reasons[0] = '\0';
662*5e7646d2SAndroid Build Coastguard Worker 
663*5e7646d2SAndroid Build Coastguard Worker   while (data->job_state < IPP_JSTATE_CANCELED)
664*5e7646d2SAndroid Build Coastguard Worker   {
665*5e7646d2SAndroid Build Coastguard Worker    /*
666*5e7646d2SAndroid Build Coastguard Worker     * Reconnect to the printer as needed...
667*5e7646d2SAndroid Build Coastguard Worker     */
668*5e7646d2SAndroid Build Coastguard Worker 
669*5e7646d2SAndroid Build Coastguard Worker     if (httpGetFd(http) < 0)
670*5e7646d2SAndroid Build Coastguard Worker       httpReconnect2(http, 30000, NULL);
671*5e7646d2SAndroid Build Coastguard Worker 
672*5e7646d2SAndroid Build Coastguard Worker     if (httpGetFd(http) >= 0)
673*5e7646d2SAndroid Build Coastguard Worker     {
674*5e7646d2SAndroid Build Coastguard Worker      /*
675*5e7646d2SAndroid Build Coastguard Worker       * Connected, so check on the printer state...
676*5e7646d2SAndroid Build Coastguard Worker       */
677*5e7646d2SAndroid Build Coastguard Worker 
678*5e7646d2SAndroid Build Coastguard Worker       request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES);
679*5e7646d2SAndroid Build Coastguard Worker       ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, data->uri);
680*5e7646d2SAndroid Build Coastguard Worker       ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser());
681*5e7646d2SAndroid Build Coastguard Worker       ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "requested-attributes", (int)(sizeof(pattrs) / sizeof(pattrs[0])), NULL, pattrs);
682*5e7646d2SAndroid Build Coastguard Worker 
683*5e7646d2SAndroid Build Coastguard Worker       response = cupsDoRequest(http, request, data->resource);
684*5e7646d2SAndroid Build Coastguard Worker 
685*5e7646d2SAndroid Build Coastguard Worker       if ((attr = ippFindAttribute(response, "printer-state", IPP_TAG_ENUM)) != NULL)
686*5e7646d2SAndroid Build Coastguard Worker         printer_state = (ipp_pstate_t)ippGetInteger(attr, 0);
687*5e7646d2SAndroid Build Coastguard Worker 
688*5e7646d2SAndroid Build Coastguard Worker       if ((attr = ippFindAttribute(response, "printer-state-reasons", IPP_TAG_KEYWORD)) != NULL)
689*5e7646d2SAndroid Build Coastguard Worker         ippAttributeString(attr, printer_state_reasons, sizeof(printer_state_reasons));
690*5e7646d2SAndroid Build Coastguard Worker 
691*5e7646d2SAndroid Build Coastguard Worker       if (printer_state != data->printer_state || strcmp(printer_state_reasons, data->printer_state_reasons))
692*5e7646d2SAndroid Build Coastguard Worker       {
693*5e7646d2SAndroid Build Coastguard Worker         printf("PRINTER: %s (%s)\n", ippEnumString("printer-state", (int)printer_state), printer_state_reasons);
694*5e7646d2SAndroid Build Coastguard Worker 
695*5e7646d2SAndroid Build Coastguard Worker         data->printer_state = printer_state;
696*5e7646d2SAndroid Build Coastguard Worker         strlcpy(data->printer_state_reasons, printer_state_reasons, sizeof(data->printer_state_reasons));
697*5e7646d2SAndroid Build Coastguard Worker       }
698*5e7646d2SAndroid Build Coastguard Worker 
699*5e7646d2SAndroid Build Coastguard Worker       ippDelete(response);
700*5e7646d2SAndroid Build Coastguard Worker 
701*5e7646d2SAndroid Build Coastguard Worker       if (data->job_id > 0)
702*5e7646d2SAndroid Build Coastguard Worker       {
703*5e7646d2SAndroid Build Coastguard Worker        /*
704*5e7646d2SAndroid Build Coastguard Worker         * Check the status of the job itself...
705*5e7646d2SAndroid Build Coastguard Worker         */
706*5e7646d2SAndroid Build Coastguard Worker 
707*5e7646d2SAndroid Build Coastguard Worker         request = ippNewRequest(IPP_OP_GET_JOB_ATTRIBUTES);
708*5e7646d2SAndroid Build Coastguard Worker         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, data->uri);
709*5e7646d2SAndroid Build Coastguard Worker         ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id", data->job_id);
710*5e7646d2SAndroid Build Coastguard Worker         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser());
711*5e7646d2SAndroid Build Coastguard Worker         ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "requested-attributes", (int)(sizeof(jattrs) / sizeof(jattrs[0])), NULL, jattrs);
712*5e7646d2SAndroid Build Coastguard Worker 
713*5e7646d2SAndroid Build Coastguard Worker         response = cupsDoRequest(http, request, data->resource);
714*5e7646d2SAndroid Build Coastguard Worker 
715*5e7646d2SAndroid Build Coastguard Worker         if ((attr = ippFindAttribute(response, "job-state", IPP_TAG_ENUM)) != NULL)
716*5e7646d2SAndroid Build Coastguard Worker           job_state = (ipp_jstate_t)ippGetInteger(attr, 0);
717*5e7646d2SAndroid Build Coastguard Worker 
718*5e7646d2SAndroid Build Coastguard Worker         if ((attr = ippFindAttribute(response, "job-state-reasons", IPP_TAG_KEYWORD)) != NULL)
719*5e7646d2SAndroid Build Coastguard Worker           ippAttributeString(attr, job_state_reasons, sizeof(job_state_reasons));
720*5e7646d2SAndroid Build Coastguard Worker 
721*5e7646d2SAndroid Build Coastguard Worker         if (job_state != data->job_state || strcmp(job_state_reasons, data->job_state_reasons))
722*5e7646d2SAndroid Build Coastguard Worker         {
723*5e7646d2SAndroid Build Coastguard Worker           printf("JOB %d: %s (%s)\n", data->job_id, ippEnumString("job-state", (int)job_state), job_state_reasons);
724*5e7646d2SAndroid Build Coastguard Worker 
725*5e7646d2SAndroid Build Coastguard Worker           data->job_state = job_state;
726*5e7646d2SAndroid Build Coastguard Worker           strlcpy(data->job_state_reasons, job_state_reasons, sizeof(data->job_state_reasons));
727*5e7646d2SAndroid Build Coastguard Worker         }
728*5e7646d2SAndroid Build Coastguard Worker 
729*5e7646d2SAndroid Build Coastguard Worker         ippDelete(response);
730*5e7646d2SAndroid Build Coastguard Worker       }
731*5e7646d2SAndroid Build Coastguard Worker     }
732*5e7646d2SAndroid Build Coastguard Worker 
733*5e7646d2SAndroid Build Coastguard Worker     if (data->job_state < IPP_JSTATE_CANCELED)
734*5e7646d2SAndroid Build Coastguard Worker     {
735*5e7646d2SAndroid Build Coastguard Worker      /*
736*5e7646d2SAndroid Build Coastguard Worker       * Sleep for 5 seconds...
737*5e7646d2SAndroid Build Coastguard Worker       */
738*5e7646d2SAndroid Build Coastguard Worker 
739*5e7646d2SAndroid Build Coastguard Worker       sleep(5);
740*5e7646d2SAndroid Build Coastguard Worker     }
741*5e7646d2SAndroid Build Coastguard Worker   }
742*5e7646d2SAndroid Build Coastguard Worker 
743*5e7646d2SAndroid Build Coastguard Worker  /*
744*5e7646d2SAndroid Build Coastguard Worker   * Cleanup and return...
745*5e7646d2SAndroid Build Coastguard Worker   */
746*5e7646d2SAndroid Build Coastguard Worker 
747*5e7646d2SAndroid Build Coastguard Worker   httpClose(http);
748*5e7646d2SAndroid Build Coastguard Worker 
749*5e7646d2SAndroid Build Coastguard Worker   printf("FINISHED MONITORING JOB %d\n", data->job_id);
750*5e7646d2SAndroid Build Coastguard Worker 
751*5e7646d2SAndroid Build Coastguard Worker   return (NULL);
752*5e7646d2SAndroid Build Coastguard Worker }
753*5e7646d2SAndroid Build Coastguard Worker 
754*5e7646d2SAndroid Build Coastguard Worker 
755*5e7646d2SAndroid Build Coastguard Worker /*
756*5e7646d2SAndroid Build Coastguard Worker  * 'run_client()' - Run a client thread.
757*5e7646d2SAndroid Build Coastguard Worker  */
758*5e7646d2SAndroid Build Coastguard Worker 
759*5e7646d2SAndroid Build Coastguard Worker static void *				/* O - Thread exit code */
run_client(_client_data_t * data)760*5e7646d2SAndroid Build Coastguard Worker run_client(
761*5e7646d2SAndroid Build Coastguard Worker     _client_data_t *data)		/* I - Client data */
762*5e7646d2SAndroid Build Coastguard Worker {
763*5e7646d2SAndroid Build Coastguard Worker   _cups_thread_t monitor_id;		/* Monitoring thread ID */
764*5e7646d2SAndroid Build Coastguard Worker   const char	*name;			/* Job name */
765*5e7646d2SAndroid Build Coastguard Worker   char		tempfile[1024] = "";	/* Temporary file (if any) */
766*5e7646d2SAndroid Build Coastguard Worker   _client_data_t ldata;			/* Local client data */
767*5e7646d2SAndroid Build Coastguard Worker   http_t	*http;			/* Connection to printer */
768*5e7646d2SAndroid Build Coastguard Worker   ipp_t		*request,		/* IPP request */
769*5e7646d2SAndroid Build Coastguard Worker 		*response;		/* IPP response */
770*5e7646d2SAndroid Build Coastguard Worker   ipp_attribute_t *attr;		/* Attribute in response */
771*5e7646d2SAndroid Build Coastguard Worker   static const char * const pattrs[] =  /* Printer attributes we are interested in */
772*5e7646d2SAndroid Build Coastguard Worker   {
773*5e7646d2SAndroid Build Coastguard Worker     "all",
774*5e7646d2SAndroid Build Coastguard Worker     "media-col-database"
775*5e7646d2SAndroid Build Coastguard Worker   };
776*5e7646d2SAndroid Build Coastguard Worker 
777*5e7646d2SAndroid Build Coastguard Worker 
778*5e7646d2SAndroid Build Coastguard Worker   ldata = *data;
779*5e7646d2SAndroid Build Coastguard Worker 
780*5e7646d2SAndroid Build Coastguard Worker  /*
781*5e7646d2SAndroid Build Coastguard Worker   * Start monitoring the printer in the background...
782*5e7646d2SAndroid Build Coastguard Worker   */
783*5e7646d2SAndroid Build Coastguard Worker 
784*5e7646d2SAndroid Build Coastguard Worker   monitor_id = _cupsThreadCreate((_cups_thread_func_t)monitor_printer, &ldata);
785*5e7646d2SAndroid Build Coastguard Worker 
786*5e7646d2SAndroid Build Coastguard Worker  /*
787*5e7646d2SAndroid Build Coastguard Worker   * Open a connection to the printer...
788*5e7646d2SAndroid Build Coastguard Worker   */
789*5e7646d2SAndroid Build Coastguard Worker 
790*5e7646d2SAndroid Build Coastguard Worker   http = httpConnect2(data->hostname, data->port, NULL, AF_UNSPEC, data->encryption, 1, 0, NULL);
791*5e7646d2SAndroid Build Coastguard Worker 
792*5e7646d2SAndroid Build Coastguard Worker  /*
793*5e7646d2SAndroid Build Coastguard Worker   * Query printer status and capabilities...
794*5e7646d2SAndroid Build Coastguard Worker   */
795*5e7646d2SAndroid Build Coastguard Worker 
796*5e7646d2SAndroid Build Coastguard Worker   request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES);
797*5e7646d2SAndroid Build Coastguard Worker   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, ldata.uri);
798*5e7646d2SAndroid Build Coastguard Worker   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser());
799*5e7646d2SAndroid Build Coastguard Worker   ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "requested-attributes", (int)(sizeof(pattrs) / sizeof(pattrs[0])), NULL, pattrs);
800*5e7646d2SAndroid Build Coastguard Worker 
801*5e7646d2SAndroid Build Coastguard Worker   response = cupsDoRequest(http, request, ldata.resource);
802*5e7646d2SAndroid Build Coastguard Worker 
803*5e7646d2SAndroid Build Coastguard Worker   if (verbosity)
804*5e7646d2SAndroid Build Coastguard Worker     show_capabilities(response);
805*5e7646d2SAndroid Build Coastguard Worker 
806*5e7646d2SAndroid Build Coastguard Worker  /*
807*5e7646d2SAndroid Build Coastguard Worker   * Now figure out what we will be printing...
808*5e7646d2SAndroid Build Coastguard Worker   */
809*5e7646d2SAndroid Build Coastguard Worker 
810*5e7646d2SAndroid Build Coastguard Worker   if (ldata.docfile)
811*5e7646d2SAndroid Build Coastguard Worker   {
812*5e7646d2SAndroid Build Coastguard Worker    /*
813*5e7646d2SAndroid Build Coastguard Worker     * User specified a print file, figure out the format...
814*5e7646d2SAndroid Build Coastguard Worker     */
815*5e7646d2SAndroid Build Coastguard Worker     const char *ext;			/* Filename extension */
816*5e7646d2SAndroid Build Coastguard Worker 
817*5e7646d2SAndroid Build Coastguard Worker     if ((ext = strrchr(ldata.docfile, '.')) != NULL)
818*5e7646d2SAndroid Build Coastguard Worker     {
819*5e7646d2SAndroid Build Coastguard Worker      /*
820*5e7646d2SAndroid Build Coastguard Worker       * Guess the format from the extension...
821*5e7646d2SAndroid Build Coastguard Worker       */
822*5e7646d2SAndroid Build Coastguard Worker 
823*5e7646d2SAndroid Build Coastguard Worker       if (!strcmp(ext, ".jpg"))
824*5e7646d2SAndroid Build Coastguard Worker         ldata.docformat = "image/jpeg";
825*5e7646d2SAndroid Build Coastguard Worker       else if (!strcmp(ext, ".pdf"))
826*5e7646d2SAndroid Build Coastguard Worker         ldata.docformat = "application/pdf";
827*5e7646d2SAndroid Build Coastguard Worker       else if (!strcmp(ext, ".ps"))
828*5e7646d2SAndroid Build Coastguard Worker         ldata.docformat = "application/postscript";
829*5e7646d2SAndroid Build Coastguard Worker       else if (!strcmp(ext, ".pwg"))
830*5e7646d2SAndroid Build Coastguard Worker         ldata.docformat = "image/pwg-raster";
831*5e7646d2SAndroid Build Coastguard Worker       else if (!strcmp(ext, ".urf"))
832*5e7646d2SAndroid Build Coastguard Worker         ldata.docformat = "image/urf";
833*5e7646d2SAndroid Build Coastguard Worker       else
834*5e7646d2SAndroid Build Coastguard Worker         ldata.docformat = "application/octet-stream";
835*5e7646d2SAndroid Build Coastguard Worker     }
836*5e7646d2SAndroid Build Coastguard Worker     else
837*5e7646d2SAndroid Build Coastguard Worker     {
838*5e7646d2SAndroid Build Coastguard Worker      /*
839*5e7646d2SAndroid Build Coastguard Worker       * Tell the printer to auto-detect...
840*5e7646d2SAndroid Build Coastguard Worker       */
841*5e7646d2SAndroid Build Coastguard Worker 
842*5e7646d2SAndroid Build Coastguard Worker       ldata.docformat = "application/octet-stream";
843*5e7646d2SAndroid Build Coastguard Worker     }
844*5e7646d2SAndroid Build Coastguard Worker   }
845*5e7646d2SAndroid Build Coastguard Worker   else
846*5e7646d2SAndroid Build Coastguard Worker   {
847*5e7646d2SAndroid Build Coastguard Worker    /*
848*5e7646d2SAndroid Build Coastguard Worker     * No file specified, make something to test with...
849*5e7646d2SAndroid Build Coastguard Worker     */
850*5e7646d2SAndroid Build Coastguard Worker 
851*5e7646d2SAndroid Build Coastguard Worker     if ((ldata.docfile = make_raster_file(response, ldata.grayscale, tempfile, sizeof(tempfile), &ldata.docformat)) == NULL)
852*5e7646d2SAndroid Build Coastguard Worker       return ((void *)1);
853*5e7646d2SAndroid Build Coastguard Worker   }
854*5e7646d2SAndroid Build Coastguard Worker 
855*5e7646d2SAndroid Build Coastguard Worker   ippDelete(response);
856*5e7646d2SAndroid Build Coastguard Worker 
857*5e7646d2SAndroid Build Coastguard Worker  /*
858*5e7646d2SAndroid Build Coastguard Worker   * Create a job and wait for completion...
859*5e7646d2SAndroid Build Coastguard Worker   */
860*5e7646d2SAndroid Build Coastguard Worker 
861*5e7646d2SAndroid Build Coastguard Worker   request = ippNewRequest(IPP_OP_CREATE_JOB);
862*5e7646d2SAndroid Build Coastguard Worker   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, ldata.uri);
863*5e7646d2SAndroid Build Coastguard Worker   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser());
864*5e7646d2SAndroid Build Coastguard Worker 
865*5e7646d2SAndroid Build Coastguard Worker   if ((name = strrchr(ldata.docfile, '/')) != NULL)
866*5e7646d2SAndroid Build Coastguard Worker     name ++;
867*5e7646d2SAndroid Build Coastguard Worker   else
868*5e7646d2SAndroid Build Coastguard Worker     name = ldata.docfile;
869*5e7646d2SAndroid Build Coastguard Worker 
870*5e7646d2SAndroid Build Coastguard Worker   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL, name);
871*5e7646d2SAndroid Build Coastguard Worker 
872*5e7646d2SAndroid Build Coastguard Worker   if (verbosity)
873*5e7646d2SAndroid Build Coastguard Worker     show_attributes("Create-Job request", 1, request);
874*5e7646d2SAndroid Build Coastguard Worker 
875*5e7646d2SAndroid Build Coastguard Worker   response = cupsDoRequest(http, request, ldata.resource);
876*5e7646d2SAndroid Build Coastguard Worker 
877*5e7646d2SAndroid Build Coastguard Worker   if (verbosity)
878*5e7646d2SAndroid Build Coastguard Worker     show_attributes("Create-Job response", 0, response);
879*5e7646d2SAndroid Build Coastguard Worker 
880*5e7646d2SAndroid Build Coastguard Worker   if (cupsLastError() >= IPP_STATUS_REDIRECTION_OTHER_SITE)
881*5e7646d2SAndroid Build Coastguard Worker   {
882*5e7646d2SAndroid Build Coastguard Worker     printf("Unable to create print job: %s\n", cupsLastErrorString());
883*5e7646d2SAndroid Build Coastguard Worker 
884*5e7646d2SAndroid Build Coastguard Worker     ldata.job_state = IPP_JSTATE_ABORTED;
885*5e7646d2SAndroid Build Coastguard Worker 
886*5e7646d2SAndroid Build Coastguard Worker     goto cleanup;
887*5e7646d2SAndroid Build Coastguard Worker   }
888*5e7646d2SAndroid Build Coastguard Worker 
889*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(response, "job-id", IPP_TAG_INTEGER)) == NULL)
890*5e7646d2SAndroid Build Coastguard Worker   {
891*5e7646d2SAndroid Build Coastguard Worker     puts("No job-id returned in Create-Job request.");
892*5e7646d2SAndroid Build Coastguard Worker 
893*5e7646d2SAndroid Build Coastguard Worker     ldata.job_state = IPP_JSTATE_ABORTED;
894*5e7646d2SAndroid Build Coastguard Worker 
895*5e7646d2SAndroid Build Coastguard Worker     goto cleanup;
896*5e7646d2SAndroid Build Coastguard Worker   }
897*5e7646d2SAndroid Build Coastguard Worker 
898*5e7646d2SAndroid Build Coastguard Worker   ldata.job_id = ippGetInteger(attr, 0);
899*5e7646d2SAndroid Build Coastguard Worker 
900*5e7646d2SAndroid Build Coastguard Worker   printf("CREATED JOB %d, sending %s of type %s\n", ldata.job_id, ldata.docfile, ldata.docformat);
901*5e7646d2SAndroid Build Coastguard Worker 
902*5e7646d2SAndroid Build Coastguard Worker   ippDelete(response);
903*5e7646d2SAndroid Build Coastguard Worker 
904*5e7646d2SAndroid Build Coastguard Worker   request = ippNewRequest(IPP_OP_SEND_DOCUMENT);
905*5e7646d2SAndroid Build Coastguard Worker   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, ldata.uri);
906*5e7646d2SAndroid Build Coastguard Worker   ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id", ldata.job_id);
907*5e7646d2SAndroid Build Coastguard Worker   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser());
908*5e7646d2SAndroid Build Coastguard Worker   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format", NULL, ldata.docformat);
909*5e7646d2SAndroid Build Coastguard Worker   ippAddBoolean(request, IPP_TAG_OPERATION, "last-document", 1);
910*5e7646d2SAndroid Build Coastguard Worker 
911*5e7646d2SAndroid Build Coastguard Worker   if (verbosity)
912*5e7646d2SAndroid Build Coastguard Worker     show_attributes("Send-Document request", 1, request);
913*5e7646d2SAndroid Build Coastguard Worker 
914*5e7646d2SAndroid Build Coastguard Worker   response = cupsDoFileRequest(http, request, ldata.resource, ldata.docfile);
915*5e7646d2SAndroid Build Coastguard Worker 
916*5e7646d2SAndroid Build Coastguard Worker   if (verbosity)
917*5e7646d2SAndroid Build Coastguard Worker     show_attributes("Send-Document response", 0, response);
918*5e7646d2SAndroid Build Coastguard Worker 
919*5e7646d2SAndroid Build Coastguard Worker   if (cupsLastError() >= IPP_STATUS_REDIRECTION_OTHER_SITE)
920*5e7646d2SAndroid Build Coastguard Worker   {
921*5e7646d2SAndroid Build Coastguard Worker     printf("Unable to print file: %s\n", cupsLastErrorString());
922*5e7646d2SAndroid Build Coastguard Worker 
923*5e7646d2SAndroid Build Coastguard Worker     ldata.job_state = IPP_JSTATE_ABORTED;
924*5e7646d2SAndroid Build Coastguard Worker 
925*5e7646d2SAndroid Build Coastguard Worker     goto cleanup;
926*5e7646d2SAndroid Build Coastguard Worker   }
927*5e7646d2SAndroid Build Coastguard Worker 
928*5e7646d2SAndroid Build Coastguard Worker   puts("WAITING FOR JOB TO COMPLETE");
929*5e7646d2SAndroid Build Coastguard Worker 
930*5e7646d2SAndroid Build Coastguard Worker   while (ldata.job_state < IPP_JSTATE_CANCELED)
931*5e7646d2SAndroid Build Coastguard Worker     sleep(1);
932*5e7646d2SAndroid Build Coastguard Worker 
933*5e7646d2SAndroid Build Coastguard Worker  /*
934*5e7646d2SAndroid Build Coastguard Worker   * Cleanup after ourselves...
935*5e7646d2SAndroid Build Coastguard Worker   */
936*5e7646d2SAndroid Build Coastguard Worker 
937*5e7646d2SAndroid Build Coastguard Worker   cleanup:
938*5e7646d2SAndroid Build Coastguard Worker 
939*5e7646d2SAndroid Build Coastguard Worker   httpClose(http);
940*5e7646d2SAndroid Build Coastguard Worker 
941*5e7646d2SAndroid Build Coastguard Worker   if (tempfile[0] && !ldata.keepfile)
942*5e7646d2SAndroid Build Coastguard Worker     unlink(tempfile);
943*5e7646d2SAndroid Build Coastguard Worker 
944*5e7646d2SAndroid Build Coastguard Worker   _cupsThreadWait(monitor_id);
945*5e7646d2SAndroid Build Coastguard Worker 
946*5e7646d2SAndroid Build Coastguard Worker   _cupsMutexLock(&client_mutex);
947*5e7646d2SAndroid Build Coastguard Worker   client_count --;
948*5e7646d2SAndroid Build Coastguard Worker   _cupsMutexUnlock(&client_mutex);
949*5e7646d2SAndroid Build Coastguard Worker 
950*5e7646d2SAndroid Build Coastguard Worker   return (NULL);
951*5e7646d2SAndroid Build Coastguard Worker }
952*5e7646d2SAndroid Build Coastguard Worker 
953*5e7646d2SAndroid Build Coastguard Worker 
954*5e7646d2SAndroid Build Coastguard Worker /*
955*5e7646d2SAndroid Build Coastguard Worker  * 'show_attributes()' - Show attributes in a request or response.
956*5e7646d2SAndroid Build Coastguard Worker  */
957*5e7646d2SAndroid Build Coastguard Worker 
958*5e7646d2SAndroid Build Coastguard Worker static void
show_attributes(const char * title,int request,ipp_t * ipp)959*5e7646d2SAndroid Build Coastguard Worker show_attributes(const char *title,      /* I - Title */
960*5e7646d2SAndroid Build Coastguard Worker                 int        request,     /* I - 1 for request, 0 for response */
961*5e7646d2SAndroid Build Coastguard Worker                 ipp_t      *ipp)        /* I - IPP request/response */
962*5e7646d2SAndroid Build Coastguard Worker {
963*5e7646d2SAndroid Build Coastguard Worker   int                   minor, major = ippGetVersion(ipp, &minor);
964*5e7646d2SAndroid Build Coastguard Worker                                         /* IPP version number */
965*5e7646d2SAndroid Build Coastguard Worker   ipp_tag_t             group = IPP_TAG_ZERO;
966*5e7646d2SAndroid Build Coastguard Worker                                         /* Current group tag */
967*5e7646d2SAndroid Build Coastguard Worker   ipp_attribute_t       *attr;          /* Current attribute */
968*5e7646d2SAndroid Build Coastguard Worker   const char            *name;          /* Attribute name */
969*5e7646d2SAndroid Build Coastguard Worker   char                  buffer[1024];   /* Value */
970*5e7646d2SAndroid Build Coastguard Worker 
971*5e7646d2SAndroid Build Coastguard Worker 
972*5e7646d2SAndroid Build Coastguard Worker   printf("%s:\n", title);
973*5e7646d2SAndroid Build Coastguard Worker   printf("  version=%d.%d\n", major, minor);
974*5e7646d2SAndroid Build Coastguard Worker   printf("  request-id=%d\n", ippGetRequestId(ipp));
975*5e7646d2SAndroid Build Coastguard Worker   if (!request)
976*5e7646d2SAndroid Build Coastguard Worker     printf("  status-code=%s\n", ippErrorString(ippGetStatusCode(ipp)));
977*5e7646d2SAndroid Build Coastguard Worker 
978*5e7646d2SAndroid Build Coastguard Worker   for (attr = ippFirstAttribute(ipp); attr; attr = ippNextAttribute(ipp))
979*5e7646d2SAndroid Build Coastguard Worker   {
980*5e7646d2SAndroid Build Coastguard Worker     if (group != ippGetGroupTag(attr))
981*5e7646d2SAndroid Build Coastguard Worker     {
982*5e7646d2SAndroid Build Coastguard Worker       group = ippGetGroupTag(attr);
983*5e7646d2SAndroid Build Coastguard Worker       if (group)
984*5e7646d2SAndroid Build Coastguard Worker         printf("  %s:\n", ippTagString(group));
985*5e7646d2SAndroid Build Coastguard Worker     }
986*5e7646d2SAndroid Build Coastguard Worker 
987*5e7646d2SAndroid Build Coastguard Worker     if ((name = ippGetName(attr)) != NULL)
988*5e7646d2SAndroid Build Coastguard Worker     {
989*5e7646d2SAndroid Build Coastguard Worker       ippAttributeString(attr, buffer, sizeof(buffer));
990*5e7646d2SAndroid Build Coastguard Worker       printf("    %s(%s%s)=%s\n", name, ippGetCount(attr) > 1 ? "1setOf " : "", ippTagString(ippGetValueTag(attr)), buffer);
991*5e7646d2SAndroid Build Coastguard Worker     }
992*5e7646d2SAndroid Build Coastguard Worker   }
993*5e7646d2SAndroid Build Coastguard Worker }
994*5e7646d2SAndroid Build Coastguard Worker 
995*5e7646d2SAndroid Build Coastguard Worker 
996*5e7646d2SAndroid Build Coastguard Worker /*
997*5e7646d2SAndroid Build Coastguard Worker  * 'show_capabilities()' - Show printer capabilities.
998*5e7646d2SAndroid Build Coastguard Worker  */
999*5e7646d2SAndroid Build Coastguard Worker 
1000*5e7646d2SAndroid Build Coastguard Worker static void
show_capabilities(ipp_t * response)1001*5e7646d2SAndroid Build Coastguard Worker show_capabilities(ipp_t *response)      /* I - Printer attributes */
1002*5e7646d2SAndroid Build Coastguard Worker {
1003*5e7646d2SAndroid Build Coastguard Worker   int                   i;              /* Looping var */
1004*5e7646d2SAndroid Build Coastguard Worker   ipp_attribute_t       *attr;          /* Attribute */
1005*5e7646d2SAndroid Build Coastguard Worker   char                  buffer[1024];   /* Attribute value buffer */
1006*5e7646d2SAndroid Build Coastguard Worker   static const char * const pattrs[] =  /* Attributes we want to show */
1007*5e7646d2SAndroid Build Coastguard Worker   {
1008*5e7646d2SAndroid Build Coastguard Worker     "copies-default",
1009*5e7646d2SAndroid Build Coastguard Worker     "copies-supported",
1010*5e7646d2SAndroid Build Coastguard Worker     "finishings-default",
1011*5e7646d2SAndroid Build Coastguard Worker     "finishings-ready",
1012*5e7646d2SAndroid Build Coastguard Worker     "finishings-supported",
1013*5e7646d2SAndroid Build Coastguard Worker     "media-default",
1014*5e7646d2SAndroid Build Coastguard Worker     "media-ready",
1015*5e7646d2SAndroid Build Coastguard Worker     "media-supported",
1016*5e7646d2SAndroid Build Coastguard Worker     "output-bin-default",
1017*5e7646d2SAndroid Build Coastguard Worker     "output-bin-supported",
1018*5e7646d2SAndroid Build Coastguard Worker     "print-color-mode-default",
1019*5e7646d2SAndroid Build Coastguard Worker     "print-color-mode-supported",
1020*5e7646d2SAndroid Build Coastguard Worker     "sides-default",
1021*5e7646d2SAndroid Build Coastguard Worker     "sides-supported",
1022*5e7646d2SAndroid Build Coastguard Worker     "document-format-default",
1023*5e7646d2SAndroid Build Coastguard Worker     "document-format-supported",
1024*5e7646d2SAndroid Build Coastguard Worker     "pwg-raster-document-resolution-supported",
1025*5e7646d2SAndroid Build Coastguard Worker     "pwg-raster-document-type-supported",
1026*5e7646d2SAndroid Build Coastguard Worker     "urf-supported"
1027*5e7646d2SAndroid Build Coastguard Worker   };
1028*5e7646d2SAndroid Build Coastguard Worker 
1029*5e7646d2SAndroid Build Coastguard Worker 
1030*5e7646d2SAndroid Build Coastguard Worker   puts("CAPABILITIES:");
1031*5e7646d2SAndroid Build Coastguard Worker   for (i = 0; i < (int)(sizeof(pattrs) / sizeof(pattrs[0])); i ++)
1032*5e7646d2SAndroid Build Coastguard Worker   {
1033*5e7646d2SAndroid Build Coastguard Worker      if ((attr = ippFindAttribute(response, pattrs[i], IPP_TAG_ZERO)) != NULL)
1034*5e7646d2SAndroid Build Coastguard Worker      {
1035*5e7646d2SAndroid Build Coastguard Worker        ippAttributeString(attr, buffer, sizeof(buffer));
1036*5e7646d2SAndroid Build Coastguard Worker        printf("  %s=%s\n", pattrs[i], buffer);
1037*5e7646d2SAndroid Build Coastguard Worker      }
1038*5e7646d2SAndroid Build Coastguard Worker   }
1039*5e7646d2SAndroid Build Coastguard Worker }
1040*5e7646d2SAndroid Build Coastguard Worker 
1041*5e7646d2SAndroid Build Coastguard Worker 
1042*5e7646d2SAndroid Build Coastguard Worker /*
1043*5e7646d2SAndroid Build Coastguard Worker  * 'usage()' - Show program usage...
1044*5e7646d2SAndroid Build Coastguard Worker  */
1045*5e7646d2SAndroid Build Coastguard Worker 
1046*5e7646d2SAndroid Build Coastguard Worker static void
usage(void)1047*5e7646d2SAndroid Build Coastguard Worker usage(void)
1048*5e7646d2SAndroid Build Coastguard Worker {
1049*5e7646d2SAndroid Build Coastguard Worker   puts("Usage: ./testclient printer-uri [options]");
1050*5e7646d2SAndroid Build Coastguard Worker   puts("Options:");
1051*5e7646d2SAndroid Build Coastguard Worker   puts("  -c num-clients      Simulate multiple clients");
1052*5e7646d2SAndroid Build Coastguard Worker   puts("  -d document-format  Generate the specified format");
1053*5e7646d2SAndroid Build Coastguard Worker   puts("  -f print-file       Print the named file");
1054*5e7646d2SAndroid Build Coastguard Worker   puts("  -g                  Force grayscale printing");
1055*5e7646d2SAndroid Build Coastguard Worker   puts("  -k                  Keep temporary files");
1056*5e7646d2SAndroid Build Coastguard Worker   puts("  -v                  Be more verbose");
1057*5e7646d2SAndroid Build Coastguard Worker }
1058