]>
git.ipfire.org Git - thirdparty/cups.git/blob - notifier/mailto.c
ce55f18b0e0210cdae8aa8f6bdad153f2e8d8ec4
2 * "mailto" notifier for CUPS.
4 * Copyright 2007-2011 by Apple Inc.
5 * Copyright 1997-2005 by Easy Software Products.
7 * These coded instructions, statements, and computer programs are the
8 * property of Apple Inc. and are protected by Federal copyright
9 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
10 * which should have been included with this file. If this file is
11 * file is missing or damaged, see the license at "http://www.cups.org/".
15 * Include necessary headers...
18 #include <cups/cups-private.h>
27 char mailtoCc
[1024]; /* Cc email address */
28 char mailtoFrom
[1024]; /* From email address */
29 char mailtoReplyTo
[1024]; /* Reply-To email address */
30 char mailtoSubject
[1024]; /* Subject prefix */
31 char mailtoSMTPServer
[1024]; /* SMTP server to use */
32 char mailtoSendmail
[1024]; /* Sendmail program to use */
39 void email_message(const char *to
, const char *subject
,
41 int load_configuration(void);
42 cups_file_t
*pipe_sendmail(const char *to
);
43 void print_attributes(ipp_t
*ipp
, int indent
);
47 * 'main()' - Main entry for the mailto notifier.
50 int /* O - Exit status */
51 main(int argc
, /* I - Number of command-line arguments */
52 char *argv
[]) /* I - Command-line arguments */
54 int i
; /* Looping var */
55 ipp_t
*msg
; /* Event message from scheduler */
56 ipp_state_t state
; /* IPP event state */
57 char *subject
, /* Subject for notification message */
58 *text
; /* Text for notification message */
59 cups_lang_t
*lang
; /* Language info */
60 char temp
[1024]; /* Temporary string */
61 int templen
; /* Length of temporary string */
62 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
63 struct sigaction action
; /* POSIX sigaction data */
64 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
68 * Don't buffer stderr...
74 * Ignore SIGPIPE signals...
78 sigset(SIGPIPE
, SIG_IGN
);
79 #elif defined(HAVE_SIGACTION)
80 memset(&action
, 0, sizeof(action
));
81 action
.sa_handler
= SIG_IGN
;
82 sigaction(SIGPIPE
, &action
, NULL
);
84 signal(SIGPIPE
, SIG_IGN
);
85 #endif /* HAVE_SIGSET */
88 * Validate command-line options...
93 fputs("Usage: mailto mailto:user@domain.com notify-user-data\n", stderr
);
97 if (strncmp(argv
[1], "mailto:", 7))
99 fprintf(stderr
, "ERROR: Bad recipient \"%s\"!\n", argv
[1]);
103 fprintf(stderr
, "DEBUG: argc=%d\n", argc
);
104 for (i
= 0; i
< argc
; i
++)
105 fprintf(stderr
, "DEBUG: argv[%d]=\"%s\"\n", i
, argv
[i
]);
108 * Load configuration data...
111 if ((lang
= cupsLangDefault()) == NULL
)
114 if (!load_configuration())
118 * Get the reply-to address...
121 templen
= sizeof(temp
);
122 httpDecode64_2(temp
, &templen
, argv
[2]);
124 if (!strncmp(temp
, "mailto:", 7))
125 strlcpy(mailtoReplyTo
, temp
+ 7, sizeof(mailtoReplyTo
));
127 fprintf(stderr
, "WARNING: Bad notify-user-data value (%d bytes) ignored!\n",
131 * Loop forever until we run out of events...
137 * Get the next event...
141 while ((state
= ippReadFile(0, msg
)) != IPP_DATA
)
143 if (state
<= IPP_IDLE
)
147 fprintf(stderr
, "DEBUG: state=%d\n", state
);
149 if (state
== IPP_ERROR
)
150 fputs("DEBUG: ippReadFile() returned IPP_ERROR!\n", stderr
);
152 if (state
<= IPP_IDLE
)
155 * Out of messages, free memory and then exit...
163 * Get the subject and text for the message, then email it...
166 subject
= cupsNotifySubject(lang
, msg
);
167 text
= cupsNotifyText(lang
, msg
);
169 fprintf(stderr
, "DEBUG: subject=\"%s\"\n", subject
);
170 fprintf(stderr
, "DEBUG: text=\"%s\"\n", text
);
173 email_message(argv
[1] + 7, subject
, text
);
176 fputs("ERROR: Missing attributes in event notification!\n", stderr
);
177 print_attributes(msg
, 4);
181 * Free the memory used for this event...
196 * 'email_message()' - Email a notification message.
200 email_message(const char *to
, /* I - Recipient of message */
201 const char *subject
, /* I - Subject of message */
202 const char *text
) /* I - Text of message */
204 cups_file_t
*fp
; /* Pipe/socket to mail server */
205 const char *nl
; /* Newline to use */
206 char response
[1024]; /* SMTP response buffer */
210 * Connect to the mail server...
213 if (mailtoSendmail
[0])
216 * Use the sendmail command...
219 fp
= pipe_sendmail(to
);
229 * Use an SMTP server...
232 char hostbuf
[1024]; /* Local hostname */
235 if (strchr(mailtoSMTPServer
, ':'))
236 fp
= cupsFileOpen(mailtoSMTPServer
, "s");
239 char spec
[1024]; /* Host:service spec */
242 snprintf(spec
, sizeof(spec
), "%s:smtp", mailtoSMTPServer
);
243 fp
= cupsFileOpen(spec
, "s");
248 fprintf(stderr
, "ERROR: Unable to connect to SMTP server \"%s\"!\n",
253 fprintf(stderr
, "DEBUG: Connected to \"%s\"...\n", mailtoSMTPServer
);
255 cupsFilePrintf(fp
, "HELO %s\r\n",
256 httpGetHostname(NULL
, hostbuf
, sizeof(hostbuf
)));
257 fprintf(stderr
, "DEBUG: >>> HELO %s\n", hostbuf
);
259 if (!cupsFileGets(fp
, response
, sizeof(response
)) || atoi(response
) >= 500)
261 fprintf(stderr
, "DEBUG: <<< %s\n", response
);
263 cupsFilePrintf(fp
, "MAIL FROM:%s\r\n", mailtoFrom
);
264 fprintf(stderr
, "DEBUG: >>> MAIL FROM:%s\n", mailtoFrom
);
266 if (!cupsFileGets(fp
, response
, sizeof(response
)) || atoi(response
) >= 500)
268 fprintf(stderr
, "DEBUG: <<< %s\n", response
);
270 cupsFilePrintf(fp
, "RCPT TO:%s\r\n", to
);
271 fprintf(stderr
, "DEBUG: >>> RCPT TO:%s\n", to
);
273 if (!cupsFileGets(fp
, response
, sizeof(response
)) || atoi(response
) >= 500)
275 fprintf(stderr
, "DEBUG: <<< %s\n", response
);
277 cupsFilePuts(fp
, "DATA\r\n");
278 fputs("DEBUG: DATA\n", stderr
);
280 if (!cupsFileGets(fp
, response
, sizeof(response
)) || atoi(response
) >= 500)
282 fprintf(stderr
, "DEBUG: <<< %s\n", response
);
288 * Send the message...
291 cupsFilePrintf(fp
, "Date: %s%s", httpGetDateString(time(NULL
)), nl
);
292 cupsFilePrintf(fp
, "From: %s%s", mailtoFrom
, nl
);
293 cupsFilePrintf(fp
, "Subject: %s %s%s", mailtoSubject
, subject
, nl
);
294 if (mailtoReplyTo
[0])
296 cupsFilePrintf(fp
, "Sender: %s%s", mailtoReplyTo
, nl
);
297 cupsFilePrintf(fp
, "Reply-To: %s%s", mailtoReplyTo
, nl
);
299 cupsFilePrintf(fp
, "To: %s%s", to
, nl
);
301 cupsFilePrintf(fp
, "Cc: %s%s", mailtoCc
, nl
);
302 cupsFilePrintf(fp
, "Content-Type: text/plain%s", nl
);
303 cupsFilePuts(fp
, nl
);
304 cupsFilePrintf(fp
, "%s%s", text
, nl
);
305 cupsFilePrintf(fp
, ".%s", nl
);
308 * Close the connection to the mail server...
311 if (mailtoSendmail
[0])
314 * Close the pipe and wait for the sendmail command to finish...
317 int status
; /* Exit status */
322 while (wait(&status
))
326 fprintf(stderr
, "DEBUG: Unable to get child status: %s\n",
334 * Report any non-zero status...
339 if (WIFEXITED(status
))
340 fprintf(stderr
, "ERROR: Sendmail command returned status %d!\n",
341 WEXITSTATUS(status
));
343 fprintf(stderr
, "ERROR: Sendmail command crashed on signal %d!\n",
350 * Finish up the SMTP submission and close the connection...
353 if (!cupsFileGets(fp
, response
, sizeof(response
)) || atoi(response
) >= 500)
355 fprintf(stderr
, "DEBUG: <<< %s\n", response
);
358 * Process SMTP errors here...
363 cupsFilePuts(fp
, "QUIT\r\n");
364 fputs("DEBUG: QUIT\n", stderr
);
366 if (!cupsFileGets(fp
, response
, sizeof(response
)) || atoi(response
) >= 500)
367 fprintf(stderr
, "ERROR: Got \"%s\" trying to QUIT connection.\n",
370 fprintf(stderr
, "DEBUG: <<< %s\n", response
);
374 fprintf(stderr
, "DEBUG: Closed connection to \"%s\"...\n",
381 * 'load_configuration()' - Load the mailto.conf file.
384 int /* I - 1 on success, 0 on failure */
385 load_configuration(void)
387 cups_file_t
*fp
; /* mailto.conf file */
388 const char *server_root
, /* CUPS_SERVERROOT environment variable */
389 *server_admin
; /* SERVER_ADMIN environment variable */
390 char line
[1024], /* Line from file */
391 *value
; /* Value for directive */
392 int linenum
; /* Line number in file */
396 * Initialize defaults...
401 if ((server_admin
= getenv("SERVER_ADMIN")) != NULL
)
402 strlcpy(mailtoFrom
, server_admin
, sizeof(mailtoFrom
));
404 snprintf(mailtoFrom
, sizeof(mailtoFrom
), "root@%s",
405 httpGetHostname(NULL
, line
, sizeof(line
)));
407 strlcpy(mailtoSendmail
, "/usr/sbin/sendmail", sizeof(mailtoSendmail
));
409 mailtoSMTPServer
[0] = '\0';
411 mailtoSubject
[0] = '\0';
414 * Try loading the config file...
417 if ((server_root
= getenv("CUPS_SERVERROOT")) == NULL
)
418 server_root
= CUPS_SERVERROOT
;
420 snprintf(line
, sizeof(line
), "%s/mailto.conf", server_root
);
422 if ((fp
= cupsFileOpen(line
, "r")) == NULL
)
426 fprintf(stderr
, "ERROR: Unable to open \"%s\" - %s\n", line
,
436 while (cupsFileGetConf(fp
, line
, sizeof(line
), &value
, &linenum
))
440 fprintf(stderr
, "ERROR: No value found for %s directive on line %d!\n",
446 if (!_cups_strcasecmp(line
, "Cc"))
447 strlcpy(mailtoCc
, value
, sizeof(mailtoCc
));
448 else if (!_cups_strcasecmp(line
, "From"))
449 strlcpy(mailtoFrom
, value
, sizeof(mailtoFrom
));
450 else if (!_cups_strcasecmp(line
, "Sendmail"))
452 strlcpy(mailtoSendmail
, value
, sizeof(mailtoSendmail
));
453 mailtoSMTPServer
[0] = '\0';
455 else if (!_cups_strcasecmp(line
, "SMTPServer"))
457 mailtoSendmail
[0] = '\0';
458 strlcpy(mailtoSMTPServer
, value
, sizeof(mailtoSMTPServer
));
460 else if (!_cups_strcasecmp(line
, "Subject"))
461 strlcpy(mailtoSubject
, value
, sizeof(mailtoSubject
));
465 "ERROR: Unknown configuration directive \"%s\" on line %d!\n",
471 * Close file and return...
481 * 'pipe_sendmail()' - Open a pipe to sendmail...
484 cups_file_t
* /* O - CUPS file */
485 pipe_sendmail(const char *to
) /* I - To: address */
487 cups_file_t
*fp
; /* CUPS file */
488 int pid
; /* Process ID */
489 int pipefds
[2]; /* Pipe file descriptors */
490 int argc
; /* Number of arguments */
491 char *argv
[100], /* Argument array */
492 line
[1024], /* Sendmail command + args */
493 *lineptr
; /* Pointer into line */
497 * First break the mailtoSendmail string into arguments...
500 strlcpy(line
, mailtoSendmail
, sizeof(line
));
504 for (lineptr
= strchr(line
, ' '); lineptr
; lineptr
= strchr(lineptr
, ' '))
506 while (*lineptr
== ' ')
512 * Point to the next argument...
515 argv
[argc
++] = lineptr
;
518 * Stop if we have too many...
521 if (argc
>= (int)(sizeof(argv
) / sizeof(argv
[0]) - 2))
526 argv
[argc
++] = (char *)to
;
535 perror("ERROR: Unable to create pipe");
540 * Then run the command...
543 if ((pid
= fork()) == 0)
546 * Child goes here - redirect stdin to the input side of the pipe,
547 * redirect stdout to stderr, and exec...
559 execvp(argv
[0], argv
);
565 * Unable to fork - error out...
568 perror("ERROR: Unable to fork command");
577 * Create a CUPS file using the output side of the pipe and close the
583 if ((fp
= cupsFileOpenFd(pipefds
[1], "w")) == NULL
)
585 int status
; /* Status of command */
597 * 'print_attributes()' - Print the attributes in a request...
601 print_attributes(ipp_t
*ipp
, /* I - IPP request */
602 int indent
) /* I - Indentation */
604 ipp_tag_t group
; /* Current group */
605 ipp_attribute_t
*attr
; /* Current attribute */
606 char buffer
[1024]; /* Value buffer */
609 for (group
= IPP_TAG_ZERO
, attr
= ipp
->attrs
; attr
; attr
= attr
->next
)
611 if ((attr
->group_tag
== IPP_TAG_ZERO
&& indent
<= 8) || !attr
->name
)
613 group
= IPP_TAG_ZERO
;
618 if (group
!= attr
->group_tag
)
620 group
= attr
->group_tag
;
622 fprintf(stderr
, "DEBUG: %*s%s:\n\n", indent
- 4, "", ippTagString(group
));
625 ippAttributeString(attr
, buffer
, sizeof(buffer
));
627 fprintf(stderr
, "DEBUG: %*s%s (%s%s) %s", indent
, "", attr
->name
,
628 attr
->num_values
> 1 ? "1setOf " : "",
629 ippTagString(attr
->value_tag
), buffer
);