2 * "$Id: cups-lpd.c,v 1.24.2.2 2001/05/13 18:38:34 mike Exp $"
4 * Line Printer Daemon interface for the Common UNIX Printing System (CUPS).
6 * Copyright 1997-2001 by Easy Software Products, all rights reserved.
8 * These coded instructions, statements, and computer programs are the
9 * property of Easy Software Products and are protected by Federal
10 * copyright law. Distribution and use rights are outlined in the file
11 * "LICENSE.txt" which should have been included with this file. If this
12 * file is missing or damaged please contact Easy Software Products
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636-3111 USA
20 * Voice: (301) 373-9603
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
26 * main() - Process an incoming LPD request...
27 * print_file() - Print a file to a printer or class.
28 * recv_print_job() - Receive a print job from the client.
29 * remove_jobs() - Cancel one or more jobs.
30 * send_short_state() - Send the short queue state.
31 * smart_gets() - Get a line of text, removing the trailing CR
36 * Include necessary headers...
39 #include <cups/cups.h>
40 #include <cups/string.h>
41 #include <cups/language.h>
47 #include <sys/types.h>
48 #include <sys/socket.h>
49 #include <netinet/in.h>
54 * LPD "mini-daemon" for CUPS. This program must be used in conjunction
55 * with inetd or another similar program that monitors ports and starts
56 * daemons for each client connection. A typical configuration is:
58 * printer stream tcp nowait lp /usr/lib/cups/daemon/cups-lpd cups-lpd
60 * This daemon implements most of RFC 1179 (the unofficial LPD specification)
63 * - This daemon does not check to make sure that the source port is
64 * between 721 and 731, since it isn't necessary for proper
65 * functioning and port-based security is no security at all!
67 * - The "Print any waiting jobs" command is a no-op.
69 * The LPD-to-IPP mapping is as defined in RFC 2569. The report formats
70 * currently match the Solaris LPD mini-daemon.
77 int print_file(const char *name
, const char *file
,
78 const char *title
, const char *docname
,
79 const char *user
, int num_options
,
80 cups_option_t
*options
);
81 int recv_print_job(const char *dest
, int num_defaults
, cups_option_t
*defaults
);
82 int remove_jobs(const char *dest
, const char *agent
, const char *list
);
83 int send_state(const char *dest
, const char *list
, int longstatus
);
84 char *smart_gets(char *s
, int len
, FILE *fp
);
88 * 'main()' - Process an incoming LPD request...
91 int /* O - Exit status */
92 main(int argc
, /* I - Number of command-line arguments */
93 char *argv
[]) /* I - Command-line arguments */
95 int i
; /* Looping var */
96 int num_defaults
; /* Number of default options */
97 cups_option_t
*defaults
; /* Default options */
98 char line
[256], /* Command string */
99 command
, /* Command code */
100 *dest
, /* Pointer to destination */
101 *list
, /* Pointer to list */
102 *agent
, /* Pointer to user */
103 status
; /* Status for client */
104 int hostlen
; /* Size of client address */
105 http_addr_t hostaddr
; /* Address of client */
106 char hostname
[256], /* Name of client */
107 hostip
[256], /* IP address */
108 *hostfamily
; /* Address family */
112 * Don't buffer the output...
115 setbuf(stdout
, NULL
);
118 * Log things using the "cups-lpd" name...
121 openlog("cups-lpd", LOG_PID
, LOG_LPR
);
124 * Get the address of the client...
127 hostlen
= sizeof(hostaddr
);
129 if (getpeername(0, (struct sockaddr
*)&hostaddr
, &hostlen
))
130 syslog(LOG_WARNING
, "Unable to get client address - %s", strerror(errno
));
133 httpAddrLookup(&hostaddr
, hostname
, sizeof(hostname
));
134 httpAddrString(&hostaddr
, hostip
, sizeof(hostip
));
137 if (hostaddr
.addr
.sa_family
== AF_INET6
)
140 #endif /* AF_INET6 */
143 syslog(LOG_INFO
, "Connection from %s (%s %s)", hostname
, hostfamily
, hostip
);
147 * Scan the command-line for options...
153 for (i
= 1; i
< argc
; i
++)
154 if (argv
[i
][0] == '-')
158 case 'o' : /* Option */
160 num_defaults
= cupsParseOptions(argv
[i
] + 2, num_defaults
,
166 num_defaults
= cupsParseOptions(argv
[i
], num_defaults
, &defaults
);
168 syslog(LOG_WARNING
, "Expected option string after -o option!");
172 syslog(LOG_WARNING
, "Unknown option \"%c\" ignored!", argv
[i
][1]);
177 syslog(LOG_WARNING
, "Unknown command-line option \"%s\" ignored!", argv
[i
]);
180 * RFC1179 specifies that only 1 daemon command can be received for
184 if (smart_gets(line
, sizeof(line
), stdin
) == NULL
)
187 * Unable to get command from client! Send an error status and return.
190 syslog(LOG_ERR
, "Unable to get command line from client!");
196 * The first byte is the command byte. After that will be the queue name,
197 * resource list, and/or user name.
203 for (list
= dest
+ 1; *list
&& !isspace(*list
); list
++);
205 while (isspace(*list
))
214 default : /* Unknown command */
215 syslog(LOG_ERR
, "Unknown LPD command 0x%02X!", command
);
216 syslog(LOG_ERR
, "Command line = %s", line
+ 1);
222 case 0x01 : /* Print any waiting jobs */
223 syslog(LOG_INFO
, "Print waiting jobs (no-op)");
229 case 0x02 : /* Receive a printer job */
230 syslog(LOG_INFO
, "Receive print job for %s", dest
);
233 status
= recv_print_job(dest
, num_defaults
, defaults
);
236 case 0x03 : /* Send queue state (short) */
237 syslog(LOG_INFO
, "Send queue state (short) for %s %s", dest
, list
);
240 status
= send_state(dest
, list
, 0);
243 case 0x04 : /* Send queue state (long) */
244 syslog(LOG_INFO
, "Send queue state (long) for %s %s", dest
, list
);
247 status
= send_state(dest
, list
, 1);
250 case 0x05 : /* Remove jobs */
254 * Grab the agent and skip to the list of users and/or jobs.
259 for (; *list
&& !isspace(*list
); list
++);
260 while (isspace(*list
))
263 syslog(LOG_INFO
, "Remove jobs %s on %s by %s", list
, dest
, agent
);
265 status
= remove_jobs(dest
, agent
, list
);
269 syslog(LOG_INFO
, "Closing connection");
277 * 'print_file()' - Print a file to a printer or class.
281 print_file(const char *name
, /* I - Printer or class name */
282 const char *file
, /* I - File to print */
283 const char *title
, /* I - Title of job */
284 const char *docname
, /* I - Name of job file */
285 const char *user
, /* I - Title of job */
286 int num_options
, /* I - Number of options */
287 cups_option_t
*options
) /* I - Options */
289 http_t
*http
; /* Connection to server */
290 ipp_t
*request
; /* IPP request */
291 ipp_t
*response
; /* IPP response */
292 ipp_attribute_t
*attr
; /* IPP job-id attribute */
293 char uri
[HTTP_MAX_URI
]; /* Printer URI */
294 cups_lang_t
*language
; /* Language to use */
295 int jobid
; /* New job ID */
299 * Setup a connection and request data...
302 if ((http
= httpConnectEncrypt(cupsServer(), ippPort(),
303 cupsEncryption())) == NULL
)
305 syslog(LOG_ERR
, "Unable to connect to server: %s", strerror(errno
));
309 language
= cupsLangDefault();
312 * Build a standard CUPS URI for the printer and fill the standard IPP
316 if ((request
= ippNew()) == NULL
)
318 syslog(LOG_ERR
, "Unable to create request: %s", strerror(errno
));
322 request
->request
.op
.operation_id
= IPP_PRINT_JOB
;
323 request
->request
.op
.request_id
= 1;
325 snprintf(uri
, sizeof(uri
), "ipp://localhost/printers/%s", name
);
327 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
328 "attributes-charset", NULL
, cupsLangEncoding(language
));
330 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
331 "attributes-natural-language", NULL
,
332 language
!= NULL
? language
->language
: "C");
334 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
337 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name",
341 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "job-name", NULL
, title
);
343 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "document-name", NULL
, docname
);
346 * Then add all options on the command-line...
349 cupsEncodeOptions(request
, num_options
, options
);
355 snprintf(uri
, sizeof(uri
), "/printers/%s", name
);
357 response
= cupsDoFileRequest(http
, request
, uri
, file
);
359 if (response
== NULL
)
361 else if (response
->request
.status
.status_code
> IPP_OK_CONFLICT
)
363 else if ((attr
= ippFindAttribute(response
, "job-id", IPP_TAG_INTEGER
)) == NULL
)
366 jobid
= attr
->values
[0].integer
;
368 if (response
!= NULL
)
372 cupsLangFree(language
);
375 syslog(LOG_INFO
, "Print file - job ID = %d", jobid
);
382 * 'recv_print_job()' - Receive a print job from the client.
385 int /* O - Command status */
386 recv_print_job(const char *dest
, /* I - Destination */
387 int num_defaults
,/* I - Number of default options */
388 cups_option_t
*defaults
) /* I - Default options */
390 int i
; /* Looping var */
391 int status
; /* Command status */
392 int fd
; /* Temporary file */
393 FILE *fp
; /* File pointer */
394 char filename
[1024]; /* Temporary filename */
395 int bytes
; /* Bytes received */
396 char line
[256], /* Line from file/stdin */
397 command
, /* Command from line */
398 *count
, /* Number of bytes */
399 *name
; /* Name of file */
400 int num_data
; /* Number of data files */
401 char control
[1024], /* Control filename */
402 data
[32][256], /* Data files */
403 temp
[32][1024]; /* Temporary files */
404 char user
[1024], /* User name */
405 title
[1024], /* Job title */
406 docname
[1024], /* Document name */
407 queue
[256], /* Printer/class queue */
408 *instance
; /* Printer/class instance */
409 int num_dests
; /* Number of destinations */
410 cups_dest_t
*dests
, /* Destinations */
411 *destptr
; /* Current destination */
412 int num_options
; /* Number of options */
413 cups_option_t
*options
; /* Options */
414 int banner
; /* Print banner? */
420 strncpy(queue
, dest
, sizeof(queue
) - 1);
421 queue
[sizeof(queue
) - 1] = '\0';
423 if ((instance
= strrchr(queue
, '/')) != NULL
)
426 num_dests
= cupsGetDests(&dests
);
427 if ((destptr
= cupsGetDest(queue
, instance
, num_dests
, dests
)) == NULL
)
430 syslog(LOG_ERR
, "Unknown destination %s/%s!", queue
, instance
);
432 syslog(LOG_ERR
, "Unknown destination %s!", queue
);
434 cupsFreeDests(num_dests
, dests
);
438 while (smart_gets(line
, sizeof(line
), stdin
) != NULL
)
440 if (strlen(line
) < 2)
449 for (name
= count
+ 1; *name
&& !isspace(*name
); name
++);
450 while (isspace(*name
))
456 case 0x01 : /* Abort */
459 case 0x02 : /* Receive control file */
460 if (strlen(name
) < 2)
462 syslog(LOG_ERR
, "Bad control file name \"%s\"", name
);
468 if ((fd
= cupsTempFd(control
, sizeof(control
))) < 0)
470 syslog(LOG_ERR
, "Unable to open temporary control file - %s",
477 strcpy(filename
, control
);
479 case 0x03 : /* Receive data file */
480 if (strlen(name
) < 2)
482 syslog(LOG_ERR
, "Bad data file name \"%s\"", name
);
488 if (num_data
>= (sizeof(data
) / sizeof(data
[0])))
491 * Too many data files...
494 syslog(LOG_ERR
, "Too many data files (%d)", num_data
);
500 strncpy(data
[num_data
], name
, sizeof(data
[0]) - 1);
501 data
[num_data
][sizeof(data
[0]) - 1] = '\0';
503 if ((fd
= cupsTempFd(temp
[num_data
], sizeof(temp
[0]))) < 0)
505 syslog(LOG_ERR
, "Unable to open temporary data file - %s",
512 strcpy(filename
, temp
[num_data
]);
524 * Copy the data or control file from the client...
527 for (i
= atoi(count
); i
> 0; i
-= bytes
)
529 if (i
> sizeof(line
))
530 bytes
= sizeof(line
);
534 if ((bytes
= fread(line
, 1, bytes
, stdin
)) > 0)
535 bytes
= write(fd
, line
, bytes
);
539 syslog(LOG_ERR
, "Error while reading file - %s",
547 * Read trailing nul...
552 if (fread(line
, 1, 1, stdin
) < 1)
555 syslog(LOG_ERR
, "Error while reading trailing nul - %s",
561 syslog(LOG_ERR
, "Trailing character after file is not nul (%02X)!",
567 * Close the file and send an acknowledgement...
581 * Process the control file and print stuff...
584 if ((fp
= fopen(control
, "rb")) == NULL
)
589 * Grab the job information first...
597 while (smart_gets(line
, sizeof(line
), fp
) != NULL
)
600 * Process control lines...
605 case 'J' : /* Job name */
606 strncpy(title
, line
+ 1, sizeof(title
) - 1);
607 title
[sizeof(title
) - 1] = '\0';
609 case 'N' : /* Document name */
610 strncpy(docname
, line
+ 1, sizeof(docname
) - 1);
611 docname
[sizeof(docname
) - 1] = '\0';
613 case 'P' : /* User identification */
614 strncpy(user
, line
+ 1, sizeof(user
) - 1);
615 user
[sizeof(user
) - 1] = '\0';
617 case 'L' : /* Print banner page */
627 * Then print the jobs...
632 while (smart_gets(line
, sizeof(line
), fp
) != NULL
)
635 * Process control lines...
640 case 'c' : /* Plot CIF file */
641 case 'd' : /* Print DVI file */
642 case 'f' : /* Print formatted file */
643 case 'g' : /* Plot file */
644 case 'l' : /* Print file leaving control characters (raw) */
645 case 'n' : /* Print ditroff output file */
646 case 'o' : /* Print PostScript output file */
647 case 'p' : /* Print file with 'pr' format (prettyprint) */
648 case 'r' : /* File to print with FORTRAN carriage control */
649 case 't' : /* Print troff output file */
650 case 'v' : /* Print raster file */
652 * Verify that we have a username...
662 * Copy the default options...
668 for (i
= 0; i
< num_defaults
; i
++)
669 num_options
= cupsAddOption(defaults
[i
].name
,
671 num_options
, &options
);
672 for (i
= 0; i
< destptr
->num_options
; i
++)
673 num_options
= cupsAddOption(destptr
->options
[i
].name
,
674 destptr
->options
[i
].value
,
675 num_options
, &options
);
678 * Add additional options as needed...
682 num_options
= cupsAddOption("job-sheets", "none",
683 num_options
, &options
);
686 num_options
= cupsAddOption("raw", "", num_options
, &options
);
689 num_options
= cupsAddOption("prettyprint", "", num_options
,
693 * Figure out which file we are printing...
696 for (i
= 0; i
< num_data
; i
++)
697 if (strcmp(data
[i
], line
+ 1) == 0)
707 * Send the print request...
710 if (print_file(queue
, temp
[i
], title
, docname
, user
, num_options
,
716 cupsFreeOptions(num_options
, options
);
729 * Clean up all temporary files and return...
734 for (i
= 0; i
< num_data
; i
++)
737 cupsFreeDests(num_dests
, dests
);
744 * 'remove_jobs()' - Cancel one or more jobs.
747 int /* O - Command status */
748 remove_jobs(const char *dest
, /* I - Destination */
749 const char *agent
, /* I - User agent */
750 const char *list
) /* I - List of jobs or users */
753 http_t
*http
; /* HTTP server connection */
754 ipp_t
*request
, /* IPP Request */
755 *response
; /* IPP Response */
756 cups_lang_t
*language
; /* Default language */
757 char uri
[HTTP_MAX_URI
]; /* Job URI */
760 (void)dest
; /* Suppress compiler warnings... */
763 * Try connecting to the local server...
766 if ((http
= httpConnectEncrypt(cupsServer(), ippPort(),
767 cupsEncryption())) == NULL
)
770 language
= cupsLangDefault();
773 * Loop for each job...
776 while ((id
= atoi(list
)) > 0)
779 * Skip job ID in list...
782 while (isdigit(*list
))
784 while (isspace(*list
))
788 * Build an IPP_CANCEL_JOB request, which requires the following
792 * attributes-natural-language
794 * requesting-user-name
799 request
->request
.op
.operation_id
= IPP_CANCEL_JOB
;
800 request
->request
.op
.request_id
= 1;
802 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
803 "attributes-charset", NULL
, cupsLangEncoding(language
));
805 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
806 "attributes-natural-language", NULL
, language
->language
);
808 sprintf(uri
, "ipp://localhost/jobs/%d", id
);
809 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "job-uri", NULL
, uri
);
811 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
,
812 "requesting-user-name", NULL
, agent
);
815 * Do the request and get back a response...
818 if ((response
= cupsDoRequest(http
, request
, "/jobs")) != NULL
)
820 if (response
->request
.status
.status_code
> IPP_OK_CONFLICT
)
822 syslog(LOG_WARNING
, "Cancel of job ID %d failed: %s\n", id
,
823 ippErrorString(response
->request
.status
.status_code
));
825 cupsLangFree(language
);
830 syslog(LOG_INFO
, "Job ID %d cancelled", id
);
836 syslog(LOG_WARNING
, "Cancel of job ID %d failed: %s\n", id
,
837 ippErrorString(cupsLastError()));
838 cupsLangFree(language
);
844 cupsLangFree(language
);
852 * 'send_short_state()' - Send the short queue state.
855 int /* O - Command status */
856 send_state(const char *dest
, /* I - Destination */
857 const char *list
, /* I - Job or user */
858 int longstatus
) /* I - List of jobs or users */
860 int id
; /* Job ID from list */
861 http_t
*http
; /* HTTP server connection */
862 ipp_t
*request
, /* IPP Request */
863 *response
; /* IPP Response */
864 ipp_attribute_t
*attr
; /* Current attribute */
865 cups_lang_t
*language
; /* Default language */
866 ipp_pstate_t state
; /* Printer state */
867 const char *jobdest
, /* Pointer into job-printer-uri */
868 *jobuser
, /* Pointer to job-originating-user-name */
869 *jobname
; /* Pointer to job-name */
870 ipp_jstate_t jobstate
; /* job-state */
871 int jobid
, /* job-id */
872 jobsize
, /* job-k-octets */
873 jobcount
, /* Number of jobs */
874 jobcopies
, /* Number of copies */
875 rank
; /* Rank of job */
876 char rankstr
[255]; /* Rank string */
877 char namestr
[1024]; /* Job name string */
878 char uri
[HTTP_MAX_URI
]; /* Printer URI */
879 char queue
[256], /* Printer/class queue */
880 *instance
; /* Printer/class instance */
881 static const char *ranks
[10] = /* Ranking strings */
894 static const char *requested
[] = /* Requested attributes */
900 "job-originating-user-name",
907 * Remove instance from destination, if any...
910 strncpy(queue
, dest
, sizeof(queue
) - 1);
911 queue
[sizeof(queue
) - 1] = '\0';
913 if ((instance
= strrchr(queue
, '/')) != NULL
)
917 * Try connecting to the local server...
920 if ((http
= httpConnectEncrypt(cupsServer(), ippPort(),
921 cupsEncryption())) == NULL
)
925 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the following
929 * attributes-natural-language
935 request
->request
.op
.operation_id
= IPP_GET_PRINTER_ATTRIBUTES
;
936 request
->request
.op
.request_id
= 1;
938 language
= cupsLangDefault();
940 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
941 "attributes-charset", NULL
, cupsLangEncoding(language
));
943 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
944 "attributes-natural-language", NULL
, language
->language
);
946 snprintf(uri
, sizeof(uri
), "ipp://localhost/printers/%s", queue
);
947 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
,
948 "printer-uri", NULL
, uri
);
950 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
951 "requested-attributes", NULL
, "printer-state");
954 * Do the request and get back a response...
957 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
959 if (response
->request
.status
.status_code
> IPP_OK_CONFLICT
)
961 syslog(LOG_WARNING
, "Unable to get printer list: %s\n",
962 ippErrorString(response
->request
.status
.status_code
));
967 if ((attr
= ippFindAttribute(response
, "printer-state", IPP_TAG_ENUM
)) != NULL
)
968 state
= (ipp_pstate_t
)attr
->values
[0].integer
;
970 state
= IPP_PRINTER_STOPPED
;
974 case IPP_PRINTER_IDLE
:
975 printf("%s is ready\n", dest
);
977 case IPP_PRINTER_PROCESSING
:
978 printf("%s is ready and printing\n", dest
);
980 case IPP_PRINTER_STOPPED
:
981 printf("%s is not ready\n", dest
);
989 syslog(LOG_WARNING
, "Unable to get printer list: %s\n",
990 ippErrorString(cupsLastError()));
995 * Build an IPP_GET_JOBS or IPP_GET_JOB_ATTRIBUTES request, which requires
996 * the following attributes:
999 * attributes-natural-language
1000 * job-uri or printer-uri
1007 request
->request
.op
.operation_id
= id
? IPP_GET_JOB_ATTRIBUTES
: IPP_GET_JOBS
;
1008 request
->request
.op
.request_id
= 1;
1010 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
1011 "attributes-charset", NULL
, cupsLangEncoding(language
));
1013 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
1014 "attributes-natural-language", NULL
, language
->language
);
1016 snprintf(uri
, sizeof(uri
), "ipp://localhost/printers/%s", queue
);
1018 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1022 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_INTEGER
, "job-id", id
);
1025 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
,
1026 "requesting-user-name", NULL
, list
);
1027 ippAddBoolean(request
, IPP_TAG_OPERATION
, "my-jobs", 1);
1030 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
1031 "requested-attributes", sizeof(requested
) / sizeof(requested
[0]),
1035 * Do the request and get back a response...
1040 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
1042 if (response
->request
.status
.status_code
> IPP_OK_CONFLICT
)
1044 printf("get-jobs failed: %s\n",
1045 ippErrorString(response
->request
.status
.status_code
));
1046 ippDelete(response
);
1053 * Loop through the job list and display them...
1056 for (attr
= response
->attrs
; attr
!= NULL
; attr
= attr
->next
)
1059 * Skip leading attributes until we hit a job...
1062 while (attr
!= NULL
&&
1063 (attr
->group_tag
!= IPP_TAG_JOB
|| attr
->name
== NULL
))
1070 * Pull the needed attributes from this job...
1075 jobstate
= IPP_JOB_PENDING
;
1076 jobname
= "untitled";
1081 while (attr
!= NULL
&& attr
->group_tag
== IPP_TAG_JOB
)
1083 if (strcmp(attr
->name
, "job-id") == 0 &&
1084 attr
->value_tag
== IPP_TAG_INTEGER
)
1085 jobid
= attr
->values
[0].integer
;
1087 if (strcmp(attr
->name
, "job-k-octets") == 0 &&
1088 attr
->value_tag
== IPP_TAG_INTEGER
)
1089 jobsize
= attr
->values
[0].integer
* 1024;
1091 if (strcmp(attr
->name
, "job-state") == 0 &&
1092 attr
->value_tag
== IPP_TAG_ENUM
)
1093 jobstate
= (ipp_jstate_t
)attr
->values
[0].integer
;
1095 if (strcmp(attr
->name
, "job-printer-uri") == 0 &&
1096 attr
->value_tag
== IPP_TAG_URI
)
1097 if ((jobdest
= strrchr(attr
->values
[0].string
.text
, '/')) != NULL
)
1100 if (strcmp(attr
->name
, "job-originating-user-name") == 0 &&
1101 attr
->value_tag
== IPP_TAG_NAME
)
1102 jobuser
= attr
->values
[0].string
.text
;
1104 if (strcmp(attr
->name
, "job-name") == 0 &&
1105 attr
->value_tag
== IPP_TAG_NAME
)
1106 jobname
= attr
->values
[0].string
.text
;
1108 if (strcmp(attr
->name
, "copies") == 0 &&
1109 attr
->value_tag
== IPP_TAG_INTEGER
)
1110 jobcopies
= attr
->values
[0].integer
;
1116 * See if we have everything needed...
1119 if (jobdest
== NULL
|| jobid
== 0)
1127 if (!longstatus
&& jobcount
== 0)
1128 puts("Rank Owner Job File(s) Total Size");
1133 * Display the job...
1136 if (jobstate
== IPP_JOB_PROCESSING
)
1137 strcpy(rankstr
, "active");
1140 snprintf(rankstr
, sizeof(rankstr
), "%d%s", rank
, ranks
[rank
% 10]);
1149 snprintf(namestr
, sizeof(namestr
), "%d copies of %s", jobcopies
,
1153 strncpy(namestr
, jobname
, sizeof(namestr
) - 1);
1154 namestr
[sizeof(namestr
) - 1] = '\0';
1157 printf("%s: %-34.34s[job %d localhost]\n", jobuser
, rankstr
, jobid
);
1158 printf(" %-40.40s%d bytes\n", namestr
, jobsize
);
1161 printf("%-7s %-8.8s%-8d%-32.32s%d bytes\n", rankstr
, jobuser
,
1162 jobid
, jobname
, jobsize
);
1168 ippDelete(response
);
1172 printf("get-jobs failed: %s\n", ippErrorString(cupsLastError()));
1179 cupsLangFree(language
);
1187 * 'smart_gets()' - Get a line of text, removing the trailing CR and/or LF.
1190 char * /* O - Line read or NULL */
1191 smart_gets(char *s
, /* I - Pointer to line buffer */
1192 int len
, /* I - Size of line buffer */
1193 FILE *fp
) /* I - File to read from */
1195 char *ptr
, /* Pointer into line */
1196 *end
; /* End of line */
1197 int ch
; /* Character from file */
1201 * Read the line; unlike fgets(), we read the entire line but dump
1202 * characters that go past the end of the buffer. Also, we accept
1203 * CR, LF, or CR LF for the line endings to be "safe", although
1204 * RFC 1179 specifically says "just use LF".
1210 while ((ch
= getc(fp
)) != EOF
)
1214 else if (ch
== '\r')
1217 * See if a LF follows...
1233 if (ch
== EOF
&& ptr
== s
)
1241 * End of "$Id: cups-lpd.c,v 1.24.2.2 2001/05/13 18:38:34 mike Exp $".