]> git.ipfire.org Git - thirdparty/cups.git/blame - scheduler/testlpd.c
Merge changes from CUPS trunk, r6739.
[thirdparty/cups.git] / scheduler / testlpd.c
CommitLineData
d09495fa 1/*
355e94dc 2 * "$Id: testlpd.c 6705 2007-07-20 22:25:31Z mike $"
d09495fa 3 *
4 * cups-lpd test program for the Common UNIX Printing System (CUPS).
5 *
bc44d920 6 * Copyright 2007 by Apple Inc.
d09495fa 7 * Copyright 2006 by Easy Software Products, all rights reserved.
8 *
9 * These coded instructions, statements, and computer programs are the
bc44d920 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/".
d09495fa 14 *
15 * Contents:
16 *
17 * main() - Simulate an LPD client.
18 * do_command() - Send the LPD command and wait for a response.
19 * print_job() - Submit a file for printing.
20 * print_waiting() - Print waiting jobs.
21 * remove_job() - Cancel a print job.
22 * status_long() - Show the long printer status.
23 * status_short() - Show the short printer status.
24 * usage() - Show program usage...
25 */
26
27/*
28 * Include necessary headers...
29 */
30
31#include <cups/cups.h>
32#include <cups/string.h>
33#include <stdlib.h>
34#include <sys/stat.h>
35#include <errno.h>
36#include <signal.h>
37#include <unistd.h>
38#include <fcntl.h>
39
40
41/*
42 * Local functions...
43 */
44
45static int do_command(int outfd, int infd, const char *command);
46static int print_job(int outfd, int infd, char *dest, char **args);
47static int print_waiting(int outfd, int infd, char *dest);
48static int remove_job(int outfd, int infd, char *dest, char **args);
49static int status_long(int outfd, int infd, char *dest, char **args);
50static int status_short(int outfd, int infd, char *dest, char **args);
51static void usage(void);
52
53
54/*
55 * 'main()' - Simulate an LPD client.
56 */
57
58int /* O - Exit status */
59main(int argc, /* I - Number of command-line arguments */
60 char *argv[]) /* I - Command-line arguments */
61{
62 int i; /* Looping var */
63 int status; /* Test status */
64 char *op, /* Operation to test */
65 **opargs, /* Remaining arguments */
66 *dest; /* Destination */
67 int cupslpd_argc; /* Argument count for cups-lpd */
68 char *cupslpd_argv[1000]; /* Arguments for cups-lpd */
69 int cupslpd_stdin[2], /* Standard input for cups-lpd */
70 cupslpd_stdout[2], /* Standard output for cups-lpd */
355e94dc
MS
71 cupslpd_pid, /* Process ID for cups-lpd */
72 cupslpd_status; /* Status of cups-lpd process */
d09495fa 73
74
75 /*
76 * Collect command-line arguments...
77 */
78
79 op = NULL;
80 opargs = NULL;
81 dest = NULL;
82 cupslpd_argc = 1;
83 cupslpd_argv[0] = (char *)"cups-lpd";
84
85 for (i = 1; i < argc; i ++)
86 if (!strncmp(argv[i], "-o", 2))
87 {
88 cupslpd_argv[cupslpd_argc++] = argv[i];
89
355e94dc 90 if (!argv[i][2])
d09495fa 91 {
92 i ++;
93
94 if (i >= argc)
95 usage();
96
97 cupslpd_argv[cupslpd_argc++] = argv[i];
98 }
99 }
100 else if (argv[i][0] == '-')
101 usage();
102 else if (!op)
103 op = argv[i];
104 else if (!dest)
105 dest = argv[i];
106 else
107 {
108 opargs = argv + i;
109 break;
110 }
111
112 if (!op ||
113 (!strcmp(op, "print-job") && (!dest || !opargs)) ||
114 (!strcmp(op, "remove-job") && (!dest || !opargs)) ||
115 (strcmp(op, "print-job") && strcmp(op, "print-waiting") &&
116 strcmp(op, "remove-job") && strcmp(op, "status-long") &&
117 strcmp(op, "status-short")))
355e94dc
MS
118 {
119 printf("op=\"%s\", dest=\"%s\", opargs=%p\n", op, dest, opargs);
d09495fa 120 usage();
355e94dc 121 }
d09495fa 122
123 /*
124 * Run the cups-lpd program using pipes...
125 */
126
127 cupslpd_argv[cupslpd_argc] = NULL;
128
129 pipe(cupslpd_stdin);
130 pipe(cupslpd_stdout);
131
132 if ((cupslpd_pid = fork()) < 0)
133 {
134 /*
135 * Error!
136 */
137
138 perror("testlpd: Unable to fork");
139 return (1);
140 }
141 else if (cupslpd_pid == 0)
142 {
143 /*
144 * Child goes here...
145 */
146
147 close(0);
148 dup(cupslpd_stdin[0]);
149 close(cupslpd_stdin[0]);
150 close(cupslpd_stdin[1]);
151
152 close(1);
153 dup(cupslpd_stdout[1]);
154 close(cupslpd_stdout[0]);
155 close(cupslpd_stdout[1]);
156
157 execv("./cups-lpd", cupslpd_argv);
158
159 perror("testlpd: Unable to exec ./cups-lpd");
160 exit(errno);
161 }
162 else
163 {
164 close(cupslpd_stdin[0]);
165 close(cupslpd_stdout[1]);
166 }
167
168 /*
169 * Do the operation test...
170 */
171
172 if (!strcmp(op, "print-job"))
173 status = print_job(cupslpd_stdin[1], cupslpd_stdout[0], dest, opargs);
174 else if (!strcmp(op, "print-waiting"))
175 status = print_waiting(cupslpd_stdin[1], cupslpd_stdout[0], dest);
176 else if (!strcmp(op, "remove-job"))
177 status = remove_job(cupslpd_stdin[1], cupslpd_stdout[0], dest, opargs);
178 else if (!strcmp(op, "status-long"))
179 status = status_long(cupslpd_stdin[1], cupslpd_stdout[0], dest, opargs);
180 else if (!strcmp(op, "status-short"))
181 status = status_short(cupslpd_stdin[1], cupslpd_stdout[0], dest, opargs);
f7deaa1a 182 else
183 {
184 printf("Unknown operation \"%s\"!\n", op);
185 status = 1;
186 }
d09495fa 187
188 /*
189 * Kill the test program...
190 */
191
192 close(cupslpd_stdin[1]);
193 close(cupslpd_stdout[0]);
355e94dc
MS
194
195 while (wait(&cupslpd_status) != cupslpd_pid);
196
197 printf("cups-lpd exit status was %d...\n", cupslpd_status);
d09495fa 198
199 /*
200 * Return the test status...
201 */
202
203 return (status);
204}
205
206
207/*
208 * 'do_command()' - Send the LPD command and wait for a response.
209 */
210
211static int /* O - Status from cups-lpd */
212do_command(int outfd, /* I - Command file descriptor */
213 int infd, /* I - Response file descriptor */
214 const char *command) /* I - Command line to send */
215{
216 int len; /* Length of command line */
217 char status; /* Status byte */
218
219
220 printf("COMMAND: %02X %s", command[0], command + 1);
221
222 len = strlen(command);
223
224 if (write(outfd, command, len) < len)
225 {
226 puts(" Write failed!");
227 return (-1);
228 }
229
230 if (read(infd, &status, 1) < 1)
355e94dc 231 puts("STATUS: ERROR");
d09495fa 232 else
355e94dc 233 printf("STATUS: %d\n", status);
d09495fa 234
235 return (status);
236}
237
238
239/*
240 * 'print_job()' - Submit a file for printing.
241 */
242
243static int /* O - Status from cups-lpd */
244print_job(int outfd, /* I - Command file descriptor */
245 int infd, /* I - Response file descriptor */
246 char *dest, /* I - Destination */
247 char **args) /* I - Arguments */
248{
249 int fd; /* Print file descriptor */
250 char command[1024], /* Command buffer */
251 control[1024], /* Control file */
252 buffer[8192]; /* Print buffer */
253 int status; /* Status of command */
254 struct stat fileinfo; /* File information */
255 char *jobname; /* Job name */
256 int sequence; /* Sequence number */
257 int bytes; /* Bytes read/written */
258
259
260 /*
261 * Check the print file...
262 */
263
264 if (stat(args[0], &fileinfo))
265 {
266 perror(args[0]);
267 return (-1);
268 }
269
270 if ((fd = open(args[0], O_RDONLY)) < 0)
271 {
272 perror(args[0]);
273 return (-1);
274 }
275
276 /*
277 * Send the "receive print job" command...
278 */
279
280 snprintf(command, sizeof(command), "\002%s\n", dest);
281 if ((status = do_command(outfd, infd, command)) != 0)
282 {
283 close(fd);
284 return (status);
285 }
286
287 /*
288 * Format a control file string that will be used to submit the job...
289 */
290
291 if ((jobname = strrchr(args[0], '/')) != NULL)
292 jobname ++;
293 else
294 jobname = args[0];
295
296 sequence = (int)getpid() % 1000;
297
298 snprintf(control, sizeof(control),
299 "Hlocalhost\n"
300 "P%s\n"
301 "J%s\n"
f7deaa1a 302 "ldfA%03dlocalhost\n"
303 "UdfA%03dlocalhost\n"
d09495fa 304 "N%s\n",
305 cupsUser(), jobname, sequence, sequence, jobname);
306
307 /*
308 * Send the control file...
309 */
310
311 bytes = strlen(control);
312
f7deaa1a 313 snprintf(command, sizeof(command), "\002%d cfA%03dlocalhost\n",
d09495fa 314 bytes, sequence);
315
316 if ((status = do_command(outfd, infd, command)) != 0)
317 {
318 close(fd);
319 return (status);
320 }
321
322 bytes ++;
323
324 if (write(outfd, control, bytes) < bytes)
325 {
326 printf("CONTROL: Unable to write %d bytes!\n", bytes);
327 close(fd);
328 return (-1);
329 }
330
331 printf("CONTROL: Wrote %d bytes.\n", bytes);
332
333 if (read(infd, command, 1) < 1)
334 {
355e94dc 335 puts("STATUS: ERROR");
d09495fa 336 close(fd);
337 return (-1);
338 }
339 else
340 {
341 status = command[0];
342
355e94dc 343 printf("STATUS: %d\n", status);
d09495fa 344 }
345
346 /*
347 * Send the data file...
348 */
349
f7deaa1a 350 snprintf(command, sizeof(command), "\003%d dfA%03dlocalhost\n",
d09495fa 351 (int)fileinfo.st_size, sequence);
352
353 if ((status = do_command(outfd, infd, command)) != 0)
354 {
355 close(fd);
356 return (status);
357 }
358
359 while ((bytes = read(fd, buffer, sizeof(buffer))) > 0)
360 {
361 if (write(outfd, buffer, bytes) < bytes)
362 {
363 printf("DATA: Unable to write %d bytes!\n", bytes);
364 close(fd);
365 return (-1);
366 }
367 }
368
369 write(outfd, "", 1);
370
371 close(fd);
372
373 printf("DATA: Wrote %d bytes.\n", (int)fileinfo.st_size);
374
375 if (read(infd, command, 1) < 1)
376 {
355e94dc 377 puts("STATUS: ERROR");
d09495fa 378 close(fd);
379 return (-1);
380 }
381 else
382 {
383 status = command[0];
384
355e94dc 385 printf("STATUS: %d\n", status);
d09495fa 386 }
387
388 return (status);
389}
390
391
392/*
393 * 'print_waiting()' - Print waiting jobs.
394 */
395
396static int /* O - Status from cups-lpd */
397print_waiting(int outfd, /* I - Command file descriptor */
398 int infd, /* I - Response file descriptor */
399 char *dest) /* I - Destination */
400{
401 char command[1024]; /* Command buffer */
402
403
404 /*
405 * Send the "print waiting jobs" command...
406 */
407
408 snprintf(command, sizeof(command), "\001%s\n", dest);
409
410 return (do_command(outfd, infd, command));
411}
412
413
414/*
415 * 'remove_job()' - Cancel a print job.
416 */
417
418static int /* O - Status from cups-lpd */
419remove_job(int outfd, /* I - Command file descriptor */
420 int infd, /* I - Response file descriptor */
421 char *dest, /* I - Destination */
422 char **args) /* I - Arguments */
423{
424 int i; /* Looping var */
425 char command[1024]; /* Command buffer */
426
427 /*
428 * Send the "remove jobs" command...
429 */
430
431 snprintf(command, sizeof(command), "\005%s", dest);
432
433 for (i = 0; args[i]; i ++)
434 {
435 strlcat(command, " ", sizeof(command));
436 strlcat(command, args[i], sizeof(command));
437 }
438
439 strlcat(command, "\n", sizeof(command));
440
441 return (do_command(outfd, infd, command));
442}
443
444
445/*
446 * 'status_long()' - Show the long printer status.
447 */
448
449static int /* O - Status from cups-lpd */
450status_long(int outfd, /* I - Command file descriptor */
451 int infd, /* I - Response file descriptor */
452 char *dest, /* I - Destination */
453 char **args) /* I - Arguments */
454{
455 char command[1024], /* Command buffer */
456 buffer[8192]; /* Status buffer */
457 int bytes; /* Bytes read/written */
458
459
460 /*
461 * Send the "send short status" command...
462 */
463
464 if (args)
465 snprintf(command, sizeof(command), "\004%s %s\n", dest, args[0]);
466 else
467 snprintf(command, sizeof(command), "\004%s\n", dest);
468
469 bytes = strlen(command);
470
471 if (write(outfd, command, bytes) < bytes)
472 return (-1);
473
474 /*
475 * Read the status back...
476 */
477
478 while ((bytes = read(infd, buffer, sizeof(buffer))) > 0)
479 {
480 fwrite(buffer, 1, bytes, stdout);
481 fflush(stdout);
482 }
483
484 return (0);
485}
486
487
488/*
489 * 'status_short()' - Show the short printer status.
490 */
491
492static int /* O - Status from cups-lpd */
493status_short(int outfd, /* I - Command file descriptor */
494 int infd, /* I - Response file descriptor */
495 char *dest, /* I - Destination */
496 char **args) /* I - Arguments */
497{
498 char command[1024], /* Command buffer */
499 buffer[8192]; /* Status buffer */
500 int bytes; /* Bytes read/written */
501
502
503 /*
504 * Send the "send short status" command...
505 */
506
507 if (args)
508 snprintf(command, sizeof(command), "\003%s %s\n", dest, args[0]);
509 else
510 snprintf(command, sizeof(command), "\003%s\n", dest);
511
512 bytes = strlen(command);
513
514 if (write(outfd, command, bytes) < bytes)
515 return (-1);
516
517 /*
518 * Read the status back...
519 */
520
521 while ((bytes = read(infd, buffer, sizeof(buffer))) > 0)
522 {
523 fwrite(buffer, 1, bytes, stdout);
524 fflush(stdout);
525 }
526
527 return (0);
528}
529
530
531/*
532 * 'usage()' - Show program usage...
533 */
534
535static void
536usage(void)
537{
355e94dc 538 puts("Usage: testlpd [options] print-job printer filename [... filename]");
d09495fa 539 puts(" testlpd [options] print-waiting [printer or user]");
540 puts(" testlpd [options] remove-job printer [user [job-id]]");
541 puts(" testlpd [options] status-long [printer or user]");
542 puts(" testlpd [options] status-short [printer or user]");
543 puts("");
544 puts("Options:");
545 puts(" -o name=value");
546
547 exit(0);
548}
549
550
551/*
355e94dc 552 * End of "$Id: testlpd.c 6705 2007-07-20 22:25:31Z mike $".
d09495fa 553 */