mirror of https://gitee.com/openkylin/cups.git
634 lines
14 KiB
C
634 lines
14 KiB
C
|
/*
|
|||
|
* "mailto" notifier for CUPS.
|
|||
|
*
|
|||
|
* Copyright © 2007-2018 by Apple Inc.
|
|||
|
* Copyright © 1997-2005 by Easy Software Products.
|
|||
|
*
|
|||
|
* Licensed under Apache License v2.0. See the file "LICENSE" for more
|
|||
|
* information.
|
|||
|
*/
|
|||
|
|
|||
|
/*
|
|||
|
* Include necessary headers...
|
|||
|
*/
|
|||
|
|
|||
|
#include <cups/cups-private.h>
|
|||
|
#include <sys/wait.h>
|
|||
|
#include <signal.h>
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
* Globals...
|
|||
|
*/
|
|||
|
|
|||
|
char mailtoCc[1024]; /* Cc email address */
|
|||
|
char mailtoFrom[1024]; /* From email address */
|
|||
|
char mailtoReplyTo[1024]; /* Reply-To email address */
|
|||
|
char mailtoSubject[1024]; /* Subject prefix */
|
|||
|
char mailtoSMTPServer[1024]; /* SMTP server to use */
|
|||
|
char mailtoSendmail[1024]; /* Sendmail program to use */
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
* Local functions...
|
|||
|
*/
|
|||
|
|
|||
|
void email_message(const char *to, const char *subject, const char *text);
|
|||
|
int load_configuration(void);
|
|||
|
cups_file_t *pipe_sendmail(const char *to);
|
|||
|
void print_attributes(ipp_t *ipp, int indent);
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
* 'main()' - Main entry for the mailto notifier.
|
|||
|
*/
|
|||
|
|
|||
|
int /* O - Exit status */
|
|||
|
main(int argc, /* I - Number of command-line arguments */
|
|||
|
char *argv[]) /* I - Command-line arguments */
|
|||
|
{
|
|||
|
int i; /* Looping var */
|
|||
|
ipp_t *msg; /* Event message from scheduler */
|
|||
|
ipp_state_t state; /* IPP event state */
|
|||
|
char *subject, /* Subject for notification message */
|
|||
|
*text; /* Text for notification message */
|
|||
|
cups_lang_t *lang; /* Language info */
|
|||
|
char temp[1024]; /* Temporary string */
|
|||
|
int templen; /* Length of temporary string */
|
|||
|
#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
|
|||
|
struct sigaction action; /* POSIX sigaction data */
|
|||
|
#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
* Don't buffer stderr...
|
|||
|
*/
|
|||
|
|
|||
|
setbuf(stderr, NULL);
|
|||
|
|
|||
|
/*
|
|||
|
* Ignore SIGPIPE signals...
|
|||
|
*/
|
|||
|
|
|||
|
#ifdef HAVE_SIGSET
|
|||
|
sigset(SIGPIPE, SIG_IGN);
|
|||
|
#elif defined(HAVE_SIGACTION)
|
|||
|
memset(&action, 0, sizeof(action));
|
|||
|
action.sa_handler = SIG_IGN;
|
|||
|
sigaction(SIGPIPE, &action, NULL);
|
|||
|
#else
|
|||
|
signal(SIGPIPE, SIG_IGN);
|
|||
|
#endif /* HAVE_SIGSET */
|
|||
|
|
|||
|
/*
|
|||
|
* Validate command-line options...
|
|||
|
*/
|
|||
|
|
|||
|
if (argc != 3)
|
|||
|
{
|
|||
|
fputs("Usage: mailto mailto:user@domain.com notify-user-data\n", stderr);
|
|||
|
return (1);
|
|||
|
}
|
|||
|
|
|||
|
if (strncmp(argv[1], "mailto:", 7))
|
|||
|
{
|
|||
|
fprintf(stderr, "ERROR: Bad recipient \"%s\"!\n", argv[1]);
|
|||
|
return (1);
|
|||
|
}
|
|||
|
|
|||
|
fprintf(stderr, "DEBUG: argc=%d\n", argc);
|
|||
|
for (i = 0; i < argc; i ++)
|
|||
|
fprintf(stderr, "DEBUG: argv[%d]=\"%s\"\n", i, argv[i]);
|
|||
|
|
|||
|
/*
|
|||
|
* Load configuration data...
|
|||
|
*/
|
|||
|
|
|||
|
if ((lang = cupsLangDefault()) == NULL)
|
|||
|
return (1);
|
|||
|
|
|||
|
if (!load_configuration())
|
|||
|
return (1);
|
|||
|
|
|||
|
/*
|
|||
|
* Get the reply-to address...
|
|||
|
*/
|
|||
|
|
|||
|
templen = sizeof(temp);
|
|||
|
httpDecode64_2(temp, &templen, argv[2]);
|
|||
|
|
|||
|
if (!strncmp(temp, "mailto:", 7))
|
|||
|
strlcpy(mailtoReplyTo, temp + 7, sizeof(mailtoReplyTo));
|
|||
|
else if (temp[0])
|
|||
|
fprintf(stderr, "WARNING: Bad notify-user-data value (%d bytes) ignored!\n",
|
|||
|
templen);
|
|||
|
|
|||
|
/*
|
|||
|
* Loop forever until we run out of events...
|
|||
|
*/
|
|||
|
|
|||
|
for (;;)
|
|||
|
{
|
|||
|
/*
|
|||
|
* Get the next event...
|
|||
|
*/
|
|||
|
|
|||
|
msg = ippNew();
|
|||
|
while ((state = ippReadFile(0, msg)) != IPP_DATA)
|
|||
|
{
|
|||
|
if (state <= IPP_IDLE)
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
fprintf(stderr, "DEBUG: state=%d\n", state);
|
|||
|
|
|||
|
if (state == IPP_ERROR)
|
|||
|
fputs("DEBUG: ippReadFile() returned IPP_ERROR!\n", stderr);
|
|||
|
|
|||
|
if (state <= IPP_IDLE)
|
|||
|
{
|
|||
|
/*
|
|||
|
* Out of messages, free memory and then exit...
|
|||
|
*/
|
|||
|
|
|||
|
ippDelete(msg);
|
|||
|
return (0);
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
* Get the subject and text for the message, then email it...
|
|||
|
*/
|
|||
|
|
|||
|
subject = cupsNotifySubject(lang, msg);
|
|||
|
text = cupsNotifyText(lang, msg);
|
|||
|
|
|||
|
fprintf(stderr, "DEBUG: subject=\"%s\"\n", subject);
|
|||
|
fprintf(stderr, "DEBUG: text=\"%s\"\n", text);
|
|||
|
|
|||
|
if (subject && text)
|
|||
|
email_message(argv[1] + 7, subject, text);
|
|||
|
else
|
|||
|
{
|
|||
|
fputs("ERROR: Missing attributes in event notification!\n", stderr);
|
|||
|
print_attributes(msg, 4);
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
* Free the memory used for this event...
|
|||
|
*/
|
|||
|
|
|||
|
if (subject)
|
|||
|
free(subject);
|
|||
|
|
|||
|
if (text)
|
|||
|
free(text);
|
|||
|
|
|||
|
ippDelete(msg);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
* 'email_message()' - Email a notification message.
|
|||
|
*/
|
|||
|
|
|||
|
void
|
|||
|
email_message(const char *to, /* I - Recipient of message */
|
|||
|
const char *subject, /* I - Subject of message */
|
|||
|
const char *text) /* I - Text of message */
|
|||
|
{
|
|||
|
cups_file_t *fp; /* Pipe/socket to mail server */
|
|||
|
const char *nl; /* Newline to use */
|
|||
|
char response[1024]; /* SMTP response buffer */
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
* Connect to the mail server...
|
|||
|
*/
|
|||
|
|
|||
|
if (mailtoSendmail[0])
|
|||
|
{
|
|||
|
/*
|
|||
|
* Use the sendmail command...
|
|||
|
*/
|
|||
|
|
|||
|
fp = pipe_sendmail(to);
|
|||
|
|
|||
|
if (!fp)
|
|||
|
return;
|
|||
|
|
|||
|
nl = "\n";
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
/*
|
|||
|
* Use an SMTP server...
|
|||
|
*/
|
|||
|
|
|||
|
char hostbuf[1024]; /* Local hostname */
|
|||
|
|
|||
|
|
|||
|
if (strchr(mailtoSMTPServer, ':'))
|
|||
|
{
|
|||
|
fp = cupsFileOpen(mailtoSMTPServer, "s");
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
char spec[1024]; /* Host:service spec */
|
|||
|
|
|||
|
|
|||
|
snprintf(spec, sizeof(spec), "%s:smtp", mailtoSMTPServer);
|
|||
|
fp = cupsFileOpen(spec, "s");
|
|||
|
}
|
|||
|
|
|||
|
if (!fp)
|
|||
|
{
|
|||
|
fprintf(stderr, "ERROR: Unable to connect to SMTP server \"%s\"!\n",
|
|||
|
mailtoSMTPServer);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
fprintf(stderr, "DEBUG: Connected to \"%s\"...\n", mailtoSMTPServer);
|
|||
|
|
|||
|
if (!cupsFileGets(fp, response, sizeof(response)) || atoi(response) >= 500)
|
|||
|
goto smtp_error;
|
|||
|
fprintf(stderr, "DEBUG: <<< %s\n", response);
|
|||
|
|
|||
|
cupsFilePrintf(fp, "HELO %s\r\n",
|
|||
|
httpGetHostname(NULL, hostbuf, sizeof(hostbuf)));
|
|||
|
fprintf(stderr, "DEBUG: >>> HELO %s\n", hostbuf);
|
|||
|
|
|||
|
if (!cupsFileGets(fp, response, sizeof(response)) || atoi(response) >= 500)
|
|||
|
goto smtp_error;
|
|||
|
fprintf(stderr, "DEBUG: <<< %s\n", response);
|
|||
|
|
|||
|
cupsFilePrintf(fp, "MAIL FROM:%s\r\n", mailtoFrom);
|
|||
|
fprintf(stderr, "DEBUG: >>> MAIL FROM:%s\n", mailtoFrom);
|
|||
|
|
|||
|
if (!cupsFileGets(fp, response, sizeof(response)) || atoi(response) >= 500)
|
|||
|
goto smtp_error;
|
|||
|
fprintf(stderr, "DEBUG: <<< %s\n", response);
|
|||
|
|
|||
|
cupsFilePrintf(fp, "RCPT TO:%s\r\n", to);
|
|||
|
fprintf(stderr, "DEBUG: >>> RCPT TO:%s\n", to);
|
|||
|
|
|||
|
if (!cupsFileGets(fp, response, sizeof(response)) || atoi(response) >= 500)
|
|||
|
goto smtp_error;
|
|||
|
fprintf(stderr, "DEBUG: <<< %s\n", response);
|
|||
|
|
|||
|
cupsFilePuts(fp, "DATA\r\n");
|
|||
|
fputs("DEBUG: DATA\n", stderr);
|
|||
|
|
|||
|
if (!cupsFileGets(fp, response, sizeof(response)) || atoi(response) >= 500)
|
|||
|
goto smtp_error;
|
|||
|
fprintf(stderr, "DEBUG: <<< %s\n", response);
|
|||
|
|
|||
|
nl = "\r\n";
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
* Send the message...
|
|||
|
*/
|
|||
|
|
|||
|
cupsFilePrintf(fp, "Date: %s%s", httpGetDateString(time(NULL)), nl);
|
|||
|
cupsFilePrintf(fp, "From: %s%s", mailtoFrom, nl);
|
|||
|
cupsFilePrintf(fp, "Subject: %s %s%s", mailtoSubject, subject, nl);
|
|||
|
if (mailtoReplyTo[0])
|
|||
|
{
|
|||
|
cupsFilePrintf(fp, "Sender: %s%s", mailtoReplyTo, nl);
|
|||
|
cupsFilePrintf(fp, "Reply-To: %s%s", mailtoReplyTo, nl);
|
|||
|
}
|
|||
|
cupsFilePrintf(fp, "To: %s%s", to, nl);
|
|||
|
if (mailtoCc[0])
|
|||
|
cupsFilePrintf(fp, "Cc: %s%s", mailtoCc, nl);
|
|||
|
cupsFilePrintf(fp, "Content-Type: text/plain%s", nl);
|
|||
|
cupsFilePuts(fp, nl);
|
|||
|
cupsFilePrintf(fp, "%s%s", text, nl);
|
|||
|
cupsFilePrintf(fp, ".%s", nl);
|
|||
|
|
|||
|
/*
|
|||
|
* Close the connection to the mail server...
|
|||
|
*/
|
|||
|
|
|||
|
if (mailtoSendmail[0])
|
|||
|
{
|
|||
|
/*
|
|||
|
* Close the pipe and wait for the sendmail command to finish...
|
|||
|
*/
|
|||
|
|
|||
|
int status; /* Exit status */
|
|||
|
|
|||
|
|
|||
|
cupsFileClose(fp);
|
|||
|
|
|||
|
while (wait(&status))
|
|||
|
{
|
|||
|
if (errno != EINTR)
|
|||
|
{
|
|||
|
fprintf(stderr, "DEBUG: Unable to get child status: %s\n",
|
|||
|
strerror(errno));
|
|||
|
status = 0;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
* Report any non-zero status...
|
|||
|
*/
|
|||
|
|
|||
|
if (status)
|
|||
|
{
|
|||
|
if (WIFEXITED(status))
|
|||
|
fprintf(stderr, "ERROR: Sendmail command returned status %d!\n",
|
|||
|
WEXITSTATUS(status));
|
|||
|
else
|
|||
|
fprintf(stderr, "ERROR: Sendmail command crashed on signal %d!\n",
|
|||
|
WTERMSIG(status));
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
/*
|
|||
|
* Finish up the SMTP submission and close the connection...
|
|||
|
*/
|
|||
|
|
|||
|
if (!cupsFileGets(fp, response, sizeof(response)) || atoi(response) >= 500)
|
|||
|
goto smtp_error;
|
|||
|
fprintf(stderr, "DEBUG: <<< %s\n", response);
|
|||
|
|
|||
|
/*
|
|||
|
* Process SMTP errors here...
|
|||
|
*/
|
|||
|
|
|||
|
smtp_error:
|
|||
|
|
|||
|
cupsFilePuts(fp, "QUIT\r\n");
|
|||
|
fputs("DEBUG: QUIT\n", stderr);
|
|||
|
|
|||
|
if (!cupsFileGets(fp, response, sizeof(response)) || atoi(response) >= 500)
|
|||
|
fprintf(stderr, "ERROR: Got \"%s\" trying to QUIT connection.\n",
|
|||
|
response);
|
|||
|
else
|
|||
|
fprintf(stderr, "DEBUG: <<< %s\n", response);
|
|||
|
|
|||
|
cupsFileClose(fp);
|
|||
|
|
|||
|
fprintf(stderr, "DEBUG: Closed connection to \"%s\"...\n",
|
|||
|
mailtoSMTPServer);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
* 'load_configuration()' - Load the mailto.conf file.
|
|||
|
*/
|
|||
|
|
|||
|
int /* I - 1 on success, 0 on failure */
|
|||
|
load_configuration(void)
|
|||
|
{
|
|||
|
cups_file_t *fp; /* mailto.conf file */
|
|||
|
const char *server_root, /* CUPS_SERVERROOT environment variable */
|
|||
|
*server_admin; /* SERVER_ADMIN environment variable */
|
|||
|
char line[1024], /* Line from file */
|
|||
|
*value; /* Value for directive */
|
|||
|
int linenum; /* Line number in file */
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
* Initialize defaults...
|
|||
|
*/
|
|||
|
|
|||
|
mailtoCc[0] = '\0';
|
|||
|
|
|||
|
if ((server_admin = getenv("SERVER_ADMIN")) != NULL)
|
|||
|
strlcpy(mailtoFrom, server_admin, sizeof(mailtoFrom));
|
|||
|
else
|
|||
|
snprintf(mailtoFrom, sizeof(mailtoFrom), "root@%s",
|
|||
|
httpGetHostname(NULL, line, sizeof(line)));
|
|||
|
|
|||
|
strlcpy(mailtoSendmail, "/usr/sbin/sendmail", sizeof(mailtoSendmail));
|
|||
|
|
|||
|
mailtoSMTPServer[0] = '\0';
|
|||
|
|
|||
|
mailtoSubject[0] = '\0';
|
|||
|
|
|||
|
/*
|
|||
|
* Try loading the config file...
|
|||
|
*/
|
|||
|
|
|||
|
if ((server_root = getenv("CUPS_SERVERROOT")) == NULL)
|
|||
|
server_root = CUPS_SERVERROOT;
|
|||
|
|
|||
|
snprintf(line, sizeof(line), "%s/mailto.conf", server_root);
|
|||
|
|
|||
|
if ((fp = cupsFileOpen(line, "r")) == NULL)
|
|||
|
{
|
|||
|
if (errno != ENOENT)
|
|||
|
{
|
|||
|
fprintf(stderr, "ERROR: Unable to open \"%s\" - %s\n", line,
|
|||
|
strerror(errno));
|
|||
|
return (1);
|
|||
|
}
|
|||
|
else
|
|||
|
return (0);
|
|||
|
}
|
|||
|
|
|||
|
linenum = 0;
|
|||
|
|
|||
|
while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
|
|||
|
{
|
|||
|
if (!value)
|
|||
|
{
|
|||
|
fprintf(stderr, "ERROR: No value found for %s directive on line %d!\n",
|
|||
|
line, linenum);
|
|||
|
cupsFileClose(fp);
|
|||
|
return (0);
|
|||
|
}
|
|||
|
|
|||
|
if (!_cups_strcasecmp(line, "Cc"))
|
|||
|
strlcpy(mailtoCc, value, sizeof(mailtoCc));
|
|||
|
else if (!_cups_strcasecmp(line, "From"))
|
|||
|
strlcpy(mailtoFrom, value, sizeof(mailtoFrom));
|
|||
|
else if (!_cups_strcasecmp(line, "Sendmail"))
|
|||
|
{
|
|||
|
strlcpy(mailtoSendmail, value, sizeof(mailtoSendmail));
|
|||
|
mailtoSMTPServer[0] = '\0';
|
|||
|
}
|
|||
|
else if (!_cups_strcasecmp(line, "SMTPServer"))
|
|||
|
{
|
|||
|
mailtoSendmail[0] = '\0';
|
|||
|
strlcpy(mailtoSMTPServer, value, sizeof(mailtoSMTPServer));
|
|||
|
}
|
|||
|
else if (!_cups_strcasecmp(line, "Subject"))
|
|||
|
strlcpy(mailtoSubject, value, sizeof(mailtoSubject));
|
|||
|
else
|
|||
|
{
|
|||
|
fprintf(stderr,
|
|||
|
"ERROR: Unknown configuration directive \"%s\" on line %d!\n",
|
|||
|
line, linenum);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
* Close file and return...
|
|||
|
*/
|
|||
|
|
|||
|
cupsFileClose(fp);
|
|||
|
|
|||
|
return (1);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
* 'pipe_sendmail()' - Open a pipe to sendmail...
|
|||
|
*/
|
|||
|
|
|||
|
cups_file_t * /* O - CUPS file */
|
|||
|
pipe_sendmail(const char *to) /* I - To: address */
|
|||
|
{
|
|||
|
cups_file_t *fp; /* CUPS file */
|
|||
|
int pid; /* Process ID */
|
|||
|
int pipefds[2]; /* Pipe file descriptors */
|
|||
|
int argc; /* Number of arguments */
|
|||
|
char *argv[100], /* Argument array */
|
|||
|
line[1024], /* Sendmail command + args */
|
|||
|
*lineptr; /* Pointer into line */
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
* First break the mailtoSendmail string into arguments...
|
|||
|
*/
|
|||
|
|
|||
|
strlcpy(line, mailtoSendmail, sizeof(line));
|
|||
|
argv[0] = line;
|
|||
|
argc = 1;
|
|||
|
|
|||
|
for (lineptr = strchr(line, ' '); lineptr; lineptr = strchr(lineptr, ' '))
|
|||
|
{
|
|||
|
while (*lineptr == ' ')
|
|||
|
*lineptr++ = '\0';
|
|||
|
|
|||
|
if (*lineptr)
|
|||
|
{
|
|||
|
/*
|
|||
|
* Point to the next argument...
|
|||
|
*/
|
|||
|
|
|||
|
argv[argc ++] = lineptr;
|
|||
|
|
|||
|
/*
|
|||
|
* Stop if we have too many...
|
|||
|
*/
|
|||
|
|
|||
|
if (argc >= (int)(sizeof(argv) / sizeof(argv[0]) - 2))
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
argv[argc ++] = (char *)to;
|
|||
|
argv[argc] = NULL;
|
|||
|
|
|||
|
/*
|
|||
|
* Create the pipe...
|
|||
|
*/
|
|||
|
|
|||
|
if (pipe(pipefds))
|
|||
|
{
|
|||
|
perror("ERROR: Unable to create pipe");
|
|||
|
return (NULL);
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
* Then run the command...
|
|||
|
*/
|
|||
|
|
|||
|
if ((pid = fork()) == 0)
|
|||
|
{
|
|||
|
/*
|
|||
|
* Child goes here - redirect stdin to the input side of the pipe,
|
|||
|
* redirect stdout to stderr, and exec...
|
|||
|
*/
|
|||
|
|
|||
|
close(0);
|
|||
|
dup(pipefds[0]);
|
|||
|
|
|||
|
close(1);
|
|||
|
dup(2);
|
|||
|
|
|||
|
close(pipefds[0]);
|
|||
|
close(pipefds[1]);
|
|||
|
|
|||
|
execvp(argv[0], argv);
|
|||
|
exit(errno);
|
|||
|
}
|
|||
|
else if (pid < 0)
|
|||
|
{
|
|||
|
/*
|
|||
|
* Unable to fork - error out...
|
|||
|
*/
|
|||
|
|
|||
|
perror("ERROR: Unable to fork command");
|
|||
|
|
|||
|
close(pipefds[0]);
|
|||
|
close(pipefds[1]);
|
|||
|
|
|||
|
return (NULL);
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
* Create a CUPS file using the output side of the pipe and close the
|
|||
|
* input side...
|
|||
|
*/
|
|||
|
|
|||
|
close(pipefds[0]);
|
|||
|
|
|||
|
if ((fp = cupsFileOpenFd(pipefds[1], "w")) == NULL)
|
|||
|
{
|
|||
|
int status; /* Status of command */
|
|||
|
|
|||
|
|
|||
|
close(pipefds[1]);
|
|||
|
wait(&status);
|
|||
|
}
|
|||
|
|
|||
|
return (fp);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
* 'print_attributes()' - Print the attributes in a request...
|
|||
|
*/
|
|||
|
|
|||
|
void
|
|||
|
print_attributes(ipp_t *ipp, /* I - IPP request */
|
|||
|
int indent) /* I - Indentation */
|
|||
|
{
|
|||
|
ipp_tag_t group; /* Current group */
|
|||
|
ipp_attribute_t *attr; /* Current attribute */
|
|||
|
char buffer[1024]; /* Value buffer */
|
|||
|
|
|||
|
|
|||
|
for (group = IPP_TAG_ZERO, attr = ipp->attrs; attr; attr = attr->next)
|
|||
|
{
|
|||
|
if ((attr->group_tag == IPP_TAG_ZERO && indent <= 8) || !attr->name)
|
|||
|
{
|
|||
|
group = IPP_TAG_ZERO;
|
|||
|
fputc('\n', stderr);
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
if (group != attr->group_tag)
|
|||
|
{
|
|||
|
group = attr->group_tag;
|
|||
|
|
|||
|
fprintf(stderr, "DEBUG: %*s%s:\n\n", indent - 4, "", ippTagString(group));
|
|||
|
}
|
|||
|
|
|||
|
ippAttributeString(attr, buffer, sizeof(buffer));
|
|||
|
|
|||
|
fprintf(stderr, "DEBUG: %*s%s (%s%s) %s", indent, "", attr->name,
|
|||
|
attr->num_values > 1 ? "1setOf " : "",
|
|||
|
ippTagString(attr->value_tag), buffer);
|
|||
|
}
|
|||
|
}
|