2 * "$Id: cups-lpd.c,v 1.24 2001/03/30 15:23:29 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 unsigned hostip
; /* (32-bit) IP address */
106 struct sockaddr_in hostaddr
; /* Address of client */
107 struct hostent
*hostname
; /* Name of client */
111 * Don't buffer the output...
114 setbuf(stdout
, NULL
);
117 * Log things using the "cups-lpd" name...
120 openlog("cups-lpd", LOG_PID
, LOG_LPR
);
123 * Get the address of the client...
126 hostlen
= sizeof(hostaddr
);
128 if (getpeername(0, (struct sockaddr
*)&hostaddr
, &hostlen
))
129 syslog(LOG_WARNING
, "Unable to get client address - %s", strerror(errno
));
132 hostip
= ntohl(hostaddr
.sin_addr
.s_addr
);
133 hostname
= gethostbyaddr((void *)&hostaddr
, hostlen
, AF_INET
);
135 syslog(LOG_INFO
, "Connection from %s (%d.%d.%d.%d)",
136 hostname
? hostname
->h_name
: "unknown",
137 (hostip
>> 24) & 255, (hostip
>> 16) & 255,
138 (hostip
>> 8) & 255, hostip
& 255);
142 * Scan the command-line for options...
148 for (i
= 1; i
< argc
; i
++)
149 if (argv
[i
][0] == '-')
153 case 'o' : /* Option */
155 num_defaults
= cupsParseOptions(argv
[i
] + 2, num_defaults
,
161 num_defaults
= cupsParseOptions(argv
[i
], num_defaults
, &defaults
);
163 syslog(LOG_WARNING
, "Expected option string after -o option!");
167 syslog(LOG_WARNING
, "Unknown option \"%c\" ignored!", argv
[i
][1]);
172 syslog(LOG_WARNING
, "Unknown command-line option \"%s\" ignored!", argv
[i
]);
175 * RFC1179 specifies that only 1 daemon command can be received for
179 if (smart_gets(line
, sizeof(line
), stdin
) == NULL
)
182 * Unable to get command from client! Send an error status and return.
185 syslog(LOG_ERR
, "Unable to get command line from client!");
191 * The first byte is the command byte. After that will be the queue name,
192 * resource list, and/or user name.
198 for (list
= dest
+ 1; *list
&& !isspace(*list
); list
++);
200 while (isspace(*list
))
209 default : /* Unknown command */
210 syslog(LOG_ERR
, "Unknown LPD command 0x%02X!", command
);
211 syslog(LOG_ERR
, "Command line = %s", line
+ 1);
217 case 0x01 : /* Print any waiting jobs */
218 syslog(LOG_INFO
, "Print waiting jobs (no-op)");
224 case 0x02 : /* Receive a printer job */
225 syslog(LOG_INFO
, "Receive print job for %s", dest
);
228 status
= recv_print_job(dest
, num_defaults
, defaults
);
231 case 0x03 : /* Send queue state (short) */
232 syslog(LOG_INFO
, "Send queue state (short) for %s %s", dest
, list
);
235 status
= send_state(dest
, list
, 0);
238 case 0x04 : /* Send queue state (long) */
239 syslog(LOG_INFO
, "Send queue state (long) for %s %s", dest
, list
);
242 status
= send_state(dest
, list
, 1);
245 case 0x05 : /* Remove jobs */
249 * Grab the agent and skip to the list of users and/or jobs.
254 for (; *list
&& !isspace(*list
); list
++);
255 while (isspace(*list
))
258 syslog(LOG_INFO
, "Remove jobs %s on %s by %s", list
, dest
, agent
);
260 status
= remove_jobs(dest
, agent
, list
);
264 syslog(LOG_INFO
, "Closing connection");
272 * 'print_file()' - Print a file to a printer or class.
276 print_file(const char *name
, /* I - Printer or class name */
277 const char *file
, /* I - File to print */
278 const char *title
, /* I - Title of job */
279 const char *docname
, /* I - Name of job file */
280 const char *user
, /* I - Title of job */
281 int num_options
, /* I - Number of options */
282 cups_option_t
*options
) /* I - Options */
284 http_t
*http
; /* Connection to server */
285 ipp_t
*request
; /* IPP request */
286 ipp_t
*response
; /* IPP response */
287 ipp_attribute_t
*attr
; /* IPP job-id attribute */
288 char uri
[HTTP_MAX_URI
]; /* Printer URI */
289 cups_lang_t
*language
; /* Language to use */
290 int jobid
; /* New job ID */
294 * Setup a connection and request data...
297 if ((http
= httpConnect(cupsServer(), ippPort())) == NULL
)
299 syslog(LOG_ERR
, "Unable to connect to server: %s", strerror(errno
));
303 language
= cupsLangDefault();
306 * Build a standard CUPS URI for the printer and fill the standard IPP
310 if ((request
= ippNew()) == NULL
)
312 syslog(LOG_ERR
, "Unable to create request: %s", strerror(errno
));
316 request
->request
.op
.operation_id
= IPP_PRINT_JOB
;
317 request
->request
.op
.request_id
= 1;
319 snprintf(uri
, sizeof(uri
), "ipp://localhost/printers/%s", name
);
321 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
322 "attributes-charset", NULL
, cupsLangEncoding(language
));
324 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
325 "attributes-natural-language", NULL
,
326 language
!= NULL
? language
->language
: "C");
328 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
331 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name",
335 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "job-name", NULL
, title
);
337 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "document-name", NULL
, docname
);
340 * Then add all options on the command-line...
343 cupsEncodeOptions(request
, num_options
, options
);
349 snprintf(uri
, sizeof(uri
), "/printers/%s", name
);
351 response
= cupsDoFileRequest(http
, request
, uri
, file
);
353 if (response
== NULL
)
355 else if (response
->request
.status
.status_code
> IPP_OK_CONFLICT
)
357 else if ((attr
= ippFindAttribute(response
, "job-id", IPP_TAG_INTEGER
)) == NULL
)
360 jobid
= attr
->values
[0].integer
;
362 if (response
!= NULL
)
366 cupsLangFree(language
);
369 syslog(LOG_INFO
, "Print file - job ID = %d", jobid
);
376 * 'recv_print_job()' - Receive a print job from the client.
379 int /* O - Command status */
380 recv_print_job(const char *dest
, /* I - Destination */
381 int num_defaults
,/* I - Number of default options */
382 cups_option_t
*defaults
) /* I - Default options */
384 int i
; /* Looping var */
385 int status
; /* Command status */
386 int fd
; /* Temporary file */
387 FILE *fp
; /* File pointer */
388 char filename
[1024]; /* Temporary filename */
389 int bytes
; /* Bytes received */
390 char line
[256], /* Line from file/stdin */
391 command
, /* Command from line */
392 *count
, /* Number of bytes */
393 *name
; /* Name of file */
394 int num_data
; /* Number of data files */
395 char control
[1024], /* Control filename */
396 data
[32][256], /* Data files */
397 temp
[32][1024]; /* Temporary files */
398 char user
[1024], /* User name */
399 title
[1024], /* Job title */
400 docname
[1024], /* Document name */
401 queue
[256], /* Printer/class queue */
402 *instance
; /* Printer/class instance */
403 int num_dests
; /* Number of destinations */
404 cups_dest_t
*dests
, /* Destinations */
405 *destptr
; /* Current destination */
406 int num_options
; /* Number of options */
407 cups_option_t
*options
; /* Options */
408 int banner
; /* Print banner? */
414 strncpy(queue
, dest
, sizeof(queue
) - 1);
415 queue
[sizeof(queue
) - 1] = '\0';
417 if ((instance
= strrchr(queue
, '/')) != NULL
)
420 num_dests
= cupsGetDests(&dests
);
421 if ((destptr
= cupsGetDest(queue
, instance
, num_dests
, dests
)) == NULL
)
424 syslog(LOG_ERR
, "Unknown destination %s/%s!", queue
, instance
);
426 syslog(LOG_ERR
, "Unknown destination %s!", queue
);
428 cupsFreeDests(num_dests
, dests
);
432 while (smart_gets(line
, sizeof(line
), stdin
) != NULL
)
434 if (strlen(line
) < 2)
443 for (name
= count
+ 1; *name
&& !isspace(*name
); name
++);
444 while (isspace(*name
))
450 case 0x01 : /* Abort */
453 case 0x02 : /* Receive control file */
454 if (strlen(name
) < 2)
456 syslog(LOG_ERR
, "Bad control file name \"%s\"", name
);
462 if ((fd
= cupsTempFd(control
, sizeof(control
))) < 0)
464 syslog(LOG_ERR
, "Unable to open temporary control file - %s",
471 strcpy(filename
, control
);
473 case 0x03 : /* Receive data file */
474 if (strlen(name
) < 2)
476 syslog(LOG_ERR
, "Bad data file name \"%s\"", name
);
482 if (num_data
>= (sizeof(data
) / sizeof(data
[0])))
485 * Too many data files...
488 syslog(LOG_ERR
, "Too many data files (%d)", num_data
);
494 strncpy(data
[num_data
], name
, sizeof(data
[0]) - 1);
495 data
[num_data
][sizeof(data
[0]) - 1] = '\0';
497 if ((fd
= cupsTempFd(temp
[num_data
], sizeof(temp
[0]))) < 0)
499 syslog(LOG_ERR
, "Unable to open temporary data file - %s",
506 strcpy(filename
, temp
[num_data
]);
518 * Copy the data or control file from the client...
521 for (i
= atoi(count
); i
> 0; i
-= bytes
)
523 if (i
> sizeof(line
))
524 bytes
= sizeof(line
);
528 if ((bytes
= fread(line
, 1, bytes
, stdin
)) > 0)
529 bytes
= write(fd
, line
, bytes
);
533 syslog(LOG_ERR
, "Error while reading file - %s",
541 * Read trailing nul...
546 if (fread(line
, 1, 1, stdin
) < 1)
549 syslog(LOG_ERR
, "Error while reading trailing nul - %s",
555 syslog(LOG_ERR
, "Trailing character after file is not nul (%02X)!",
561 * Close the file and send an acknowledgement...
575 * Process the control file and print stuff...
578 if ((fp
= fopen(control
, "rb")) == NULL
)
583 * Grab the job information first...
591 while (smart_gets(line
, sizeof(line
), fp
) != NULL
)
594 * Process control lines...
599 case 'J' : /* Job name */
600 strncpy(title
, line
+ 1, sizeof(title
) - 1);
601 title
[sizeof(title
) - 1] = '\0';
603 case 'N' : /* Document name */
604 strncpy(docname
, line
+ 1, sizeof(docname
) - 1);
605 docname
[sizeof(docname
) - 1] = '\0';
607 case 'P' : /* User identification */
608 strncpy(user
, line
+ 1, sizeof(user
) - 1);
609 user
[sizeof(user
) - 1] = '\0';
611 case 'L' : /* Print banner page */
621 * Then print the jobs...
626 while (smart_gets(line
, sizeof(line
), fp
) != NULL
)
629 * Process control lines...
634 case 'c' : /* Plot CIF file */
635 case 'd' : /* Print DVI file */
636 case 'f' : /* Print formatted file */
637 case 'g' : /* Plot file */
638 case 'l' : /* Print file leaving control characters (raw) */
639 case 'n' : /* Print ditroff output file */
640 case 'o' : /* Print PostScript output file */
641 case 'p' : /* Print file with 'pr' format (prettyprint) */
642 case 'r' : /* File to print with FORTRAN carriage control */
643 case 't' : /* Print troff output file */
644 case 'v' : /* Print raster file */
646 * Verify that we have a username...
656 * Copy the default options...
662 for (i
= 0; i
< num_defaults
; i
++)
663 num_options
= cupsAddOption(defaults
[i
].name
,
665 num_options
, &options
);
666 for (i
= 0; i
< destptr
->num_options
; i
++)
667 num_options
= cupsAddOption(destptr
->options
[i
].name
,
668 destptr
->options
[i
].value
,
669 num_options
, &options
);
672 * Add additional options as needed...
676 num_options
= cupsAddOption("job-sheets", "none",
677 num_options
, &options
);
680 num_options
= cupsAddOption("raw", "", num_options
, &options
);
683 num_options
= cupsAddOption("prettyprint", "", num_options
,
687 * Figure out which file we are printing...
690 for (i
= 0; i
< num_data
; i
++)
691 if (strcmp(data
[i
], line
+ 1) == 0)
701 * Send the print request...
704 if (print_file(queue
, temp
[i
], title
, docname
, user
, num_options
,
710 cupsFreeOptions(num_options
, options
);
723 * Clean up all temporary files and return...
728 for (i
= 0; i
< num_data
; i
++)
731 cupsFreeDests(num_dests
, dests
);
738 * 'remove_jobs()' - Cancel one or more jobs.
741 int /* O - Command status */
742 remove_jobs(const char *dest
, /* I - Destination */
743 const char *agent
, /* I - User agent */
744 const char *list
) /* I - List of jobs or users */
747 http_t
*http
; /* HTTP server connection */
748 ipp_t
*request
, /* IPP Request */
749 *response
; /* IPP Response */
750 cups_lang_t
*language
; /* Default language */
751 char uri
[HTTP_MAX_URI
]; /* Job URI */
754 (void)dest
; /* Suppress compiler warnings... */
757 * Try connecting to the local server...
760 if ((http
= httpConnect(cupsServer(), ippPort())) == NULL
)
763 language
= cupsLangDefault();
766 * Loop for each job...
769 while ((id
= atoi(list
)) > 0)
772 * Skip job ID in list...
775 while (isdigit(*list
))
777 while (isspace(*list
))
781 * Build an IPP_CANCEL_JOB request, which requires the following
785 * attributes-natural-language
787 * requesting-user-name
792 request
->request
.op
.operation_id
= IPP_CANCEL_JOB
;
793 request
->request
.op
.request_id
= 1;
795 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
796 "attributes-charset", NULL
, cupsLangEncoding(language
));
798 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
799 "attributes-natural-language", NULL
, language
->language
);
801 sprintf(uri
, "ipp://localhost/jobs/%d", id
);
802 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "job-uri", NULL
, uri
);
804 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
,
805 "requesting-user-name", NULL
, agent
);
808 * Do the request and get back a response...
811 if ((response
= cupsDoRequest(http
, request
, "/jobs")) != NULL
)
813 if (response
->request
.status
.status_code
> IPP_OK_CONFLICT
)
815 syslog(LOG_WARNING
, "Cancel of job ID %d failed: %s\n", id
,
816 ippErrorString(response
->request
.status
.status_code
));
818 cupsLangFree(language
);
823 syslog(LOG_INFO
, "Job ID %d cancelled", id
);
829 syslog(LOG_WARNING
, "Cancel of job ID %d failed: %s\n", id
,
830 ippErrorString(cupsLastError()));
831 cupsLangFree(language
);
837 cupsLangFree(language
);
845 * 'send_short_state()' - Send the short queue state.
848 int /* O - Command status */
849 send_state(const char *dest
, /* I - Destination */
850 const char *list
, /* I - Job or user */
851 int longstatus
) /* I - List of jobs or users */
853 int id
; /* Job ID from list */
854 http_t
*http
; /* HTTP server connection */
855 ipp_t
*request
, /* IPP Request */
856 *response
; /* IPP Response */
857 ipp_attribute_t
*attr
; /* Current attribute */
858 cups_lang_t
*language
; /* Default language */
859 ipp_pstate_t state
; /* Printer state */
860 const char *jobdest
, /* Pointer into job-printer-uri */
861 *jobuser
, /* Pointer to job-originating-user-name */
862 *jobname
; /* Pointer to job-name */
863 ipp_jstate_t jobstate
; /* job-state */
864 int jobid
, /* job-id */
865 jobsize
, /* job-k-octets */
866 jobcount
, /* Number of jobs */
867 jobcopies
, /* Number of copies */
868 rank
; /* Rank of job */
869 char rankstr
[255]; /* Rank string */
870 char namestr
[1024]; /* Job name string */
871 char uri
[HTTP_MAX_URI
]; /* Printer URI */
872 char queue
[256], /* Printer/class queue */
873 *instance
; /* Printer/class instance */
874 static const char *ranks
[10] = /* Ranking strings */
887 static const char *requested
[] = /* Requested attributes */
893 "job-originating-user-name",
900 * Remove instance from destination, if any...
903 strncpy(queue
, dest
, sizeof(queue
) - 1);
904 queue
[sizeof(queue
) - 1] = '\0';
906 if ((instance
= strrchr(queue
, '/')) != NULL
)
910 * Try connecting to the local server...
913 if ((http
= httpConnect(cupsServer(), ippPort())) == NULL
)
917 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the following
921 * attributes-natural-language
927 request
->request
.op
.operation_id
= IPP_GET_PRINTER_ATTRIBUTES
;
928 request
->request
.op
.request_id
= 1;
930 language
= cupsLangDefault();
932 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
933 "attributes-charset", NULL
, cupsLangEncoding(language
));
935 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
936 "attributes-natural-language", NULL
, language
->language
);
938 snprintf(uri
, sizeof(uri
), "ipp://localhost/printers/%s", queue
);
939 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
,
940 "printer-uri", NULL
, uri
);
942 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
943 "requested-attributes", NULL
, "printer-state");
946 * Do the request and get back a response...
949 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
951 if (response
->request
.status
.status_code
> IPP_OK_CONFLICT
)
953 syslog(LOG_WARNING
, "Unable to get printer list: %s\n",
954 ippErrorString(response
->request
.status
.status_code
));
959 if ((attr
= ippFindAttribute(response
, "printer-state", IPP_TAG_ENUM
)) != NULL
)
960 state
= (ipp_pstate_t
)attr
->values
[0].integer
;
962 state
= IPP_PRINTER_STOPPED
;
966 case IPP_PRINTER_IDLE
:
967 printf("%s is ready\n", dest
);
969 case IPP_PRINTER_PROCESSING
:
970 printf("%s is ready and printing\n", dest
);
972 case IPP_PRINTER_STOPPED
:
973 printf("%s is not ready\n", dest
);
981 syslog(LOG_WARNING
, "Unable to get printer list: %s\n",
982 ippErrorString(cupsLastError()));
987 * Build an IPP_GET_JOBS or IPP_GET_JOB_ATTRIBUTES request, which requires
988 * the following attributes:
991 * attributes-natural-language
992 * job-uri or printer-uri
999 request
->request
.op
.operation_id
= id
? IPP_GET_JOB_ATTRIBUTES
: IPP_GET_JOBS
;
1000 request
->request
.op
.request_id
= 1;
1002 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
1003 "attributes-charset", NULL
, cupsLangEncoding(language
));
1005 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
1006 "attributes-natural-language", NULL
, language
->language
);
1008 snprintf(uri
, sizeof(uri
), "ipp://localhost/printers/%s", queue
);
1010 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1014 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_INTEGER
, "job-id", id
);
1017 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
,
1018 "requesting-user-name", NULL
, list
);
1019 ippAddBoolean(request
, IPP_TAG_OPERATION
, "my-jobs", 1);
1022 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
1023 "requested-attributes", sizeof(requested
) / sizeof(requested
[0]),
1027 * Do the request and get back a response...
1032 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
1034 if (response
->request
.status
.status_code
> IPP_OK_CONFLICT
)
1036 printf("get-jobs failed: %s\n",
1037 ippErrorString(response
->request
.status
.status_code
));
1038 ippDelete(response
);
1045 * Loop through the job list and display them...
1048 for (attr
= response
->attrs
; attr
!= NULL
; attr
= attr
->next
)
1051 * Skip leading attributes until we hit a job...
1054 while (attr
!= NULL
&&
1055 (attr
->group_tag
!= IPP_TAG_JOB
|| attr
->name
== NULL
))
1062 * Pull the needed attributes from this job...
1067 jobstate
= IPP_JOB_PENDING
;
1068 jobname
= "untitled";
1073 while (attr
!= NULL
&& attr
->group_tag
== IPP_TAG_JOB
)
1075 if (strcmp(attr
->name
, "job-id") == 0 &&
1076 attr
->value_tag
== IPP_TAG_INTEGER
)
1077 jobid
= attr
->values
[0].integer
;
1079 if (strcmp(attr
->name
, "job-k-octets") == 0 &&
1080 attr
->value_tag
== IPP_TAG_INTEGER
)
1081 jobsize
= attr
->values
[0].integer
* 1024;
1083 if (strcmp(attr
->name
, "job-state") == 0 &&
1084 attr
->value_tag
== IPP_TAG_ENUM
)
1085 jobstate
= (ipp_jstate_t
)attr
->values
[0].integer
;
1087 if (strcmp(attr
->name
, "job-printer-uri") == 0 &&
1088 attr
->value_tag
== IPP_TAG_URI
)
1089 if ((jobdest
= strrchr(attr
->values
[0].string
.text
, '/')) != NULL
)
1092 if (strcmp(attr
->name
, "job-originating-user-name") == 0 &&
1093 attr
->value_tag
== IPP_TAG_NAME
)
1094 jobuser
= attr
->values
[0].string
.text
;
1096 if (strcmp(attr
->name
, "job-name") == 0 &&
1097 attr
->value_tag
== IPP_TAG_NAME
)
1098 jobname
= attr
->values
[0].string
.text
;
1100 if (strcmp(attr
->name
, "copies") == 0 &&
1101 attr
->value_tag
== IPP_TAG_INTEGER
)
1102 jobcopies
= attr
->values
[0].integer
;
1108 * See if we have everything needed...
1111 if (jobdest
== NULL
|| jobid
== 0)
1119 if (!longstatus
&& jobcount
== 0)
1120 puts("Rank Owner Job File(s) Total Size");
1125 * Display the job...
1128 if (jobstate
== IPP_JOB_PROCESSING
)
1129 strcpy(rankstr
, "active");
1132 snprintf(rankstr
, sizeof(rankstr
), "%d%s", rank
, ranks
[rank
% 10]);
1141 snprintf(namestr
, sizeof(namestr
), "%d copies of %s", jobcopies
,
1145 strncpy(namestr
, jobname
, sizeof(namestr
) - 1);
1146 namestr
[sizeof(namestr
) - 1] = '\0';
1149 printf("%s: %-34.34s[job %d localhost]\n", jobuser
, rankstr
, jobid
);
1150 printf(" %-40.40s%d bytes\n", namestr
, jobsize
);
1153 printf("%-7s %-8.8s%-8d%-32.32s%d bytes\n", rankstr
, jobuser
,
1154 jobid
, jobname
, jobsize
);
1160 ippDelete(response
);
1164 printf("get-jobs failed: %s\n", ippErrorString(cupsLastError()));
1171 cupsLangFree(language
);
1179 * 'smart_gets()' - Get a line of text, removing the trailing CR and/or LF.
1182 char * /* O - Line read or NULL */
1183 smart_gets(char *s
, /* I - Pointer to line buffer */
1184 int len
, /* I - Size of line buffer */
1185 FILE *fp
) /* I - File to read from */
1187 char *ptr
, /* Pointer into line */
1188 *end
; /* End of line */
1189 int ch
; /* Character from file */
1193 * Read the line; unlike fgets(), we read the entire line but dump
1194 * characters that go past the end of the buffer. Also, we accept
1195 * CR, LF, or CR LF for the line endings to be "safe", although
1196 * RFC 1179 specifically says "just use LF".
1202 while ((ch
= getc(fp
)) != EOF
)
1206 else if (ch
== '\r')
1209 * See if a LF follows...
1225 if (ch
== EOF
&& ptr
== s
)
1233 * End of "$Id: cups-lpd.c,v 1.24 2001/03/30 15:23:29 mike Exp $".