|
Packit |
2fc92b |
/*
|
|
Packit |
2fc92b |
* Mini-daemon utility functions for CUPS.
|
|
Packit |
2fc92b |
*
|
|
Packit |
2fc92b |
* Copyright 2007-2014 by Apple Inc.
|
|
Packit |
2fc92b |
* Copyright 1997-2005 by Easy Software Products.
|
|
Packit |
2fc92b |
*
|
|
Packit |
2fc92b |
* These coded instructions, statements, and computer programs are the
|
|
Packit |
2fc92b |
* property of Apple Inc. and are protected by Federal copyright
|
|
Packit |
2fc92b |
* law. Distribution and use rights are outlined in the file "LICENSE.txt"
|
|
Packit |
2fc92b |
* which should have been included with this file. If this file is
|
|
Packit |
2fc92b |
* missing or damaged, see the license at "http://www.cups.org/".
|
|
Packit |
2fc92b |
*/
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
/*
|
|
Packit |
2fc92b |
* Include necessary headers...
|
|
Packit |
2fc92b |
*/
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
#include "util.h"
|
|
Packit |
2fc92b |
#include <unistd.h>
|
|
Packit |
2fc92b |
#include <sys/stat.h>
|
|
Packit |
2fc92b |
#include <fcntl.h>
|
|
Packit |
2fc92b |
#ifdef __APPLE__
|
|
Packit |
2fc92b |
# include <libgen.h>
|
|
Packit |
2fc92b |
extern char **environ;
|
|
Packit |
2fc92b |
#endif /* __APPLE__ */
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
/*
|
|
Packit |
2fc92b |
* 'cupsdCompareNames()' - Compare two names.
|
|
Packit |
2fc92b |
*
|
|
Packit |
2fc92b |
* This function basically does a _cups_strcasecmp() of the two strings,
|
|
Packit |
2fc92b |
* but is also aware of numbers so that "a2" < "a100".
|
|
Packit |
2fc92b |
*/
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
int /* O - Result of comparison */
|
|
Packit |
2fc92b |
cupsdCompareNames(const char *s, /* I - First string */
|
|
Packit |
2fc92b |
const char *t) /* I - Second string */
|
|
Packit |
2fc92b |
{
|
|
Packit |
2fc92b |
int diff, /* Difference between digits */
|
|
Packit |
2fc92b |
digits; /* Number of digits */
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
/*
|
|
Packit |
2fc92b |
* Loop through both names, returning only when a difference is
|
|
Packit |
2fc92b |
* seen. Also, compare whole numbers rather than just characters, too!
|
|
Packit |
2fc92b |
*/
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
while (*s && *t)
|
|
Packit |
2fc92b |
{
|
|
Packit |
2fc92b |
if (isdigit(*s & 255) && isdigit(*t & 255))
|
|
Packit |
2fc92b |
{
|
|
Packit |
2fc92b |
/*
|
|
Packit |
2fc92b |
* Got a number; start by skipping leading 0's...
|
|
Packit |
2fc92b |
*/
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
while (*s == '0')
|
|
Packit |
2fc92b |
s ++;
|
|
Packit |
2fc92b |
while (*t == '0')
|
|
Packit |
2fc92b |
t ++;
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
/*
|
|
Packit |
2fc92b |
* Skip equal digits...
|
|
Packit |
2fc92b |
*/
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
while (isdigit(*s & 255) && *s == *t)
|
|
Packit |
2fc92b |
{
|
|
Packit |
2fc92b |
s ++;
|
|
Packit |
2fc92b |
t ++;
|
|
Packit |
2fc92b |
}
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
/*
|
|
Packit |
2fc92b |
* Bounce out if *s and *t aren't both digits...
|
|
Packit |
2fc92b |
*/
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
if (isdigit(*s & 255) && !isdigit(*t & 255))
|
|
Packit |
2fc92b |
return (1);
|
|
Packit |
2fc92b |
else if (!isdigit(*s & 255) && isdigit(*t & 255))
|
|
Packit |
2fc92b |
return (-1);
|
|
Packit |
2fc92b |
else if (!isdigit(*s & 255) || !isdigit(*t & 255))
|
|
Packit |
2fc92b |
continue;
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
if (*s < *t)
|
|
Packit |
2fc92b |
diff = -1;
|
|
Packit |
2fc92b |
else
|
|
Packit |
2fc92b |
diff = 1;
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
/*
|
|
Packit |
2fc92b |
* Figure out how many more digits there are...
|
|
Packit |
2fc92b |
*/
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
digits = 0;
|
|
Packit |
2fc92b |
s ++;
|
|
Packit |
2fc92b |
t ++;
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
while (isdigit(*s & 255))
|
|
Packit |
2fc92b |
{
|
|
Packit |
2fc92b |
digits ++;
|
|
Packit |
2fc92b |
s ++;
|
|
Packit |
2fc92b |
}
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
while (isdigit(*t & 255))
|
|
Packit |
2fc92b |
{
|
|
Packit |
2fc92b |
digits --;
|
|
Packit |
2fc92b |
t ++;
|
|
Packit |
2fc92b |
}
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
/*
|
|
Packit |
2fc92b |
* Return if the number or value of the digits is different...
|
|
Packit |
2fc92b |
*/
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
if (digits < 0)
|
|
Packit |
2fc92b |
return (-1);
|
|
Packit |
2fc92b |
else if (digits > 0)
|
|
Packit |
2fc92b |
return (1);
|
|
Packit |
2fc92b |
else if (diff)
|
|
Packit |
2fc92b |
return (diff);
|
|
Packit |
2fc92b |
}
|
|
Packit |
2fc92b |
else if (tolower(*s) < tolower(*t))
|
|
Packit |
2fc92b |
return (-1);
|
|
Packit |
2fc92b |
else if (tolower(*s) > tolower(*t))
|
|
Packit |
2fc92b |
return (1);
|
|
Packit |
2fc92b |
else
|
|
Packit |
2fc92b |
{
|
|
Packit |
2fc92b |
s ++;
|
|
Packit |
2fc92b |
t ++;
|
|
Packit |
2fc92b |
}
|
|
Packit |
2fc92b |
}
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
/*
|
|
Packit |
2fc92b |
* Return the results of the final comparison...
|
|
Packit |
2fc92b |
*/
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
if (*s)
|
|
Packit |
2fc92b |
return (1);
|
|
Packit |
2fc92b |
else if (*t)
|
|
Packit |
2fc92b |
return (-1);
|
|
Packit |
2fc92b |
else
|
|
Packit |
2fc92b |
return (0);
|
|
Packit |
2fc92b |
}
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
/*
|
|
Packit |
2fc92b |
* 'cupsdCreateStringsArray()' - Create a CUPS array of strings.
|
|
Packit |
2fc92b |
*/
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
cups_array_t * /* O - CUPS array */
|
|
Packit |
2fc92b |
cupsdCreateStringsArray(const char *s) /* I - Comma-delimited strings */
|
|
Packit |
2fc92b |
{
|
|
Packit |
2fc92b |
if (!s || !*s)
|
|
Packit |
2fc92b |
return (NULL);
|
|
Packit |
2fc92b |
else
|
|
Packit |
2fc92b |
return (_cupsArrayNewStrings(s, ','));
|
|
Packit |
2fc92b |
}
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
/*
|
|
Packit |
2fc92b |
* 'cupsdExec()' - Run a program with the correct environment.
|
|
Packit |
2fc92b |
*
|
|
Packit |
2fc92b |
* On macOS, we need to update the CFProcessPath environment variable that
|
|
Packit |
2fc92b |
* is passed in the environment so the child can access its bundled resources.
|
|
Packit |
2fc92b |
*/
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
int /* O - exec() status */
|
|
Packit |
2fc92b |
cupsdExec(const char *command, /* I - Full path to program */
|
|
Packit |
2fc92b |
char **argv) /* I - Command-line arguments */
|
|
Packit |
2fc92b |
{
|
|
Packit |
2fc92b |
#ifdef __APPLE__
|
|
Packit |
2fc92b |
int i, j; /* Looping vars */
|
|
Packit |
2fc92b |
char *envp[500], /* Array of environment variables */
|
|
Packit |
2fc92b |
cfprocesspath[1024], /* CFProcessPath environment variable */
|
|
Packit |
2fc92b |
linkpath[1024]; /* Link path for symlinks... */
|
|
Packit |
2fc92b |
int linkbytes; /* Bytes for link path */
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
/*
|
|
Packit |
2fc92b |
* Some macOS programs are bundled and need the CFProcessPath environment
|
|
Packit |
2fc92b |
* variable defined. If the command is a symlink, resolve the link and point
|
|
Packit |
2fc92b |
* to the resolved location, otherwise, use the command path itself.
|
|
Packit |
2fc92b |
*/
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
if ((linkbytes = readlink(command, linkpath, sizeof(linkpath) - 1)) > 0)
|
|
Packit |
2fc92b |
{
|
|
Packit |
2fc92b |
/*
|
|
Packit |
2fc92b |
* Yes, this is a symlink to the actual program, nul-terminate and
|
|
Packit |
2fc92b |
* use it...
|
|
Packit |
2fc92b |
*/
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
linkpath[linkbytes] = '\0';
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
if (linkpath[0] == '/')
|
|
Packit |
2fc92b |
snprintf(cfprocesspath, sizeof(cfprocesspath), "CFProcessPath=%s",
|
|
Packit |
2fc92b |
linkpath);
|
|
Packit |
2fc92b |
else
|
|
Packit |
2fc92b |
snprintf(cfprocesspath, sizeof(cfprocesspath), "CFProcessPath=%s/%s",
|
|
Packit |
2fc92b |
dirname((char *)command), linkpath);
|
|
Packit |
2fc92b |
}
|
|
Packit |
2fc92b |
else
|
|
Packit |
2fc92b |
snprintf(cfprocesspath, sizeof(cfprocesspath), "CFProcessPath=%s", command);
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
envp[0] = cfprocesspath;
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
/*
|
|
Packit |
2fc92b |
* Copy the rest of the environment except for any CFProcessPath that may
|
|
Packit |
2fc92b |
* already be there...
|
|
Packit |
2fc92b |
*/
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
for (i = 1, j = 0;
|
|
Packit |
2fc92b |
environ[j] && i < (int)(sizeof(envp) / sizeof(envp[0]) - 1);
|
|
Packit |
2fc92b |
j ++)
|
|
Packit |
2fc92b |
if (strncmp(environ[j], "CFProcessPath=", 14))
|
|
Packit |
2fc92b |
envp[i ++] = environ[j];
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
envp[i] = NULL;
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
/*
|
|
Packit |
2fc92b |
* Use execve() to run the program...
|
|
Packit |
2fc92b |
*/
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
return (execve(command, argv, envp));
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
#else
|
|
Packit |
2fc92b |
/*
|
|
Packit |
2fc92b |
* On other operating systems, just call execv() to use the same environment
|
|
Packit |
2fc92b |
* variables as the parent...
|
|
Packit |
2fc92b |
*/
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
return (execv(command, argv));
|
|
Packit |
2fc92b |
#endif /* __APPLE__ */
|
|
Packit |
2fc92b |
}
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
/*
|
|
Packit |
2fc92b |
* 'cupsdPipeCommand()' - Read output from a command.
|
|
Packit |
2fc92b |
*/
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
cups_file_t * /* O - CUPS file or NULL on error */
|
|
Packit |
2fc92b |
cupsdPipeCommand(int *pid, /* O - Process ID or 0 on error */
|
|
Packit |
2fc92b |
const char *command, /* I - Command to run */
|
|
Packit |
2fc92b |
char **argv, /* I - Arguments to pass to command */
|
|
Packit |
2fc92b |
uid_t user) /* I - User to run as or 0 for current */
|
|
Packit |
2fc92b |
{
|
|
Packit |
2fc92b |
int fd, /* Temporary file descriptor */
|
|
Packit |
2fc92b |
fds[2]; /* Pipe file descriptors */
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
/*
|
|
Packit |
2fc92b |
* First create the pipe...
|
|
Packit |
2fc92b |
*/
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
if (pipe(fds))
|
|
Packit |
2fc92b |
{
|
|
Packit |
2fc92b |
*pid = 0;
|
|
Packit |
2fc92b |
return (NULL);
|
|
Packit |
2fc92b |
}
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
/*
|
|
Packit |
2fc92b |
* Set the "close on exec" flag on each end of the pipe...
|
|
Packit |
2fc92b |
*/
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
if (fcntl(fds[0], F_SETFD, fcntl(fds[0], F_GETFD) | FD_CLOEXEC))
|
|
Packit |
2fc92b |
{
|
|
Packit |
2fc92b |
close(fds[0]);
|
|
Packit |
2fc92b |
close(fds[1]);
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
*pid = 0;
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
return (NULL);
|
|
Packit |
2fc92b |
}
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
if (fcntl(fds[1], F_SETFD, fcntl(fds[1], F_GETFD) | FD_CLOEXEC))
|
|
Packit |
2fc92b |
{
|
|
Packit |
2fc92b |
close(fds[0]);
|
|
Packit |
2fc92b |
close(fds[1]);
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
*pid = 0;
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
return (NULL);
|
|
Packit |
2fc92b |
}
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
/*
|
|
Packit |
2fc92b |
* Then run the command...
|
|
Packit |
2fc92b |
*/
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
if ((*pid = fork()) < 0)
|
|
Packit |
2fc92b |
{
|
|
Packit |
2fc92b |
/*
|
|
Packit |
2fc92b |
* Unable to fork!
|
|
Packit |
2fc92b |
*/
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
*pid = 0;
|
|
Packit |
2fc92b |
close(fds[0]);
|
|
Packit |
2fc92b |
close(fds[1]);
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
return (NULL);
|
|
Packit |
2fc92b |
}
|
|
Packit |
2fc92b |
else if (!*pid)
|
|
Packit |
2fc92b |
{
|
|
Packit |
2fc92b |
/*
|
|
Packit |
2fc92b |
* Child comes here...
|
|
Packit |
2fc92b |
*/
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
if (!getuid() && user)
|
|
Packit |
2fc92b |
setuid(user); /* Run as restricted user */
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
if ((fd = open("/dev/null", O_RDONLY)) > 0)
|
|
Packit |
2fc92b |
{
|
|
Packit |
2fc92b |
dup2(fd, 0); /*
|
|
Packit |
2fc92b |
close(fd);
|
|
Packit |
2fc92b |
}
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
dup2(fds[1], 1); /* >pipe */
|
|
Packit |
2fc92b |
close(fds[1]);
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
cupsdExec(command, argv);
|
|
Packit |
2fc92b |
exit(errno);
|
|
Packit |
2fc92b |
}
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
/*
|
|
Packit |
2fc92b |
* Parent comes here, open the input side of the pipe...
|
|
Packit |
2fc92b |
*/
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
close(fds[1]);
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
return (cupsFileOpenFd(fds[0], "r"));
|
|
Packit |
2fc92b |
}
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
/*
|
|
Packit |
2fc92b |
* 'cupsdSendIPPGroup()' - Send a group tag.
|
|
Packit |
2fc92b |
*/
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
void
|
|
Packit |
2fc92b |
cupsdSendIPPGroup(ipp_tag_t group_tag) /* I - Group tag */
|
|
Packit |
2fc92b |
{
|
|
Packit |
2fc92b |
/*
|
|
Packit |
2fc92b |
* Send IPP group tag (1 byte)...
|
|
Packit |
2fc92b |
*/
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
putchar(group_tag);
|
|
Packit |
2fc92b |
}
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
/*
|
|
Packit |
2fc92b |
* 'cupsdSendIPPHeader()' - Send the IPP response header.
|
|
Packit |
2fc92b |
*/
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
void
|
|
Packit |
2fc92b |
cupsdSendIPPHeader(
|
|
Packit |
2fc92b |
ipp_status_t status_code, /* I - Status code */
|
|
Packit |
2fc92b |
int request_id) /* I - Request ID */
|
|
Packit |
2fc92b |
{
|
|
Packit |
2fc92b |
/*
|
|
Packit |
2fc92b |
* Send IPP/1.1 response header: version number (2 bytes), status code
|
|
Packit |
2fc92b |
* (2 bytes), and request ID (4 bytes)...
|
|
Packit |
2fc92b |
*
|
|
Packit |
2fc92b |
* TODO: Add version number (IPP/2.x and IPP/1.0) support.
|
|
Packit |
2fc92b |
*/
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
putchar(1);
|
|
Packit |
2fc92b |
putchar(1);
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
putchar(status_code >> 8);
|
|
Packit |
2fc92b |
putchar(status_code);
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
putchar(request_id >> 24);
|
|
Packit |
2fc92b |
putchar(request_id >> 16);
|
|
Packit |
2fc92b |
putchar(request_id >> 8);
|
|
Packit |
2fc92b |
putchar(request_id);
|
|
Packit |
2fc92b |
}
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
/*
|
|
Packit |
2fc92b |
* 'cupsdSendIPPInteger()' - Send an integer attribute.
|
|
Packit |
2fc92b |
*/
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
void
|
|
Packit |
2fc92b |
cupsdSendIPPInteger(
|
|
Packit |
2fc92b |
ipp_tag_t value_tag, /* I - Value tag */
|
|
Packit |
2fc92b |
const char *name, /* I - Attribute name */
|
|
Packit |
2fc92b |
int value) /* I - Attribute value */
|
|
Packit |
2fc92b |
{
|
|
Packit |
2fc92b |
size_t len; /* Length of attribute name */
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
/*
|
|
Packit |
2fc92b |
* Send IPP integer value: value tag (1 byte), name length (2 bytes),
|
|
Packit |
2fc92b |
* name string (without nul), value length (2 bytes), and value (4 bytes)...
|
|
Packit |
2fc92b |
*/
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
putchar(value_tag);
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
len = strlen(name);
|
|
Packit |
2fc92b |
putchar((int)(len >> 8));
|
|
Packit |
2fc92b |
putchar((int)len);
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
fputs(name, stdout);
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
putchar(0);
|
|
Packit |
2fc92b |
putchar(4);
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
putchar(value >> 24);
|
|
Packit |
2fc92b |
putchar(value >> 16);
|
|
Packit |
2fc92b |
putchar(value >> 8);
|
|
Packit |
2fc92b |
putchar(value);
|
|
Packit |
2fc92b |
}
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
/*
|
|
Packit |
2fc92b |
* 'cupsdSendIPPString()' - Send a string attribute.
|
|
Packit |
2fc92b |
*/
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
void
|
|
Packit |
2fc92b |
cupsdSendIPPString(
|
|
Packit |
2fc92b |
ipp_tag_t value_tag, /* I - Value tag */
|
|
Packit |
2fc92b |
const char *name, /* I - Attribute name */
|
|
Packit |
2fc92b |
const char *value) /* I - Attribute value */
|
|
Packit |
2fc92b |
{
|
|
Packit |
2fc92b |
size_t len; /* Length of attribute name */
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
/*
|
|
Packit |
2fc92b |
* Send IPP string value: value tag (1 byte), name length (2 bytes),
|
|
Packit |
2fc92b |
* name string (without nul), value length (2 bytes), and value string
|
|
Packit |
2fc92b |
* (without nul)...
|
|
Packit |
2fc92b |
*/
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
putchar(value_tag);
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
len = strlen(name);
|
|
Packit |
2fc92b |
putchar((int)(len >> 8));
|
|
Packit |
2fc92b |
putchar((int)len);
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
fputs(name, stdout);
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
len = strlen(value);
|
|
Packit |
2fc92b |
putchar((int)(len >> 8));
|
|
Packit |
2fc92b |
putchar((int)len);
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
fputs(value, stdout);
|
|
Packit |
2fc92b |
}
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
/*
|
|
Packit |
2fc92b |
* 'cupsdSendIPPTrailer()' - Send the end-of-message tag.
|
|
Packit |
2fc92b |
*/
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
void
|
|
Packit |
2fc92b |
cupsdSendIPPTrailer(void)
|
|
Packit |
2fc92b |
{
|
|
Packit |
2fc92b |
putchar(IPP_TAG_END);
|
|
Packit |
2fc92b |
fflush(stdout);
|
|
Packit |
2fc92b |
}
|