+ if (parse_semicolon(filter) == -1)
+ return -1;
+ }
+#ifdef ENOTIFY
+ else if (parse_identifier(filter, CUS "notify"))
+ {
+ /*
+ notify-command = "notify" { notify-options } <method: string> ";"
+ notify-options = [":from" string]
+ [":importance" <"1" / "2" / "3">]
+ [":options" 1*(string-list / number)]
+ [":message" string]
+ */
+
+ int m;
+ gstring from = { .s = NULL, .ptr = -1 };
+ gstring importance = { .s = NULL, .ptr = -1 };
+ gstring message = { .s = NULL, .ptr = -1 };
+ gstring method;
+ struct Notification *already;
+ string_item * recipient = NULL;
+ gstring header = { .s = NULL, .ptr = -1 };
+ gstring subject = { .s = NULL, .ptr = -1 };
+ gstring body = { .s = NULL, .ptr = -1 };
+ uschar *envelope_from;
+ gstring auto_submitted_value;
+ uschar *auto_submitted_def;
+
+ if (!filter->require_enotify)
+ {
+ filter->errmsg = CUS "missing previous require \"enotify\";";
+ return -1;
+ }
+ envelope_from = sender_address && sender_address[0]
+ ? expand_string(US"$local_part_prefix$local_part$local_part_suffix@$domain") : US "";
+ if (!envelope_from)
+ {
+ filter->errmsg = CUS "expansion failure for envelope from";
+ return -1;
+ }
+ for (;;)
+ {
+ if (parse_white(filter) == -1)
+ return -1;
+ if (parse_identifier(filter, CUS ":from") == 1)
+ {
+ if (parse_white(filter) == -1)
+ return -1;
+ if ((m = parse_string(filter, &from)) != 1)
+ {
+ if (m == 0) filter->errmsg = CUS "from string expected";
+ return -1;
+ }
+ }
+ else if (parse_identifier(filter, CUS ":importance") == 1)
+ {
+ if (parse_white(filter) == -1)
+ return -1;
+ if ((m = parse_string(filter, &importance)) != 1)
+ {
+ if (m == 0)
+ filter->errmsg = CUS "importance string expected";
+ return -1;
+ }
+ if (importance.ptr != 1 || importance.s[0] < '1' || importance.s[0] > '3')
+ {
+ filter->errmsg = CUS "invalid importance";
+ return -1;
+ }
+ }
+ else if (parse_identifier(filter, CUS ":options") == 1)
+ {
+ if (parse_white(filter) == -1)
+ return -1;
+ }
+ else if (parse_identifier(filter, CUS ":message") == 1)
+ {
+ if (parse_white(filter) == -1)
+ return -1;
+ if ((m = parse_string(filter, &message)) != 1)
+ {
+ if (m == 0)
+ filter->errmsg = CUS "message string expected";
+ return -1;
+ }
+ }
+ else break;
+ }
+ if (parse_white(filter) == -1)
+ return -1;
+ if ((m = parse_string(filter, &method)) != 1)
+ {
+ if (m == 0)
+ filter->errmsg = CUS "missing method string";
+ return -1;
+ }
+ if (parse_semicolon(filter) == -1)
+ return -1;
+ if (parse_mailto_uri(filter, method.s, &recipient, &header, &subject, &body) != 1)
+ return -1;
+ if (exec)
+ {
+ if (message.ptr == -1)
+ message = subject;
+ if (message.ptr == -1)
+ expand_header(&message, &str_subject);
+ expand_header(&auto_submitted_value, &str_auto_submitted);
+ auto_submitted_def = expand_string(US"${if def:header_auto-submitted {true}{false}}");
+ if (!auto_submitted_value.s || !auto_submitted_def)
+ {
+ filter->errmsg = CUS "header string expansion failed";
+ return -1;
+ }
+ if (Ustrcmp(auto_submitted_def,"true") != 0 || Ustrcmp(auto_submitted_value.s,"no") == 0)
+ {
+ for (already = filter->notified; already; already = already->next)
+ {
+ if ( already->method.ptr == method.ptr
+ && (method.ptr == -1 || Ustrcmp(already->method.s, method.s) == 0)
+ && already->importance.ptr == importance.ptr
+ && (importance.ptr == -1 || Ustrcmp(already->importance.s, importance.s) == 0)
+ && already->message.ptr == message.ptr
+ && (message.ptr == -1 || Ustrcmp(already->message.s, message.s) == 0))
+ break;
+ }
+ if (!already)
+ /* New notification, process it */
+ {
+ struct Notification * sent = store_get(sizeof(struct Notification), GET_UNTAINTED);
+ sent->method = method;
+ sent->importance = importance;
+ sent->message = message;
+ sent->next = filter->notified;
+ filter->notified = sent;
+ #ifndef COMPILE_SYNTAX_CHECKER
+ if (filter_test == FTEST_NONE)
+ {
+ int pid, fd;
+
+ if ((pid = child_open_exim2(&fd, envelope_from, envelope_from,
+ US"sieve-notify")) >= 1)
+ {
+ FILE * f = fdopen(fd, "wb");
+
+ fprintf(f,"From: %s\n", from.ptr == -1
+ ? expand_string(US"$local_part_prefix$local_part$local_part_suffix@$domain")
+ : from.s);
+ for (string_item * p = recipient; p; p = p->next)
+ fprintf(f, "To: %s\n", p->text);
+ fprintf(f, "Auto-Submitted: auto-notified; %s\n", filter->enotify_mailto_owner);
+ if (header.ptr > 0) fprintf(f, "%s", header.s);
+ if (message.ptr == -1)
+ {
+ message.s = US"Notification";
+ message.ptr = Ustrlen(message.s);
+ }
+ if (message.ptr != -1)
+ fprintf(f, "Subject: %s\n", parse_quote_2047(message.s,
+ message.ptr, US"utf-8", TRUE));
+ fprintf(f,"\n");
+ if (body.ptr > 0) fprintf(f, "%s\n", body.s);
+ fflush(f);
+ (void)fclose(f);
+ (void)child_close(pid, 0);
+ }
+ }
+ if ((filter_test != FTEST_NONE && debug_selector != 0) || debug_selector & D_filter)
+ debug_printf_indent("Notification to `%s': '%s'.\n", method.s, message.ptr != -1 ? message.s : CUS "");
+#endif
+ }
+ else
+ if ((filter_test != FTEST_NONE && debug_selector != 0) || debug_selector & D_filter)
+ debug_printf_indent("Repeated notification to `%s' ignored.\n", method.s);
+ }
+ else
+ if ((filter_test != FTEST_NONE && debug_selector != 0) || debug_selector & D_filter)
+ debug_printf_indent("Ignoring notification, triggering message contains Auto-submitted: field.\n");
+ }