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