]>
git.ipfire.org Git - thirdparty/cups.git/blob - notifier/mailto.c
2 * "$Id: mailto.c 5235 2006-03-06 13:02:23Z mike $"
4 * "mailto" notifier for the Common UNIX Printing System (CUPS).
6 * Copyright 1997-2005 by Easy Software Products.
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 USA
20 * Voice: (301) 373-9600
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
26 * main() - Main entry for the mailto notifier.
27 * email_message() - Email a notification message.
28 * load_configuration() - Load the mailto.conf file.
29 * pipe_sendmail() - Open a pipe to sendmail...
30 * print_attributes() - Print the attributes in a request...
34 * Include necessary headers...
37 #include <cups/cups.h>
38 #include <cups/i18n.h>
39 #include <cups/string.h>
49 char mailtoCc
[1024]; /* Cc email address */
50 char mailtoFrom
[1024]; /* From email address */
51 char mailtoReplyTo
[1024]; /* Reply-To email address */
52 char mailtoSubject
[1024]; /* Subject prefix */
53 char mailtoSMTPServer
[1024]; /* SMTP server to use */
54 char mailtoSendmail
[1024]; /* Sendmail program to use */
61 void email_message(const char *to
, const char *subject
,
63 int load_configuration(void);
64 cups_file_t
*pipe_sendmail(const char *to
);
65 void print_attributes(ipp_t
*ipp
, int indent
);
69 * 'main()' - Main entry for the mailto notifier.
72 int /* O - Exit status */
73 main(int argc
, /* I - Number of command-line arguments */
74 char *argv
[]) /* I - Command-line arguments */
76 int i
; /* Looping var */
77 ipp_t
*msg
; /* Event message from scheduler */
78 ipp_state_t state
; /* IPP event state */
79 char *subject
, /* Subject for notification message */
80 *text
; /* Text for notification message */
81 cups_lang_t
*lang
; /* Language info */
82 char temp
[1024]; /* Temporary string */
83 int templen
; /* Length of temporary string */
84 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
85 struct sigaction action
; /* POSIX sigaction data */
86 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
90 * Don't buffer stderr...
96 * Ignore SIGPIPE signals...
100 sigset(SIGPIPE
, SIG_IGN
);
101 #elif defined(HAVE_SIGACTION)
102 memset(&action
, 0, sizeof(action
));
103 action
.sa_handler
= SIG_IGN
;
104 sigaction(SIGPIPE
, &action
, NULL
);
106 signal(SIGPIPE
, SIG_IGN
);
107 #endif /* HAVE_SIGSET */
110 * Validate command-line options...
115 fputs("Usage: mailto mailto:user@domain.com notify-user-data\n", stderr
);
119 if (strncmp(argv
[1], "mailto:", 7))
121 fprintf(stderr
, "ERROR: Bad recipient \"%s\"!\n", argv
[1]);
125 fprintf(stderr
, "DEBUG: argc=%d\n", argc
);
126 for (i
= 0; i
< argc
; i
++)
127 fprintf(stderr
, "DEBUG: argv[%d]=\"%s\"\n", i
, argv
[i
]);
130 * Load configuration data...
133 if ((lang
= cupsLangDefault()) == NULL
)
136 if (!load_configuration())
140 * Get the reply-to address...
143 templen
= sizeof(temp
);
144 httpDecode64_2(temp
, &templen
, argv
[2]);
146 if (!strncmp(temp
, "mailto:", 7))
147 strlcpy(mailtoReplyTo
, temp
+ 7, sizeof(mailtoReplyTo
));
149 fprintf(stderr
, "WARNING: Bad notify-user-data value (%d bytes) ignored!\n",
153 * Loop forever until we run out of events...
159 * Get the next event...
163 while ((state
= ippReadFile(0, msg
)) != IPP_DATA
)
165 if (state
<= IPP_IDLE
)
169 fprintf(stderr
, "DEBUG: state=%d\n", state
);
171 if (state
== IPP_ERROR
)
172 fputs("DEBUG: ippReadFile() returned IPP_ERROR!\n", stderr
);
174 if (state
<= IPP_IDLE
)
177 * Out of messages, free memory and then exit...
185 * Get the subject and text for the message, then email it...
188 subject
= cupsNotifySubject(lang
, msg
);
189 text
= cupsNotifyText(lang
, msg
);
191 fprintf(stderr
, "DEBUG: subject=\"%s\"\n", subject
);
192 fprintf(stderr
, "DEBUG: text=\"%s\"\n", text
);
195 email_message(argv
[1] + 7, subject
, text
);
198 fputs("ERROR: Missing attributes in event notification!\n", stderr
);
199 print_attributes(msg
, 4);
203 * Free the memory used for this event...
218 * 'email_message()' - Email a notification message.
222 email_message(const char *to
, /* I - Recipient of message */
223 const char *subject
, /* I - Subject of message */
224 const char *text
) /* I - Text of message */
226 cups_file_t
*fp
; /* Pipe/socket to mail server */
227 const char *nl
; /* Newline to use */
228 char response
[1024]; /* SMTP response buffer */
232 * Connect to the mail server...
235 if (mailtoSendmail
[0])
238 * Use the sendmail command...
241 fp
= pipe_sendmail(to
);
251 * Use an SMTP server...
254 char hostbuf
[1024]; /* Local hostname */
257 if (strchr(mailtoSMTPServer
, ':'))
258 fp
= cupsFileOpen(mailtoSMTPServer
, "s");
261 char spec
[1024]; /* Host:service spec */
264 snprintf(spec
, sizeof(spec
), "%s:smtp", mailtoSMTPServer
);
265 fp
= cupsFileOpen(spec
, "s");
270 fprintf(stderr
, "ERROR: Unable to connect to SMTP server \"%s\"!\n",
275 fprintf(stderr
, "DEBUG: Connected to \"%s\"...\n", mailtoSMTPServer
);
277 cupsFilePrintf(fp
, "HELO %s\r\n",
278 httpGetHostname(NULL
, hostbuf
, sizeof(hostbuf
)));
279 fprintf(stderr
, "DEBUG: >>> HELO %s\n", hostbuf
);
281 if (!cupsFileGets(fp
, response
, sizeof(response
)) || atoi(response
) >= 500)
283 fprintf(stderr
, "DEBUG: <<< %s\n", response
);
285 cupsFilePrintf(fp
, "MAIL FROM:%s\r\n", mailtoFrom
);
286 fprintf(stderr
, "DEBUG: >>> MAIL FROM:%s\n", mailtoFrom
);
288 if (!cupsFileGets(fp
, response
, sizeof(response
)) || atoi(response
) >= 500)
290 fprintf(stderr
, "DEBUG: <<< %s\n", response
);
292 cupsFilePrintf(fp
, "RCPT TO:%s\r\n", to
);
293 fprintf(stderr
, "DEBUG: >>> RCPT TO:%s\n", to
);
295 if (!cupsFileGets(fp
, response
, sizeof(response
)) || atoi(response
) >= 500)
297 fprintf(stderr
, "DEBUG: <<< %s\n", response
);
299 cupsFilePuts(fp
, "DATA\r\n");
300 fputs("DEBUG: DATA\n", stderr
);
302 if (!cupsFileGets(fp
, response
, sizeof(response
)) || atoi(response
) >= 500)
304 fprintf(stderr
, "DEBUG: <<< %s\n", response
);
310 * Send the message...
313 cupsFilePrintf(fp
, "Date: %s%s", httpGetDateString(time(NULL
)), nl
);
314 cupsFilePrintf(fp
, "From: %s%s", mailtoFrom
, nl
);
315 cupsFilePrintf(fp
, "Subject: %s %s%s", mailtoSubject
, subject
, nl
);
316 if (mailtoReplyTo
[0])
318 cupsFilePrintf(fp
, "Sender: %s%s", mailtoReplyTo
, nl
);
319 cupsFilePrintf(fp
, "Reply-To: %s%s", mailtoReplyTo
, nl
);
321 cupsFilePrintf(fp
, "To: %s%s", to
, nl
);
323 cupsFilePrintf(fp
, "Cc: %s%s", mailtoCc
, nl
);
324 cupsFilePrintf(fp
, "Content-Type: text/plain%s", nl
);
325 cupsFilePuts(fp
, nl
);
326 cupsFilePrintf(fp
, "%s%s", text
, nl
);
327 cupsFilePrintf(fp
, ".\n", nl
);
330 * Close the connection to the mail server...
333 if (mailtoSendmail
[0])
336 * Close the pipe and wait for the sendmail command to finish...
339 int status
; /* Exit status */
348 * Report any non-zero status...
353 if (WIFEXITED(status
))
354 fprintf(stderr
, "ERROR: Sendmail command returned status %d!\n",
355 WEXITSTATUS(status
));
357 fprintf(stderr
, "ERROR: Sendmail command crashed on signal %d!\n",
364 * Finish up the SMTP submission and close the connection...
367 if (!cupsFileGets(fp
, response
, sizeof(response
)) || atoi(response
) >= 500)
369 fprintf(stderr
, "DEBUG: <<< %s\n", response
);
372 * Process SMTP errors here...
377 cupsFilePuts(fp
, "QUIT\r\n");
378 fputs("DEBUG: QUIT\n", stderr
);
380 if (!cupsFileGets(fp
, response
, sizeof(response
)) || atoi(response
) >= 500)
382 fprintf(stderr
, "DEBUG: <<< %s\n", response
);
386 fprintf(stderr
, "DEBUG: Closed connection to \"%s\"...\n",
393 * 'load_configuration()' - Load the mailto.conf file.
396 int /* I - 1 on success, 0 on failure */
397 load_configuration(void)
399 cups_file_t
*fp
; /* mailto.conf file */
400 const char *server_root
, /* CUPS_SERVERROOT environment variable */
401 *server_admin
; /* SERVER_ADMIN environment variable */
402 char line
[1024], /* Line from file */
403 *value
; /* Value for directive */
404 int linenum
; /* Line number in file */
408 * Initialize defaults...
413 if ((server_admin
= getenv("SERVER_ADMIN")) != NULL
)
414 strlcpy(mailtoFrom
, server_admin
, sizeof(mailtoFrom
));
416 snprintf(mailtoFrom
, sizeof(mailtoFrom
), "root@%s",
417 httpGetHostname(NULL
, line
, sizeof(line
)));
419 strlcpy(mailtoSendmail
, "/usr/sbin/sendmail", sizeof(mailtoSendmail
));
421 mailtoSMTPServer
[0] = '\0';
423 mailtoSubject
[0] = '\0';
426 * Try loading the config file...
429 if ((server_root
= getenv("CUPS_SERVERROOT")) == NULL
)
430 server_root
= CUPS_SERVERROOT
;
432 snprintf(line
, sizeof(line
), "%s/mailto.conf", server_root
);
434 if ((fp
= cupsFileOpen(line
, "r")) == NULL
)
436 fprintf(stderr
, "ERROR: Unable to open \"%s\" - %s\n", line
,
443 while (cupsFileGetConf(fp
, line
, sizeof(line
), &value
, &linenum
))
447 fprintf(stderr
, "ERROR: No value found for %s directive on line %d!\n",
453 if (!strcasecmp(line
, "Cc"))
454 strlcpy(mailtoCc
, value
, sizeof(mailtoCc
));
455 else if (!strcasecmp(line
, "From"))
456 strlcpy(mailtoFrom
, value
, sizeof(mailtoFrom
));
457 else if (!strcasecmp(line
, "Sendmail"))
459 strlcpy(mailtoSendmail
, value
, sizeof(mailtoSendmail
));
460 mailtoSMTPServer
[0] = '\0';
462 else if (!strcasecmp(line
, "SMTPServer"))
464 mailtoSendmail
[0] = '\0';
465 strlcpy(mailtoSMTPServer
, value
, sizeof(mailtoSMTPServer
));
467 else if (!strcasecmp(line
, "Subject"))
468 strlcpy(mailtoSubject
, value
, sizeof(mailtoSubject
));
472 "ERROR: Unknown configuration directive \"%s\" on line %d!\n",
478 * Close file and return...
488 * 'pipe_sendmail()' - Open a pipe to sendmail...
491 cups_file_t
* /* O - CUPS file */
492 pipe_sendmail(const char *to
) /* I - To: address */
494 cups_file_t
*fp
; /* CUPS file */
495 int pid
; /* Process ID */
496 int pipefds
[2]; /* Pipe file descriptors */
497 int argc
; /* Number of arguments */
498 char *argv
[100], /* Argument array */
499 line
[1024], /* Sendmail command + args */
500 *lineptr
; /* Pointer into line */
504 * First break the mailtoSendmail string into arguments...
507 strlcpy(line
, mailtoSendmail
, sizeof(line
));
511 for (lineptr
= strchr(line
, ' '); lineptr
; lineptr
= strchr(lineptr
, ' '))
513 while (*lineptr
== ' ')
519 * Point to the next argument...
522 argv
[argc
++] = lineptr
;
525 * Stop if we have too many...
528 if (argc
>= (int)(sizeof(argv
) / sizeof(argv
[0]) - 2))
533 argv
[argc
++] = (char *)to
;
542 perror("ERROR: Unable to create pipe");
547 * Then run the command...
550 if ((pid
= fork()) == 0)
553 * Child goes here - redirect stdin to the input side of the pipe,
554 * redirect stdout to stderr, and exec...
566 execvp(argv
[0], argv
);
572 * Unable to fork - error out...
575 perror("ERROR: Unable to fork command");
584 * Create a CUPS file using the output side of the pipe and close the
590 if ((fp
= cupsFileOpenFd(pipefds
[1], "w")) == NULL
)
592 int status
; /* Status of command */
604 * 'print_attributes()' - Print the attributes in a request...
608 print_attributes(ipp_t
*ipp
, /* I - IPP request */
609 int indent
) /* I - Indentation */
611 int i
; /* Looping var */
612 ipp_tag_t group
; /* Current group */
613 ipp_attribute_t
*attr
; /* Current attribute */
614 ipp_value_t
*val
; /* Current value */
615 static const char * const tags
[] = /* Value/group tag strings */
618 "operation-attributes-tag",
619 "job-attributes-tag",
620 "end-of-attributes-tag",
621 "printer-attributes-tag",
622 "unsupported-attributes-tag",
623 "subscription-attributes-tag",
624 "event-attributes-tag",
682 "textWithoutLanguage",
683 "nameWithoutLanguage",
695 for (group
= IPP_TAG_ZERO
, attr
= ipp
->attrs
; attr
; attr
= attr
->next
)
697 if ((attr
->group_tag
== IPP_TAG_ZERO
&& indent
<= 8) || !attr
->name
)
699 group
= IPP_TAG_ZERO
;
704 if (group
!= attr
->group_tag
)
706 group
= attr
->group_tag
;
708 fprintf(stderr
, "DEBUG: %*s%s:\n\n", indent
- 4, "", tags
[group
]);
711 fprintf(stderr
, "DEBUG: %*s%s (", indent
, "", attr
->name
);
712 if (attr
->num_values
> 1)
713 fputs("1setOf ", stderr
);
714 fprintf(stderr
, "%s):", tags
[attr
->value_tag
]);
716 switch (attr
->value_tag
)
719 case IPP_TAG_INTEGER
:
720 for (i
= 0, val
= attr
->values
; i
< attr
->num_values
; i
++, val
++)
721 fprintf(stderr
, " %d", val
->integer
);
725 case IPP_TAG_BOOLEAN
:
726 for (i
= 0, val
= attr
->values
; i
< attr
->num_values
; i
++, val
++)
727 fprintf(stderr
, " %s", val
->boolean
? "true" : "false");
732 for (i
= 0, val
= attr
->values
; i
< attr
->num_values
; i
++, val
++)
733 fprintf(stderr
, " %d-%d", val
->range
.lower
, val
->range
.upper
);
739 time_t vtime
; /* Date/Time value */
740 struct tm
*vdate
; /* Date info */
741 char vstring
[256]; /* Formatted time */
743 for (i
= 0, val
= attr
->values
; i
< attr
->num_values
; i
++, val
++)
745 vtime
= ippDateToTime(val
->date
);
746 vdate
= localtime(&vtime
);
747 strftime(vstring
, sizeof(vstring
), "%c", vdate
);
748 fprintf(stderr
, " (%s)", vstring
);
754 case IPP_TAG_RESOLUTION
:
755 for (i
= 0, val
= attr
->values
; i
< attr
->num_values
; i
++, val
++)
756 fprintf(stderr
, " %dx%d%s", val
->resolution
.xres
,
757 val
->resolution
.yres
,
758 val
->resolution
.units
== IPP_RES_PER_INCH
? "dpi" : "dpc");
762 case IPP_TAG_STRING
:
763 case IPP_TAG_TEXTLANG
:
764 case IPP_TAG_NAMELANG
:
767 case IPP_TAG_KEYWORD
:
769 case IPP_TAG_URISCHEME
:
770 case IPP_TAG_CHARSET
:
771 case IPP_TAG_LANGUAGE
:
772 case IPP_TAG_MIMETYPE
:
773 for (i
= 0, val
= attr
->values
; i
< attr
->num_values
; i
++, val
++)
774 fprintf(stderr
, " \"%s\"", val
->string
.text
);
778 case IPP_TAG_BEGIN_COLLECTION
:
781 for (i
= 0, val
= attr
->values
; i
< attr
->num_values
; i
++, val
++)
785 print_attributes(val
->collection
, indent
+ 4);
790 fprintf(stderr
, "UNKNOWN (%d values)\n", attr
->num_values
);
798 * End of "$Id: mailto.c 5235 2006-03-06 13:02:23Z mike $".