1/*
2 * "$Id: cancel.c 11093 2013-07-03 20:48:42Z msweet $"
3 *
4 *   "cancel" command for CUPS.
5 *
6 *   Copyright 2007-2013 by Apple Inc.
7 *   Copyright 1997-2006 by Easy Software Products.
8 *
9 *   These coded instructions, statements, and computer programs are the
10 *   property of Apple Inc. and are protected by Federal copyright
11 *   law.  Distribution and use rights are outlined in the file "LICENSE.txt"
12 *   which should have been included with this file.  If this file is
13 *   file is missing or damaged, see the license at "http://www.cups.org/".
14 *
15 * Contents:
16 *
17 *   main() - Parse options and cancel jobs.
18 */
19
20/*
21 * Include necessary headers...
22 */
23
24#include <cups/cups-private.h>
25
26
27/*
28 * 'main()' - Parse options and cancel jobs.
29 */
30
31int					/* O - Exit status */
32main(int  argc,				/* I - Number of command-line arguments */
33     char *argv[])			/* I - Command-line arguments */
34{
35  http_t	*http;			/* HTTP connection to server */
36  int		i;			/* Looping var */
37  int		job_id;			/* Job ID */
38  int		num_dests;		/* Number of destinations */
39  cups_dest_t	*dests;			/* Destinations */
40  char		*dest,			/* Destination printer */
41		*job,			/* Job ID pointer */
42		*user;			/* Cancel jobs for a user */
43  int		purge;			/* Purge or cancel jobs? */
44  char		uri[1024];		/* Printer or job URI */
45  ipp_t		*request;		/* IPP request */
46  ipp_t		*response;		/* IPP response */
47  ipp_op_t	op;			/* Operation */
48
49
50  _cupsSetLocale(argv);
51
52 /*
53  * Setup to cancel individual print jobs...
54  */
55
56  op        = IPP_CANCEL_JOB;
57  purge     = 0;
58  dest      = NULL;
59  user      = NULL;
60  http      = NULL;
61  num_dests = 0;
62  dests     = NULL;
63
64
65 /*
66  * Process command-line arguments...
67  */
68
69  for (i = 1; i < argc; i ++)
70    if (argv[i][0] == '-' && argv[i][1])
71    {
72      switch (argv[i][1])
73      {
74        case 'E' : /* Encrypt */
75#ifdef HAVE_SSL
76	    cupsSetEncryption(HTTP_ENCRYPT_REQUIRED);
77
78	    if (http)
79	      httpEncryption(http, HTTP_ENCRYPT_REQUIRED);
80#else
81            _cupsLangPrintf(stderr,
82	                    _("%s: Sorry, no encryption support."), argv[0]);
83#endif /* HAVE_SSL */
84	    break;
85
86        case 'U' : /* Username */
87	    if (argv[i][2] != '\0')
88	      cupsSetUser(argv[i] + 2);
89	    else
90	    {
91	      i ++;
92	      if (i >= argc)
93	      {
94	        _cupsLangPrintf(stderr,
95		                _("%s: Error - expected username after "
96				  "\"-U\" option."), argv[0]);
97	        return (1);
98	      }
99
100              cupsSetUser(argv[i]);
101	    }
102	    break;
103
104        case 'a' : /* Cancel all jobs */
105	    op = purge ? IPP_PURGE_JOBS : IPP_CANCEL_JOBS;
106	    break;
107
108        case 'h' : /* Connect to host */
109	    if (http != NULL)
110	    {
111	      httpClose(http);
112	      http = NULL;
113	    }
114
115	    if (argv[i][2] != '\0')
116              cupsSetServer(argv[i] + 2);
117	    else
118	    {
119	      i ++;
120
121	      if (i >= argc)
122	      {
123	        _cupsLangPrintf(stderr,
124		        	_("%s: Error - expected hostname after "
125			          "\"-h\" option."), argv[0]);
126		return (1);
127              }
128	      else
129                cupsSetServer(argv[i]);
130	    }
131	    break;
132
133        case 'u' : /* Username */
134	    op = IPP_CANCEL_MY_JOBS;
135
136	    if (argv[i][2] != '\0')
137	      user = argv[i] + 2;
138	    else
139	    {
140	      i ++;
141
142	      if (i >= argc)
143	      {
144	        _cupsLangPrintf(stderr,
145		        	_("%s: Error - expected username after "
146			          "\"-u\" option."), argv[0]);
147		return (1);
148              }
149	      else
150		user = argv[i];
151	    }
152	    break;
153
154        case 'x' : /* Purge job(s) */
155	    purge = 1;
156
157	    if (op == IPP_CANCEL_JOBS)
158	      op = IPP_PURGE_JOBS;
159	    break;
160
161	default :
162	    _cupsLangPrintf(stderr,
163	                    _("%s: Error - unknown option \"%c\"."),
164			    argv[0], argv[i][1]);
165	    return (1);
166      }
167    }
168    else
169    {
170     /*
171      * Cancel a job or printer...
172      */
173
174      if (num_dests == 0)
175        num_dests = cupsGetDests(&dests);
176
177      if (!strcmp(argv[i], "-"))
178      {
179       /*
180        * Delete the current job...
181	*/
182
183        dest   = "";
184	job_id = 0;
185      }
186      else if (cupsGetDest(argv[i], NULL, num_dests, dests) != NULL)
187      {
188       /*
189        * Delete the current job on the named destination...
190	*/
191
192        dest   = argv[i];
193	job_id = 0;
194      }
195      else if ((job = strrchr(argv[i], '-')) != NULL && isdigit(job[1] & 255))
196      {
197       /*
198        * Delete the specified job ID.
199	*/
200
201        dest   = NULL;
202	op     = IPP_CANCEL_JOB;
203        job_id = atoi(job + 1);
204      }
205      else if (isdigit(argv[i][0] & 255))
206      {
207       /*
208        * Delete the specified job ID.
209	*/
210
211        dest   = NULL;
212	op     = IPP_CANCEL_JOB;
213        job_id = atoi(argv[i]);
214      }
215      else
216      {
217       /*
218        * Bad printer name!
219	*/
220
221        _cupsLangPrintf(stderr,
222	                _("%s: Error - unknown destination \"%s\"."),
223			argv[0], argv[i]);
224	return (1);
225      }
226
227     /*
228      * For Solaris LP compatibility, ignore a destination name after
229      * cancelling a specific job ID...
230      */
231
232      if (job_id && (i + 1) < argc &&
233          cupsGetDest(argv[i + 1], NULL, num_dests, dests) != NULL)
234        i ++;
235
236     /*
237      * Open a connection to the server...
238      */
239
240      if (http == NULL)
241	if ((http = httpConnectEncrypt(cupsServer(), ippPort(),
242	                               cupsEncryption())) == NULL)
243	{
244	  _cupsLangPrintf(stderr,
245	                  _("%s: Unable to connect to server."), argv[0]);
246	  return (1);
247	}
248
249     /*
250      * Build an IPP request, which requires the following
251      * attributes:
252      *
253      *    attributes-charset
254      *    attributes-natural-language
255      *    printer-uri + job-id *or* job-uri
256      *    [requesting-user-name]
257      */
258
259      request = ippNewRequest(op);
260
261      if (dest)
262      {
263	httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
264	                 "localhost", 0, "/printers/%s", dest);
265	ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
266	             "printer-uri", NULL, uri);
267	ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id",
268	              job_id);
269      }
270      else
271      {
272        sprintf(uri, "ipp://localhost/jobs/%d", job_id);
273	ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL,
274	             uri);
275      }
276
277      if (user)
278      {
279	ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
280                     "requesting-user-name", NULL, user);
281	ippAddBoolean(request, IPP_TAG_OPERATION, "my-jobs", 1);
282
283        if (op == IPP_CANCEL_JOBS)
284          op = IPP_CANCEL_MY_JOBS;
285      }
286      else
287	ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
288                     "requesting-user-name", NULL, cupsUser());
289
290      if (purge)
291	ippAddBoolean(request, IPP_TAG_OPERATION, "purge-jobs", purge);
292
293     /*
294      * Do the request and get back a response...
295      */
296
297      if (op == IPP_CANCEL_JOBS && (!user || _cups_strcasecmp(user, cupsUser())))
298        response = cupsDoRequest(http, request, "/admin/");
299      else
300        response = cupsDoRequest(http, request, "/jobs/");
301
302      if (response == NULL ||
303          response->request.status.status_code > IPP_OK_CONFLICT)
304      {
305	_cupsLangPrintf(stderr, _("%s: %s failed: %s"), argv[0],
306	        	op == IPP_PURGE_JOBS ? "purge-jobs" : "cancel-job",
307        		cupsLastErrorString());
308
309	if (response)
310	  ippDelete(response);
311
312	return (1);
313      }
314
315      ippDelete(response);
316    }
317
318  if (num_dests == 0 && op == IPP_PURGE_JOBS)
319  {
320   /*
321    * Open a connection to the server...
322    */
323
324    if (http == NULL)
325      if ((http = httpConnectEncrypt(cupsServer(), ippPort(),
326	                             cupsEncryption())) == NULL)
327      {
328	_cupsLangPrintf(stderr, _("%s: Unable to contact server."), argv[0]);
329	return (1);
330      }
331
332   /*
333    * Build an IPP request, which requires the following
334    * attributes:
335    *
336    *    attributes-charset
337    *    attributes-natural-language
338    *    printer-uri + job-id *or* job-uri
339    *    [requesting-user-name]
340    */
341
342    request = ippNewRequest(op);
343
344    ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
345	         "printer-uri", NULL, "ipp://localhost/printers/");
346
347    if (user)
348    {
349      ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
350                   "requesting-user-name", NULL, user);
351      ippAddBoolean(request, IPP_TAG_OPERATION, "my-jobs", 1);
352    }
353    else
354      ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
355                   "requesting-user-name", NULL, cupsUser());
356
357    ippAddBoolean(request, IPP_TAG_OPERATION, "purge-jobs", purge);
358
359   /*
360    * Do the request and get back a response...
361    */
362
363    response = cupsDoRequest(http, request, "/admin/");
364
365    if (response == NULL ||
366        response->request.status.status_code > IPP_OK_CONFLICT)
367    {
368      _cupsLangPrintf(stderr, _("%s: %s failed: %s"), argv[0],
369		      op == IPP_PURGE_JOBS ? "purge-jobs" : "cancel-job",
370        	      cupsLastErrorString());
371
372      if (response)
373	ippDelete(response);
374
375      return (1);
376    }
377
378    ippDelete(response);
379  }
380
381  return (0);
382}
383
384
385/*
386 * End of "$Id: cancel.c 11093 2013-07-03 20:48:42Z msweet $".
387 */
388