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