Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
srohatgi01
GitHub Repository: srohatgi01/cups
Path: blob/master/notifier/mailto.c
1090 views
1
/*
2
* "mailto" notifier for CUPS.
3
*
4
* Copyright © 2007-2018 by Apple Inc.
5
* Copyright © 1997-2005 by Easy Software Products.
6
*
7
* Licensed under Apache License v2.0. See the file "LICENSE" for more
8
* information.
9
*/
10
11
/*
12
* Include necessary headers...
13
*/
14
15
#include <cups/cups-private.h>
16
#include <sys/wait.h>
17
#include <signal.h>
18
19
20
/*
21
* Globals...
22
*/
23
24
char mailtoCc[1024]; /* Cc email address */
25
char mailtoFrom[1024]; /* From email address */
26
char mailtoReplyTo[1024]; /* Reply-To email address */
27
char mailtoSubject[1024]; /* Subject prefix */
28
char mailtoSMTPServer[1024]; /* SMTP server to use */
29
char mailtoSendmail[1024]; /* Sendmail program to use */
30
31
32
/*
33
* Local functions...
34
*/
35
36
void email_message(const char *to, const char *subject, const char *text);
37
int load_configuration(void);
38
cups_file_t *pipe_sendmail(const char *to);
39
void print_attributes(ipp_t *ipp, int indent);
40
41
42
/*
43
* 'main()' - Main entry for the mailto notifier.
44
*/
45
46
int /* O - Exit status */
47
main(int argc, /* I - Number of command-line arguments */
48
char *argv[]) /* I - Command-line arguments */
49
{
50
int i; /* Looping var */
51
ipp_t *msg; /* Event message from scheduler */
52
ipp_state_t state; /* IPP event state */
53
char *subject, /* Subject for notification message */
54
*text; /* Text for notification message */
55
cups_lang_t *lang; /* Language info */
56
char temp[1024]; /* Temporary string */
57
int templen; /* Length of temporary string */
58
#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
59
struct sigaction action; /* POSIX sigaction data */
60
#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
61
62
63
/*
64
* Don't buffer stderr...
65
*/
66
67
setbuf(stderr, NULL);
68
69
/*
70
* Ignore SIGPIPE signals...
71
*/
72
73
#ifdef HAVE_SIGSET
74
sigset(SIGPIPE, SIG_IGN);
75
#elif defined(HAVE_SIGACTION)
76
memset(&action, 0, sizeof(action));
77
action.sa_handler = SIG_IGN;
78
sigaction(SIGPIPE, &action, NULL);
79
#else
80
signal(SIGPIPE, SIG_IGN);
81
#endif /* HAVE_SIGSET */
82
83
/*
84
* Validate command-line options...
85
*/
86
87
if (argc != 3)
88
{
89
fputs("Usage: mailto mailto:[email protected] notify-user-data\n", stderr);
90
return (1);
91
}
92
93
if (strncmp(argv[1], "mailto:", 7))
94
{
95
fprintf(stderr, "ERROR: Bad recipient \"%s\"!\n", argv[1]);
96
return (1);
97
}
98
99
fprintf(stderr, "DEBUG: argc=%d\n", argc);
100
for (i = 0; i < argc; i ++)
101
fprintf(stderr, "DEBUG: argv[%d]=\"%s\"\n", i, argv[i]);
102
103
/*
104
* Load configuration data...
105
*/
106
107
if ((lang = cupsLangDefault()) == NULL)
108
return (1);
109
110
if (!load_configuration())
111
return (1);
112
113
/*
114
* Get the reply-to address...
115
*/
116
117
templen = sizeof(temp);
118
httpDecode64_2(temp, &templen, argv[2]);
119
120
if (!strncmp(temp, "mailto:", 7))
121
strlcpy(mailtoReplyTo, temp + 7, sizeof(mailtoReplyTo));
122
else if (temp[0])
123
fprintf(stderr, "WARNING: Bad notify-user-data value (%d bytes) ignored!\n",
124
templen);
125
126
/*
127
* Loop forever until we run out of events...
128
*/
129
130
for (;;)
131
{
132
/*
133
* Get the next event...
134
*/
135
136
msg = ippNew();
137
while ((state = ippReadFile(0, msg)) != IPP_DATA)
138
{
139
if (state <= IPP_IDLE)
140
break;
141
}
142
143
fprintf(stderr, "DEBUG: state=%d\n", state);
144
145
if (state == IPP_ERROR)
146
fputs("DEBUG: ippReadFile() returned IPP_ERROR!\n", stderr);
147
148
if (state <= IPP_IDLE)
149
{
150
/*
151
* Out of messages, free memory and then exit...
152
*/
153
154
ippDelete(msg);
155
return (0);
156
}
157
158
/*
159
* Get the subject and text for the message, then email it...
160
*/
161
162
subject = cupsNotifySubject(lang, msg);
163
text = cupsNotifyText(lang, msg);
164
165
fprintf(stderr, "DEBUG: subject=\"%s\"\n", subject);
166
fprintf(stderr, "DEBUG: text=\"%s\"\n", text);
167
168
if (subject && text)
169
email_message(argv[1] + 7, subject, text);
170
else
171
{
172
fputs("ERROR: Missing attributes in event notification!\n", stderr);
173
print_attributes(msg, 4);
174
}
175
176
/*
177
* Free the memory used for this event...
178
*/
179
180
if (subject)
181
free(subject);
182
183
if (text)
184
free(text);
185
186
ippDelete(msg);
187
}
188
}
189
190
191
/*
192
* 'email_message()' - Email a notification message.
193
*/
194
195
void
196
email_message(const char *to, /* I - Recipient of message */
197
const char *subject, /* I - Subject of message */
198
const char *text) /* I - Text of message */
199
{
200
cups_file_t *fp; /* Pipe/socket to mail server */
201
const char *nl; /* Newline to use */
202
char response[1024]; /* SMTP response buffer */
203
204
205
/*
206
* Connect to the mail server...
207
*/
208
209
if (mailtoSendmail[0])
210
{
211
/*
212
* Use the sendmail command...
213
*/
214
215
fp = pipe_sendmail(to);
216
217
if (!fp)
218
return;
219
220
nl = "\n";
221
}
222
else
223
{
224
/*
225
* Use an SMTP server...
226
*/
227
228
char hostbuf[1024]; /* Local hostname */
229
230
231
if (strchr(mailtoSMTPServer, ':'))
232
{
233
fp = cupsFileOpen(mailtoSMTPServer, "s");
234
}
235
else
236
{
237
char spec[1024]; /* Host:service spec */
238
239
240
snprintf(spec, sizeof(spec), "%s:smtp", mailtoSMTPServer);
241
fp = cupsFileOpen(spec, "s");
242
}
243
244
if (!fp)
245
{
246
fprintf(stderr, "ERROR: Unable to connect to SMTP server \"%s\"!\n",
247
mailtoSMTPServer);
248
return;
249
}
250
251
fprintf(stderr, "DEBUG: Connected to \"%s\"...\n", mailtoSMTPServer);
252
253
if (!cupsFileGets(fp, response, sizeof(response)) || atoi(response) >= 500)
254
goto smtp_error;
255
fprintf(stderr, "DEBUG: <<< %s\n", response);
256
257
cupsFilePrintf(fp, "HELO %s\r\n",
258
httpGetHostname(NULL, hostbuf, sizeof(hostbuf)));
259
fprintf(stderr, "DEBUG: >>> HELO %s\n", hostbuf);
260
261
if (!cupsFileGets(fp, response, sizeof(response)) || atoi(response) >= 500)
262
goto smtp_error;
263
fprintf(stderr, "DEBUG: <<< %s\n", response);
264
265
cupsFilePrintf(fp, "MAIL FROM:%s\r\n", mailtoFrom);
266
fprintf(stderr, "DEBUG: >>> MAIL FROM:%s\n", mailtoFrom);
267
268
if (!cupsFileGets(fp, response, sizeof(response)) || atoi(response) >= 500)
269
goto smtp_error;
270
fprintf(stderr, "DEBUG: <<< %s\n", response);
271
272
cupsFilePrintf(fp, "RCPT TO:%s\r\n", to);
273
fprintf(stderr, "DEBUG: >>> RCPT TO:%s\n", to);
274
275
if (!cupsFileGets(fp, response, sizeof(response)) || atoi(response) >= 500)
276
goto smtp_error;
277
fprintf(stderr, "DEBUG: <<< %s\n", response);
278
279
cupsFilePuts(fp, "DATA\r\n");
280
fputs("DEBUG: DATA\n", stderr);
281
282
if (!cupsFileGets(fp, response, sizeof(response)) || atoi(response) >= 500)
283
goto smtp_error;
284
fprintf(stderr, "DEBUG: <<< %s\n", response);
285
286
nl = "\r\n";
287
}
288
289
/*
290
* Send the message...
291
*/
292
293
cupsFilePrintf(fp, "Date: %s%s", httpGetDateString(time(NULL)), nl);
294
cupsFilePrintf(fp, "From: %s%s", mailtoFrom, nl);
295
cupsFilePrintf(fp, "Subject: %s %s%s", mailtoSubject, subject, nl);
296
if (mailtoReplyTo[0])
297
{
298
cupsFilePrintf(fp, "Sender: %s%s", mailtoReplyTo, nl);
299
cupsFilePrintf(fp, "Reply-To: %s%s", mailtoReplyTo, nl);
300
}
301
cupsFilePrintf(fp, "To: %s%s", to, nl);
302
if (mailtoCc[0])
303
cupsFilePrintf(fp, "Cc: %s%s", mailtoCc, nl);
304
cupsFilePrintf(fp, "Content-Type: text/plain%s", nl);
305
cupsFilePuts(fp, nl);
306
cupsFilePrintf(fp, "%s%s", text, nl);
307
cupsFilePrintf(fp, ".%s", nl);
308
309
/*
310
* Close the connection to the mail server...
311
*/
312
313
if (mailtoSendmail[0])
314
{
315
/*
316
* Close the pipe and wait for the sendmail command to finish...
317
*/
318
319
int status; /* Exit status */
320
321
322
cupsFileClose(fp);
323
324
while (wait(&status))
325
{
326
if (errno != EINTR)
327
{
328
fprintf(stderr, "DEBUG: Unable to get child status: %s\n",
329
strerror(errno));
330
status = 0;
331
break;
332
}
333
}
334
335
/*
336
* Report any non-zero status...
337
*/
338
339
if (status)
340
{
341
if (WIFEXITED(status))
342
fprintf(stderr, "ERROR: Sendmail command returned status %d!\n",
343
WEXITSTATUS(status));
344
else
345
fprintf(stderr, "ERROR: Sendmail command crashed on signal %d!\n",
346
WTERMSIG(status));
347
}
348
}
349
else
350
{
351
/*
352
* Finish up the SMTP submission and close the connection...
353
*/
354
355
if (!cupsFileGets(fp, response, sizeof(response)) || atoi(response) >= 500)
356
goto smtp_error;
357
fprintf(stderr, "DEBUG: <<< %s\n", response);
358
359
/*
360
* Process SMTP errors here...
361
*/
362
363
smtp_error:
364
365
cupsFilePuts(fp, "QUIT\r\n");
366
fputs("DEBUG: QUIT\n", stderr);
367
368
if (!cupsFileGets(fp, response, sizeof(response)) || atoi(response) >= 500)
369
fprintf(stderr, "ERROR: Got \"%s\" trying to QUIT connection.\n",
370
response);
371
else
372
fprintf(stderr, "DEBUG: <<< %s\n", response);
373
374
cupsFileClose(fp);
375
376
fprintf(stderr, "DEBUG: Closed connection to \"%s\"...\n",
377
mailtoSMTPServer);
378
}
379
}
380
381
382
/*
383
* 'load_configuration()' - Load the mailto.conf file.
384
*/
385
386
int /* I - 1 on success, 0 on failure */
387
load_configuration(void)
388
{
389
cups_file_t *fp; /* mailto.conf file */
390
const char *server_root, /* CUPS_SERVERROOT environment variable */
391
*server_admin; /* SERVER_ADMIN environment variable */
392
char line[1024], /* Line from file */
393
*value; /* Value for directive */
394
int linenum; /* Line number in file */
395
396
397
/*
398
* Initialize defaults...
399
*/
400
401
mailtoCc[0] = '\0';
402
403
if ((server_admin = getenv("SERVER_ADMIN")) != NULL)
404
strlcpy(mailtoFrom, server_admin, sizeof(mailtoFrom));
405
else
406
snprintf(mailtoFrom, sizeof(mailtoFrom), "root@%s",
407
httpGetHostname(NULL, line, sizeof(line)));
408
409
strlcpy(mailtoSendmail, "/usr/sbin/sendmail", sizeof(mailtoSendmail));
410
411
mailtoSMTPServer[0] = '\0';
412
413
mailtoSubject[0] = '\0';
414
415
/*
416
* Try loading the config file...
417
*/
418
419
if ((server_root = getenv("CUPS_SERVERROOT")) == NULL)
420
server_root = CUPS_SERVERROOT;
421
422
snprintf(line, sizeof(line), "%s/mailto.conf", server_root);
423
424
if ((fp = cupsFileOpen(line, "r")) == NULL)
425
{
426
if (errno != ENOENT)
427
{
428
fprintf(stderr, "ERROR: Unable to open \"%s\" - %s\n", line,
429
strerror(errno));
430
return (1);
431
}
432
else
433
return (0);
434
}
435
436
linenum = 0;
437
438
while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
439
{
440
if (!value)
441
{
442
fprintf(stderr, "ERROR: No value found for %s directive on line %d!\n",
443
line, linenum);
444
cupsFileClose(fp);
445
return (0);
446
}
447
448
if (!_cups_strcasecmp(line, "Cc"))
449
strlcpy(mailtoCc, value, sizeof(mailtoCc));
450
else if (!_cups_strcasecmp(line, "From"))
451
strlcpy(mailtoFrom, value, sizeof(mailtoFrom));
452
else if (!_cups_strcasecmp(line, "Sendmail"))
453
{
454
strlcpy(mailtoSendmail, value, sizeof(mailtoSendmail));
455
mailtoSMTPServer[0] = '\0';
456
}
457
else if (!_cups_strcasecmp(line, "SMTPServer"))
458
{
459
mailtoSendmail[0] = '\0';
460
strlcpy(mailtoSMTPServer, value, sizeof(mailtoSMTPServer));
461
}
462
else if (!_cups_strcasecmp(line, "Subject"))
463
strlcpy(mailtoSubject, value, sizeof(mailtoSubject));
464
else
465
{
466
fprintf(stderr,
467
"ERROR: Unknown configuration directive \"%s\" on line %d!\n",
468
line, linenum);
469
}
470
}
471
472
/*
473
* Close file and return...
474
*/
475
476
cupsFileClose(fp);
477
478
return (1);
479
}
480
481
482
/*
483
* 'pipe_sendmail()' - Open a pipe to sendmail...
484
*/
485
486
cups_file_t * /* O - CUPS file */
487
pipe_sendmail(const char *to) /* I - To: address */
488
{
489
cups_file_t *fp; /* CUPS file */
490
int pid; /* Process ID */
491
int pipefds[2]; /* Pipe file descriptors */
492
int argc; /* Number of arguments */
493
char *argv[100], /* Argument array */
494
line[1024], /* Sendmail command + args */
495
*lineptr; /* Pointer into line */
496
497
498
/*
499
* First break the mailtoSendmail string into arguments...
500
*/
501
502
strlcpy(line, mailtoSendmail, sizeof(line));
503
argv[0] = line;
504
argc = 1;
505
506
for (lineptr = strchr(line, ' '); lineptr; lineptr = strchr(lineptr, ' '))
507
{
508
while (*lineptr == ' ')
509
*lineptr++ = '\0';
510
511
if (*lineptr)
512
{
513
/*
514
* Point to the next argument...
515
*/
516
517
argv[argc ++] = lineptr;
518
519
/*
520
* Stop if we have too many...
521
*/
522
523
if (argc >= (int)(sizeof(argv) / sizeof(argv[0]) - 2))
524
break;
525
}
526
}
527
528
argv[argc ++] = (char *)to;
529
argv[argc] = NULL;
530
531
/*
532
* Create the pipe...
533
*/
534
535
if (pipe(pipefds))
536
{
537
perror("ERROR: Unable to create pipe");
538
return (NULL);
539
}
540
541
/*
542
* Then run the command...
543
*/
544
545
if ((pid = fork()) == 0)
546
{
547
/*
548
* Child goes here - redirect stdin to the input side of the pipe,
549
* redirect stdout to stderr, and exec...
550
*/
551
552
close(0);
553
dup(pipefds[0]);
554
555
close(1);
556
dup(2);
557
558
close(pipefds[0]);
559
close(pipefds[1]);
560
561
execvp(argv[0], argv);
562
exit(errno);
563
}
564
else if (pid < 0)
565
{
566
/*
567
* Unable to fork - error out...
568
*/
569
570
perror("ERROR: Unable to fork command");
571
572
close(pipefds[0]);
573
close(pipefds[1]);
574
575
return (NULL);
576
}
577
578
/*
579
* Create a CUPS file using the output side of the pipe and close the
580
* input side...
581
*/
582
583
close(pipefds[0]);
584
585
if ((fp = cupsFileOpenFd(pipefds[1], "w")) == NULL)
586
{
587
int status; /* Status of command */
588
589
590
close(pipefds[1]);
591
wait(&status);
592
}
593
594
return (fp);
595
}
596
597
598
/*
599
* 'print_attributes()' - Print the attributes in a request...
600
*/
601
602
void
603
print_attributes(ipp_t *ipp, /* I - IPP request */
604
int indent) /* I - Indentation */
605
{
606
ipp_tag_t group; /* Current group */
607
ipp_attribute_t *attr; /* Current attribute */
608
char buffer[1024]; /* Value buffer */
609
610
611
for (group = IPP_TAG_ZERO, attr = ipp->attrs; attr; attr = attr->next)
612
{
613
if ((attr->group_tag == IPP_TAG_ZERO && indent <= 8) || !attr->name)
614
{
615
group = IPP_TAG_ZERO;
616
fputc('\n', stderr);
617
continue;
618
}
619
620
if (group != attr->group_tag)
621
{
622
group = attr->group_tag;
623
624
fprintf(stderr, "DEBUG: %*s%s:\n\n", indent - 4, "", ippTagString(group));
625
}
626
627
ippAttributeString(attr, buffer, sizeof(buffer));
628
629
fprintf(stderr, "DEBUG: %*s%s (%s%s) %s", indent, "", attr->name,
630
attr->num_values > 1 ? "1setOf " : "",
631
ippTagString(attr->value_tag), buffer);
632
}
633
}
634
635