PageRenderTime 53ms CodeModel.GetById 12ms RepoModel.GetById 1ms app.codeStats 0ms

/mh/pick.y

#
Happy | 445 lines | 378 code | 67 blank | 0 comment | 0 complexity | 00d6b54d9e56cf89aa31e025876ba68d MD5 | raw file
Possible License(s): GPL-3.0, LGPL-3.0, CC-BY-SA-3.0
  1. %{
  2. /* GNU Mailutils -- a suite of utilities for electronic mail
  3. Copyright (C) 2003-2007, 2009-2012, 2014 Free Software Foundation,
  4. Inc.
  5. GNU Mailutils is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 3, or (at your option)
  8. any later version.
  9. GNU Mailutils is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */
  15. #include <mh.h>
  16. #include <regex.h>
  17. #include <pick.h>
  18. static node_t *pick_node_create (node_type type, void *a, void *b);
  19. static void set_cflags (char *str);
  20. static regex_t *
  21. regex_dup (regex_t *re)
  22. {
  23. regex_t *rp = mu_alloc (sizeof (*rp));
  24. *rp = *re;
  25. return rp;
  26. }
  27. int yyerror (const char *s);
  28. int yylex (void);
  29. static node_t *parse_tree;
  30. static int nesting_level;
  31. static int reg_flags = REG_EXTENDED|REG_ICASE;
  32. %}
  33. %token <string> T_COMP T_DATEFIELD T_STRING T_CFLAGS
  34. %token T_LBRACE T_RBRACE T_BEFORE T_AFTER
  35. %left T_OR
  36. %left T_AND
  37. %left T_NOT
  38. %union {
  39. char *string;
  40. node_t *node;
  41. regex_t regex;
  42. };
  43. %type <node> expr exprlist
  44. %type <regex> regex
  45. %%
  46. input : /* empty */
  47. {
  48. parse_tree = NULL;
  49. }
  50. | exprlist
  51. {
  52. parse_tree = $1;
  53. }
  54. ;
  55. exprlist : expr
  56. | exprlist expr
  57. {
  58. $$ = pick_node_create (node_and, $1, $2);
  59. }
  60. ;
  61. cflags : /* empty */
  62. | T_CFLAGS
  63. {
  64. set_cflags ($1);
  65. }
  66. ;
  67. regex : cflags T_STRING
  68. {
  69. int rc = regcomp (&$$, $2, reg_flags|REG_NOSUB);
  70. if (rc)
  71. {
  72. char errbuf[512];
  73. regerror (rc, &$$, errbuf, sizeof (errbuf));
  74. mu_error ("error compiling regex \"%s\": %s",
  75. $2, errbuf);
  76. YYERROR;
  77. }
  78. }
  79. ;
  80. expr : lbrace exprlist rbrace
  81. {
  82. $$ = $2;
  83. }
  84. | cflags T_COMP regex
  85. {
  86. $$ = pick_node_create (node_regex, $2, regex_dup (&$3));
  87. }
  88. | regex
  89. {
  90. $$ = pick_node_create (node_regex, NULL, regex_dup (&$1));
  91. }
  92. | T_DATEFIELD
  93. {
  94. $$ = pick_node_create (node_datefield, $1, NULL);
  95. }
  96. | T_BEFORE T_STRING
  97. {
  98. time_t t;
  99. if (mu_parse_date ($2, &t, NULL))
  100. {
  101. mu_error (_("bad date format: %s"), $2);
  102. exit (1);
  103. }
  104. $$ = pick_node_create (node_before, NULL, NULL);
  105. $$->v.time = t;
  106. }
  107. | T_AFTER T_STRING
  108. {
  109. time_t t;
  110. if (mu_parse_date ($2, &t, NULL))
  111. {
  112. mu_error (_("bad date format: %s"), $2);
  113. exit (1);
  114. }
  115. $$ = pick_node_create (node_after, NULL, NULL);
  116. $$->v.time = t;
  117. }
  118. | expr T_AND expr
  119. {
  120. $$ = pick_node_create (node_and, $1, $3);
  121. }
  122. | expr T_OR expr
  123. {
  124. $$ = pick_node_create (node_or, $1, $3);
  125. }
  126. | T_NOT expr
  127. {
  128. $$ = pick_node_create (node_not, $2, NULL);
  129. }
  130. ;
  131. lbrace : T_LBRACE
  132. {
  133. nesting_level++;
  134. }
  135. ;
  136. rbrace : T_RBRACE
  137. {
  138. nesting_level--;
  139. }
  140. ;
  141. %%
  142. /* Lexical analizer */
  143. struct token
  144. {
  145. int tok;
  146. char *val;
  147. };
  148. static mu_iterator_t iterator;
  149. int
  150. yylex ()
  151. {
  152. struct token *tok;
  153. if (mu_iterator_is_done (iterator))
  154. return 0;
  155. mu_iterator_current (iterator, (void **)&tok);
  156. mu_iterator_next (iterator);
  157. yylval.string = tok->val;
  158. return tok->tok;
  159. }
  160. static char *
  161. tokname (int tok)
  162. {
  163. switch (tok)
  164. {
  165. case T_DATEFIELD:
  166. return "--datefield";
  167. case T_BEFORE:
  168. return "--before";
  169. case T_AFTER:
  170. return "--after";
  171. case T_LBRACE:
  172. return "--lbrace";
  173. case T_RBRACE:
  174. return "--rbrace";
  175. case T_OR:
  176. return "--or";
  177. case T_AND:
  178. return "--and";
  179. case T_NOT:
  180. return "--not";
  181. }
  182. return NULL;
  183. }
  184. int
  185. yyerror (const char *s)
  186. {
  187. int tok = yylex ();
  188. const char *str;
  189. if (!tok)
  190. str = _("end of input");
  191. else if (yylval.string)
  192. str = yylval.string;
  193. else
  194. str = tokname (tok);
  195. if (nesting_level)
  196. mu_error (_("%s near %s (missing closing brace?)"), s, str);
  197. else
  198. mu_error (_("%s near %s"), s, str);
  199. return 0;
  200. }
  201. void
  202. pick_add_token (mu_list_t *list, int tok, char *val)
  203. {
  204. struct token *tp;
  205. int rc;
  206. if (!*list && (rc = mu_list_create (list)))
  207. {
  208. mu_error(_("cannot create list: %s"), mu_strerror (rc));
  209. exit (1);
  210. }
  211. tp = mu_alloc (sizeof (*tp));
  212. tp->tok = tok;
  213. tp->val = val;
  214. mu_list_append (*list, tp);
  215. }
  216. /* Main entry point */
  217. int
  218. pick_parse (mu_list_t toklist)
  219. {
  220. int rc;
  221. if (!toklist)
  222. {
  223. parse_tree = NULL;
  224. return 0;
  225. }
  226. if (mu_list_get_iterator (toklist, &iterator))
  227. return -1;
  228. mu_iterator_first (iterator);
  229. rc = yyparse ();
  230. mu_iterator_destroy (&iterator);
  231. return rc;
  232. }
  233. /* Parse tree functions */
  234. node_t *
  235. pick_node_create (node_type type, void *a, void *b)
  236. {
  237. node_t *node;
  238. node = mu_alloc (sizeof (*node));
  239. node->type = type;
  240. node->v.gen.a = a;
  241. node->v.gen.b = b;
  242. return node;
  243. }
  244. struct eval_env
  245. {
  246. mu_message_t msg;
  247. char *datefield;
  248. };
  249. static int
  250. match_header (mu_message_t msg, char *comp, regex_t *regex)
  251. {
  252. int rc;
  253. size_t i, count;
  254. mu_header_t hdr = NULL;
  255. const char *buf;
  256. rc = mu_message_get_header (msg, &hdr);
  257. if (rc)
  258. {
  259. mu_error (_("cannot get header: %s"), mu_strerror (rc));
  260. return 0;
  261. }
  262. mu_header_get_field_count (hdr, &count);
  263. for (i = 1; i <= count; i++)
  264. {
  265. mu_header_sget_field_name (hdr, i, &buf);
  266. if (mu_c_strcasecmp (buf, comp) == 0)
  267. {
  268. mu_header_sget_field_value (hdr, i, &buf);
  269. if (regexec (regex, buf, 0, NULL, 0) == 0)
  270. return 1;
  271. }
  272. }
  273. return 0;
  274. }
  275. static int
  276. match_message (mu_message_t msg, regex_t *regex)
  277. {
  278. mu_stream_t str = NULL;
  279. char buf[128];
  280. size_t n;
  281. mu_message_get_streamref (msg, &str);
  282. while (mu_stream_readline (str, buf, sizeof buf, &n) == 0
  283. && n > 0)
  284. {
  285. buf[n] = 0;
  286. if (regexec (regex, buf, 0, NULL, 0) == 0)
  287. return 1;
  288. }
  289. mu_stream_destroy (&str);
  290. return 0;
  291. }
  292. static int
  293. get_date_field (struct eval_env *env, time_t *t)
  294. {
  295. mu_header_t hdr;
  296. char buf[128];
  297. if (mu_message_get_header (env->msg, &hdr))
  298. return 1;
  299. if (mu_header_get_value (hdr, env->datefield, buf, sizeof buf, NULL))
  300. return 1;
  301. return mu_parse_date (buf, t, NULL);
  302. }
  303. static int
  304. pick_eval_node (node_t *node, struct eval_env *env)
  305. {
  306. time_t t;
  307. switch (node->type)
  308. {
  309. case node_and:
  310. if (!pick_eval_node (node->v.op.larg, env))
  311. return 0;
  312. return pick_eval_node (node->v.op.rarg, env);
  313. case node_or:
  314. if (pick_eval_node (node->v.op.larg, env))
  315. return 1;
  316. return pick_eval_node (node->v.op.rarg, env);
  317. case node_not:
  318. return !pick_eval_node (node->v.op.larg, env);
  319. case node_regex:
  320. if (node->v.re.comp)
  321. return match_header (env->msg, node->v.re.comp, node->v.re.regex);
  322. else
  323. return match_message (env->msg, node->v.re.regex);
  324. case node_datefield:
  325. env->datefield = node->v.df.datefield;
  326. return 1;
  327. case node_before:
  328. if (get_date_field (env, &t))
  329. break;
  330. return t < node->v.time;
  331. case node_after:
  332. if (get_date_field (env, &t))
  333. break;
  334. return t > node->v.time;
  335. }
  336. return 0;
  337. }
  338. int
  339. pick_eval (mu_message_t msg)
  340. {
  341. struct eval_env env;
  342. if (!parse_tree)
  343. return 1;
  344. env.msg = msg;
  345. env.datefield = "date";
  346. return pick_eval_node (parse_tree, &env);
  347. }
  348. void
  349. set_cflags (char *str)
  350. {
  351. reg_flags = 0;
  352. for (; *str; str++)
  353. {
  354. switch (*str)
  355. {
  356. case 'b':
  357. case 'B':
  358. reg_flags &= ~REG_EXTENDED;
  359. break;
  360. case 'e':
  361. case 'E':
  362. reg_flags |= REG_EXTENDED;
  363. break;
  364. case 'c':
  365. case 'C':
  366. reg_flags &= ~REG_ICASE;
  367. break;
  368. case 'i':
  369. case 'I':
  370. reg_flags |= REG_ICASE;
  371. break;
  372. default:
  373. mu_error (_("Invalid regular expression flag: %c"), *str);
  374. exit (1);
  375. }
  376. }
  377. }