PageRenderTime 45ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/libmu_sieve/extensions/pipe.c

#
C | 271 lines | 209 code | 33 blank | 29 comment | 31 complexity | 8602f3aad1ef807c9c57c71047cf1ba5 MD5 | raw file
Possible License(s): GPL-3.0, LGPL-3.0, CC-BY-SA-3.0
  1. /* GNU Mailutils -- a suite of utilities for electronic mail
  2. Copyright (C) 2007, 2009-2012, 2014 Free Software Foundation, Inc.
  3. This library is free software; you can redistribute it and/or
  4. modify it under the terms of the GNU Lesser General Public
  5. License as published by the Free Software Foundation; either
  6. version 3 of the License, or (at your option) any later version.
  7. This library is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  10. Lesser General Public License for more details.
  11. You should have received a copy of the GNU Lesser General
  12. Public License along with this library. If not, see
  13. <http://www.gnu.org/licenses/>. */
  14. /* Syntax: pipe [:envelope] <program: string>
  15. The pipe action executes a shell command specified by its
  16. argument and pipes the entire message to its standard input.
  17. The envelope of the message is included, if the :envelope tag is given.
  18. Notes/FIXME: 1. it would be nice to implement meta-variables in
  19. <program call> which would expand to various
  20. items from the message being handled.
  21. 2. :mime tag could be useful too.
  22. */
  23. #ifdef HAVE_CONFIG_H
  24. # include <config.h>
  25. #endif
  26. #include <stdio.h>
  27. #include <unistd.h>
  28. #include <stdlib.h>
  29. #include <sys/types.h>
  30. #include <sys/wait.h>
  31. #include <string.h>
  32. #include <signal.h>
  33. #include <regex.h>
  34. #include <mailutils/sieve.h>
  35. #include <mailutils/prog.h>
  36. #define ONERR(rc, diag, arg) \
  37. if (rc) \
  38. { \
  39. error_diag = diag; \
  40. error_arg = arg; \
  41. break; \
  42. }
  43. #define PIPE_ENVELOPE 0x01
  44. #define PIPE_HEADERS 0x02
  45. #define PIPE_BODY 0x04
  46. #define PIPE_ALL (PIPE_ENVELOPE | PIPE_HEADERS | PIPE_BODY)
  47. int
  48. sieve_pipe (mu_sieve_machine_t mach, mu_list_t args, mu_list_t tags, int test)
  49. {
  50. int retval = 0;
  51. int rc, result;
  52. mu_message_t msg;
  53. mu_sieve_value_t *val;
  54. char *cmd;
  55. mu_stream_t pstr;
  56. mu_envelope_t env;
  57. const char *error_diag = NULL;
  58. const char *error_arg = NULL;
  59. int pipe_mask = 0;
  60. val = mu_sieve_value_get (args, 0);
  61. if (!val)
  62. {
  63. mu_sieve_error (mach, "%lu: %s",
  64. (unsigned long) mu_sieve_get_message_num (mach),
  65. _("cannot get command!"));
  66. mu_sieve_abort (mach);
  67. }
  68. cmd = val->v.string;
  69. if (mu_sieve_get_debug_level (mach) & MU_SIEVE_DEBUG_TRACE)
  70. {
  71. mu_sieve_debug (mach, test ? "PIPE (test)" : "PIPE (action)");
  72. }
  73. if (mu_sieve_is_dry_run (mach))
  74. return 0;
  75. msg = mu_sieve_get_message (mach);
  76. mu_message_get_envelope (msg, &env);
  77. if (mu_sieve_tag_lookup (tags, "envelope", NULL))
  78. pipe_mask |= PIPE_ENVELOPE;
  79. if (mu_sieve_tag_lookup (tags, "header", NULL))
  80. pipe_mask |= PIPE_HEADERS;
  81. if (mu_sieve_tag_lookup (tags, "body", NULL))
  82. pipe_mask |= PIPE_BODY;
  83. if (pipe_mask == 0)
  84. pipe_mask = PIPE_ALL;
  85. do
  86. {
  87. mu_stream_t mstr = NULL;
  88. rc = mu_command_stream_create (&pstr, cmd, MU_STREAM_WRITE);
  89. ONERR (rc, _("cannot create command stream"), cmd);
  90. if (pipe_mask & PIPE_ENVELOPE)
  91. {
  92. char *p;
  93. rc = mu_envelope_aget_sender (env, &p);
  94. ONERR (rc, _("cannot get envelope sender"), NULL);
  95. rc = mu_stream_write (pstr, "From ", 5, NULL);
  96. ONERR (rc, _("stream write failed"), NULL);
  97. mu_stream_write (pstr, p, strlen (p), NULL);
  98. free (p);
  99. rc = mu_stream_write (pstr, " ", 1, NULL);
  100. ONERR (rc, _("stream write failed"), NULL);
  101. rc = mu_envelope_aget_date (env, &p);
  102. ONERR (rc, _("cannot get envelope date"), NULL);
  103. rc = mu_stream_write (pstr, p, strlen (p), NULL);
  104. ONERR (rc, _("stream write failed"), NULL);
  105. free (p);
  106. rc = mu_stream_write (pstr, "\n", 1, NULL);
  107. ONERR (rc, _("stream write failed"), NULL);
  108. }
  109. if (pipe_mask & PIPE_HEADERS)
  110. {
  111. mu_header_t hdr;
  112. mu_message_get_header (msg, &hdr);
  113. mu_header_get_streamref (hdr, &mstr);
  114. rc = mu_stream_copy (pstr, mstr, 0, NULL);
  115. ONERR (rc, _("copying headers failed"), cmd);
  116. mu_stream_destroy (&mstr);
  117. }
  118. if (pipe_mask & PIPE_BODY)
  119. {
  120. mu_body_t body;
  121. mu_message_get_body (msg, &body);
  122. mu_body_get_streamref (body, &mstr);
  123. rc = mu_stream_copy (pstr, mstr, 0, NULL);
  124. ONERR (rc, _("copying body failed"), cmd);
  125. mu_stream_destroy (&mstr);
  126. }
  127. }
  128. while (0);
  129. result = mu_stream_close (pstr);
  130. if (rc)
  131. {
  132. if (error_arg)
  133. mu_sieve_error (mach, "%lu: %s: %s: %s",
  134. (unsigned long) mu_sieve_get_message_num (mach),
  135. error_diag,
  136. error_arg,
  137. mu_strerror (rc));
  138. else
  139. mu_sieve_error (mach, "%lu: %s: %s",
  140. (unsigned long) mu_sieve_get_message_num (mach),
  141. error_diag,
  142. mu_strerror (rc));
  143. mu_stream_destroy (&pstr);
  144. mu_sieve_abort (mach);
  145. }
  146. if (test)
  147. {
  148. int code = 0;
  149. int status;
  150. rc = mu_stream_ioctl (pstr, MU_IOCTL_PROGSTREAM,
  151. MU_IOCTL_PROG_STATUS, &status);
  152. if (rc)
  153. {
  154. mu_stream_destroy (&pstr);
  155. mu_sieve_abort (mach);
  156. }
  157. if (mu_sieve_tag_lookup (tags, "exit", &val))
  158. code = val->v.number;
  159. if (result == 0)
  160. retval = code == 0;
  161. else if (result == MU_ERR_PROCESS_EXITED)
  162. retval = code == WEXITSTATUS (status);
  163. else if (result == MU_ERR_PROCESS_SIGNALED)
  164. {
  165. int signo = WTERMSIG (status);
  166. if (mu_sieve_tag_lookup (tags, "signal", &val))
  167. retval = signo == val->v.number;
  168. else
  169. {
  170. mu_stream_destroy (&pstr);
  171. mu_sieve_abort (mach);
  172. }
  173. }
  174. else
  175. {
  176. mu_sieve_error (mach, "%lu: %s",
  177. (unsigned long) mu_sieve_get_message_num (mach),
  178. mu_strerror (result));
  179. mu_stream_destroy (&pstr);
  180. mu_sieve_abort (mach);
  181. }
  182. }
  183. mu_stream_destroy (&pstr);
  184. return retval;
  185. }
  186. int
  187. sieve_action_pipe (mu_sieve_machine_t mach, mu_list_t args, mu_list_t tags)
  188. {
  189. mu_sieve_log_action (mach, "PIPE", NULL);
  190. return sieve_pipe (mach, args, tags, 0);
  191. }
  192. int
  193. sieve_test_pipe (mu_sieve_machine_t mach, mu_list_t args, mu_list_t tags)
  194. {
  195. return sieve_pipe (mach, args, tags, 1);
  196. }
  197. /* Tagged arguments: */
  198. static mu_sieve_tag_def_t pipe_tags[] = {
  199. { "envelope", SVT_VOID },
  200. { "body", SVT_VOID },
  201. { "header", SVT_VOID },
  202. { NULL }
  203. };
  204. static mu_sieve_tag_group_t pipe_action_tag_groups[] = {
  205. { pipe_tags, NULL },
  206. { NULL }
  207. };
  208. static mu_sieve_tag_def_t pipe_test_tags[] = {
  209. { "exit", SVT_NUMBER },
  210. { "signal", SVT_NUMBER },
  211. { NULL }
  212. };
  213. static mu_sieve_tag_group_t pipe_test_tag_groups[] = {
  214. { pipe_tags, NULL },
  215. { pipe_test_tags, NULL },
  216. { NULL }
  217. };
  218. /* Required arguments: */
  219. static mu_sieve_data_type pipe_args[] = {
  220. SVT_STRING, /* program call */
  221. SVT_VOID
  222. };
  223. int
  224. SIEVE_EXPORT (pipe, init) (mu_sieve_machine_t mach)
  225. {
  226. int rc;
  227. rc = mu_sieve_register_action (mach, "pipe", sieve_action_pipe,
  228. pipe_args, pipe_action_tag_groups, 1);
  229. if (rc)
  230. return rc;
  231. return mu_sieve_register_test (mach, "pipe", sieve_test_pipe,
  232. pipe_args, pipe_test_tag_groups, 1);
  233. }