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