1 |
/* |
2 |
* Copyright (c) 2002-2003 Erik Fears |
3 |
* Copyright (c) 2014-2020 ircd-hybrid development team |
4 |
* |
5 |
* This program 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 2 of the License, or |
8 |
* (at your option) any later version. |
9 |
* |
10 |
* This program is distributed in the hope that it will be useful, |
11 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 |
* GNU General Public License for more details. |
14 |
* |
15 |
* You should have received a copy of the GNU General Public License |
16 |
* along with this program; if not, write to the Free Software |
17 |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 |
18 |
* USA |
19 |
*/ |
20 |
|
21 |
%{ |
22 |
#include <string.h> |
23 |
|
24 |
#include "memory.h" |
25 |
#include "config.h" |
26 |
|
27 |
int yylex(void); |
28 |
|
29 |
static void *tmp; /* Variable to temporarily hold nodes before insertion to list */ |
30 |
|
31 |
%} |
32 |
|
33 |
%token ADDRESS_FAMILY |
34 |
%token AWAY |
35 |
%token BAN_UNKNOWN |
36 |
%token BLACKLIST |
37 |
%token BYTES KBYTES MBYTES |
38 |
%token CHANNEL |
39 |
%token COMMAND_INTERVAL |
40 |
%token COMMAND_QUEUE_SIZE |
41 |
%token COMMAND_TIMEOUT |
42 |
%token CONNREGEX |
43 |
%token DNS_FDLIMIT |
44 |
%token DNS_TIMEOUT |
45 |
%token DNSBL_FROM |
46 |
%token DNSBL_TO |
47 |
%token EXEMPT |
48 |
%token FD |
49 |
%token INVITE |
50 |
%token IPV4 |
51 |
%token IPV6 |
52 |
%token IRC |
53 |
%token KLINE |
54 |
%token KEY |
55 |
%token MASK |
56 |
%token MAX_READ |
57 |
%token MODE |
58 |
%token NAME |
59 |
%token NEGCACHE |
60 |
%token NEGCACHE_REBUILD |
61 |
%token NICK |
62 |
%token NICKSERV |
63 |
%token NOTICE |
64 |
%token OPER |
65 |
%token OPM |
66 |
%token OPTIONS |
67 |
%token PASSWORD |
68 |
%token PERFORM |
69 |
%token PIDFILE |
70 |
%token PORT |
71 |
%token PROTOCOL |
72 |
%token READTIMEOUT |
73 |
%token REALNAME |
74 |
%token RECONNECTINTERVAL |
75 |
%token REPLY |
76 |
%token SCANLOG |
77 |
%token SCANNER |
78 |
%token SECONDS MINUTES HOURS DAYS WEEKS MONTHS YEARS |
79 |
%token SENDMAIL |
80 |
%token SERVER |
81 |
%token TARGET_IP |
82 |
%token TARGET_PORT |
83 |
%token TARGET_STRING |
84 |
%token TIMEOUT |
85 |
%token TLS |
86 |
%token TLS_HOSTNAME_VERIFICATION |
87 |
%token TYPE |
88 |
%token USERNAME |
89 |
%token USER |
90 |
%token VHOST |
91 |
|
92 |
%union |
93 |
{ |
94 |
int number; |
95 |
char *string; |
96 |
} |
97 |
|
98 |
%token <number> NUMBER |
99 |
%token <string> STRING |
100 |
%token <number> PROTOCOLTYPE |
101 |
%type <number> timespec |
102 |
%type <number> timespec_ |
103 |
%type <number> sizespec |
104 |
%type <number> sizespec_ |
105 |
|
106 |
%% |
107 |
|
108 |
config: |
109 |
| config config_items |
110 |
; |
111 |
|
112 |
config_items: irc_entry | |
113 |
options_entry | |
114 |
opm_entry | |
115 |
user_entry | |
116 |
scanner_entry | |
117 |
exempt_entry; |
118 |
|
119 |
timespec_: { $$ = 0; } | timespec; |
120 |
timespec: NUMBER timespec_ { $$ = $1 + $2; } | |
121 |
NUMBER SECONDS timespec_ { $$ = $1 + $3; } | |
122 |
NUMBER MINUTES timespec_ { $$ = $1 * 60 + $3; } | |
123 |
NUMBER HOURS timespec_ { $$ = $1 * 60 * 60 + $3; } | |
124 |
NUMBER DAYS timespec_ { $$ = $1 * 60 * 60 * 24 + $3; } | |
125 |
NUMBER WEEKS timespec_ { $$ = $1 * 60 * 60 * 24 * 7 + $3; } | |
126 |
NUMBER MONTHS timespec_ { $$ = $1 * 60 * 60 * 24 * 7 * 4 + $3; } | |
127 |
NUMBER YEARS timespec_ { $$ = $1 * 60 * 60 * 24 * 365 + $3; } |
128 |
; |
129 |
|
130 |
sizespec_: { $$ = 0; } | sizespec; |
131 |
sizespec: NUMBER sizespec_ { $$ = $1 + $2; } | |
132 |
NUMBER BYTES sizespec_ { $$ = $1 + $3; } | |
133 |
NUMBER KBYTES sizespec_ { $$ = $1 * 1024 + $3; } | |
134 |
NUMBER MBYTES sizespec_ { $$ = $1 * 1024 * 1024 + $3; } |
135 |
; |
136 |
|
137 |
|
138 |
/*************************** OPTIONS BLOCK ***********************/ |
139 |
options_entry: OPTIONS '{' options_items '}' ';'; |
140 |
|
141 |
options_items: options_items options_item | |
142 |
options_item; |
143 |
|
144 |
options_item: options_negcache | |
145 |
options_negcache_rebuild | |
146 |
options_pidfile | |
147 |
options_dns_fdlimit | |
148 |
options_dns_timeout | |
149 |
options_scanlog | |
150 |
options_command_queue_size | |
151 |
options_command_interval | |
152 |
options_command_timeout | |
153 |
error; |
154 |
|
155 |
options_negcache: NEGCACHE '=' timespec ';' |
156 |
{ |
157 |
OptionsItem.negcache = $3; |
158 |
}; |
159 |
|
160 |
options_negcache_rebuild: NEGCACHE_REBUILD '=' timespec ';' |
161 |
{ |
162 |
OptionsItem.negcache_rebuild = $3; |
163 |
}; |
164 |
|
165 |
options_pidfile: PIDFILE '=' STRING ';' |
166 |
{ |
167 |
xfree(OptionsItem.pidfile); |
168 |
OptionsItem.pidfile = xstrdup($3); |
169 |
}; |
170 |
|
171 |
options_dns_fdlimit: DNS_FDLIMIT '=' NUMBER ';' |
172 |
{ |
173 |
OptionsItem.dns_fdlimit = $3; |
174 |
}; |
175 |
|
176 |
options_dns_timeout: DNS_TIMEOUT '=' timespec ';' |
177 |
{ |
178 |
OptionsItem.dns_timeout = $3; |
179 |
}; |
180 |
|
181 |
options_scanlog: SCANLOG '=' STRING ';' |
182 |
{ |
183 |
xfree(OptionsItem.scanlog); |
184 |
OptionsItem.scanlog = xstrdup($3); |
185 |
}; |
186 |
|
187 |
options_command_queue_size: COMMAND_QUEUE_SIZE '=' NUMBER ';' |
188 |
{ |
189 |
OptionsItem.command_queue_size = $3; |
190 |
}; |
191 |
|
192 |
options_command_interval: COMMAND_INTERVAL '=' timespec ';' |
193 |
{ |
194 |
OptionsItem.command_interval = $3; |
195 |
}; |
196 |
|
197 |
options_command_timeout: COMMAND_TIMEOUT '=' timespec ';' |
198 |
{ |
199 |
OptionsItem.command_timeout = $3; |
200 |
}; |
201 |
|
202 |
|
203 |
/*************************** IRC BLOCK ***************************/ |
204 |
irc_entry: IRC '{' irc_items '}' ';'; |
205 |
|
206 |
irc_items: irc_items irc_item | |
207 |
irc_item; |
208 |
|
209 |
irc_item: irc_away | |
210 |
irc_connregex | |
211 |
irc_kline | |
212 |
irc_nick | |
213 |
irc_nickserv | |
214 |
irc_mode | |
215 |
irc_oper | |
216 |
irc_password | |
217 |
irc_port | |
218 |
irc_tls | |
219 |
irc_tls_hostname_verification | |
220 |
irc_readtimeout | |
221 |
irc_reconnectinterval | |
222 |
irc_realname | |
223 |
irc_server | |
224 |
irc_username | |
225 |
irc_vhost | |
226 |
irc_perform | |
227 |
irc_notice | |
228 |
channel_entry | |
229 |
error; |
230 |
|
231 |
irc_away: AWAY '=' STRING ';' |
232 |
{ |
233 |
xfree(IRCItem.away); |
234 |
IRCItem.away = xstrdup($3); |
235 |
}; |
236 |
|
237 |
irc_kline: KLINE '=' STRING ';' |
238 |
{ |
239 |
xfree(IRCItem.kline); |
240 |
IRCItem.kline = xstrdup($3); |
241 |
}; |
242 |
|
243 |
irc_mode: MODE '=' STRING ';' |
244 |
{ |
245 |
xfree(IRCItem.mode); |
246 |
IRCItem.mode = xstrdup($3); |
247 |
}; |
248 |
|
249 |
irc_nick: NICK '=' STRING ';' |
250 |
{ |
251 |
xfree(IRCItem.nick); |
252 |
IRCItem.nick = xstrdup($3); |
253 |
}; |
254 |
|
255 |
irc_nickserv: NICKSERV '=' STRING ';' |
256 |
{ |
257 |
xfree(IRCItem.nickserv); |
258 |
IRCItem.nickserv = xstrdup($3); |
259 |
}; |
260 |
|
261 |
irc_oper: OPER '=' STRING ';' |
262 |
{ |
263 |
xfree(IRCItem.oper); |
264 |
IRCItem.oper = xstrdup($3); |
265 |
}; |
266 |
|
267 |
irc_password: PASSWORD '=' STRING ';' |
268 |
{ |
269 |
xfree(IRCItem.password); |
270 |
IRCItem.password = xstrdup($3); |
271 |
}; |
272 |
|
273 |
irc_perform: PERFORM '=' STRING ';' |
274 |
{ |
275 |
list_add(xstrdup($3), node_create(), &IRCItem.performs); |
276 |
}; |
277 |
|
278 |
irc_notice: NOTICE '=' STRING ';' |
279 |
{ |
280 |
list_add(xstrdup($3), node_create(), &IRCItem.notices); |
281 |
}; |
282 |
|
283 |
irc_port: PORT '=' NUMBER ';' |
284 |
{ |
285 |
IRCItem.port = $3; |
286 |
}; |
287 |
|
288 |
irc_tls: TLS '=' NUMBER ';' |
289 |
{ |
290 |
IRCItem.tls = $3; |
291 |
}; |
292 |
|
293 |
irc_tls_hostname_verification: TLS_HOSTNAME_VERIFICATION '=' NUMBER ';' |
294 |
{ |
295 |
IRCItem.tls_hostname_verification = $3; |
296 |
}; |
297 |
|
298 |
irc_readtimeout: READTIMEOUT '=' timespec ';' |
299 |
{ |
300 |
IRCItem.readtimeout = $3; |
301 |
}; |
302 |
|
303 |
irc_reconnectinterval: RECONNECTINTERVAL '=' timespec ';' |
304 |
{ |
305 |
IRCItem.reconnectinterval = $3; |
306 |
}; |
307 |
|
308 |
irc_realname: REALNAME '=' STRING ';' |
309 |
{ |
310 |
xfree(IRCItem.realname); |
311 |
IRCItem.realname = xstrdup($3); |
312 |
}; |
313 |
|
314 |
irc_server: SERVER '=' STRING ';' |
315 |
{ |
316 |
xfree(IRCItem.server); |
317 |
IRCItem.server = xstrdup($3); |
318 |
}; |
319 |
|
320 |
irc_username: USERNAME '=' STRING ';' |
321 |
{ |
322 |
xfree(IRCItem.username); |
323 |
IRCItem.username = xstrdup($3); |
324 |
}; |
325 |
|
326 |
irc_vhost: VHOST '=' STRING ';' |
327 |
{ |
328 |
xfree(IRCItem.vhost); |
329 |
IRCItem.vhost = xstrdup($3); |
330 |
}; |
331 |
|
332 |
irc_connregex: CONNREGEX '=' STRING ';' |
333 |
{ |
334 |
xfree(IRCItem.connregex); |
335 |
IRCItem.connregex = xstrdup($3); |
336 |
}; |
337 |
|
338 |
|
339 |
/************************** CHANNEL BLOCK *************************/ |
340 |
channel_entry: |
341 |
{ |
342 |
struct ChannelConf *item; |
343 |
|
344 |
item = xcalloc(sizeof(*item)); |
345 |
item->name = xstrdup(""); |
346 |
item->key = xstrdup(""); |
347 |
item->invite = xstrdup(""); |
348 |
|
349 |
list_add(item, &item->node, &IRCItem.channels); |
350 |
tmp = item; |
351 |
} |
352 |
CHANNEL '{' channel_items '}' ';'; |
353 |
|
354 |
channel_items: channel_items channel_item | |
355 |
channel_item; |
356 |
|
357 |
channel_item: channel_name | |
358 |
channel_key | |
359 |
channel_invite; |
360 |
|
361 |
channel_name: NAME '=' STRING ';' |
362 |
{ |
363 |
struct ChannelConf *item = tmp; |
364 |
|
365 |
xfree(item->name); |
366 |
item->name = xstrdup($3); |
367 |
}; |
368 |
|
369 |
channel_key: KEY '=' STRING ';' |
370 |
{ |
371 |
struct ChannelConf *item = tmp; |
372 |
|
373 |
xfree(item->key); |
374 |
item->key = xstrdup($3); |
375 |
}; |
376 |
|
377 |
channel_invite: INVITE '=' STRING ';' |
378 |
{ |
379 |
struct ChannelConf *item = tmp; |
380 |
|
381 |
xfree(item->invite); |
382 |
item->invite = xstrdup($3); |
383 |
}; |
384 |
|
385 |
|
386 |
/*************************** USER BLOCK ***************************/ |
387 |
user_entry: |
388 |
{ |
389 |
struct UserConf *item; |
390 |
|
391 |
item = xcalloc(sizeof(*item)); |
392 |
|
393 |
list_add(item, &item->node, &UserItemList); |
394 |
tmp = item; |
395 |
} |
396 |
USER '{' user_items '}' ';' ; |
397 |
|
398 |
user_items: user_items user_item | |
399 |
user_item; |
400 |
|
401 |
user_item: user_mask | |
402 |
user_scanner | |
403 |
error; |
404 |
|
405 |
user_mask: MASK '=' STRING ';' |
406 |
{ |
407 |
struct UserConf *item = tmp; |
408 |
|
409 |
list_add(xstrdup($3), node_create(), &item->masks); |
410 |
}; |
411 |
|
412 |
user_scanner: SCANNER '=' STRING ';' |
413 |
{ |
414 |
struct UserConf *item = tmp; |
415 |
|
416 |
list_add(xstrdup($3), node_create(), &item->scanners); |
417 |
}; |
418 |
|
419 |
|
420 |
/*************************** SCANNER BLOCK ***************************/ |
421 |
scanner_entry: |
422 |
{ |
423 |
struct ScannerConf *item, *olditem; |
424 |
|
425 |
item = xcalloc(sizeof(*item)); |
426 |
|
427 |
/* Setup ScannerConf defaults */ |
428 |
item->name = xstrdup("undefined"); |
429 |
|
430 |
if (LIST_SIZE(&ScannerItemList)) |
431 |
{ |
432 |
olditem = ScannerItemList.tail->data; |
433 |
|
434 |
item->vhost = xstrdup(olditem->vhost); |
435 |
item->fd = olditem->fd; |
436 |
item->target_ip = xstrdup(olditem->target_ip); |
437 |
item->target_port = olditem->target_port; |
438 |
item->timeout = olditem->timeout; |
439 |
item->max_read = olditem->max_read; |
440 |
memcpy(&item->target_string, &olditem->target_string, sizeof(item->target_string)); |
441 |
} |
442 |
else |
443 |
{ |
444 |
item->vhost = xstrdup("0.0.0.0"); |
445 |
item->fd = 512; |
446 |
item->target_ip = xstrdup("127.0.0.1"); |
447 |
item->target_port = 6667; |
448 |
item->timeout = 30; |
449 |
item->max_read = 4096; |
450 |
} |
451 |
|
452 |
list_add(item, &item->node, &ScannerItemList); |
453 |
tmp = item; |
454 |
} |
455 |
SCANNER '{' scanner_items '}' ';' ; |
456 |
|
457 |
scanner_items: scanner_items scanner_item | |
458 |
scanner_item; |
459 |
|
460 |
scanner_item: scanner_name | |
461 |
scanner_vhost | |
462 |
scanner_fd | |
463 |
scanner_target_ip | |
464 |
scanner_target_port | |
465 |
scanner_target_string | |
466 |
scanner_protocol | |
467 |
scanner_timeout | |
468 |
scanner_max_read | |
469 |
error; |
470 |
|
471 |
scanner_name: NAME '=' STRING ';' |
472 |
{ |
473 |
struct ScannerConf *item = tmp; |
474 |
|
475 |
xfree(item->name); |
476 |
item->name = xstrdup($3); |
477 |
}; |
478 |
|
479 |
scanner_vhost: VHOST '=' STRING ';' |
480 |
{ |
481 |
struct ScannerConf *item = tmp; |
482 |
|
483 |
xfree(item->vhost); |
484 |
item->vhost = xstrdup($3); |
485 |
}; |
486 |
|
487 |
scanner_target_ip: TARGET_IP '=' STRING ';' |
488 |
{ |
489 |
struct ScannerConf *item = tmp; |
490 |
|
491 |
xfree(item->target_ip); |
492 |
item->target_ip = xstrdup($3); |
493 |
}; |
494 |
|
495 |
scanner_target_string: TARGET_STRING '=' STRING ';' |
496 |
{ |
497 |
struct ScannerConf *item = tmp; |
498 |
|
499 |
if (item->target_string_created == 0) |
500 |
{ |
501 |
memset(&item->target_string, 0, sizeof(item->target_string)); |
502 |
item->target_string_created = 1; |
503 |
} |
504 |
|
505 |
list_add(xstrdup($3), node_create(), &item->target_string); |
506 |
}; |
507 |
|
508 |
scanner_fd: FD '=' NUMBER ';' |
509 |
{ |
510 |
struct ScannerConf *item = tmp; |
511 |
|
512 |
item->fd = $3; |
513 |
}; |
514 |
|
515 |
scanner_target_port: TARGET_PORT '=' NUMBER ';' |
516 |
{ |
517 |
struct ScannerConf *item = tmp; |
518 |
|
519 |
item->target_port = $3; |
520 |
}; |
521 |
|
522 |
scanner_timeout: TIMEOUT '=' timespec ';' |
523 |
{ |
524 |
struct ScannerConf *item = tmp; |
525 |
|
526 |
item->timeout = $3; |
527 |
}; |
528 |
|
529 |
scanner_max_read: MAX_READ '=' sizespec ';' |
530 |
{ |
531 |
struct ScannerConf *item = tmp; |
532 |
|
533 |
item->max_read = $3; |
534 |
}; |
535 |
|
536 |
scanner_protocol: PROTOCOL '=' PROTOCOLTYPE ':' NUMBER ';' |
537 |
{ |
538 |
struct ProtocolConf *item; |
539 |
struct ScannerConf *item2; |
540 |
|
541 |
item = xcalloc(sizeof(*item)); |
542 |
item->type = $3; |
543 |
item->port = $5; |
544 |
|
545 |
item2 = tmp; |
546 |
|
547 |
list_add(item, node_create(), &item2->protocols); |
548 |
}; |
549 |
|
550 |
|
551 |
/*************************** OPM BLOCK ***************************/ |
552 |
opm_entry: OPM '{' opm_items '}' ';' ; |
553 |
|
554 |
opm_items: opm_items opm_item | |
555 |
opm_item; |
556 |
|
557 |
opm_item: opm_dnsbl_from | |
558 |
opm_dnsbl_to | |
559 |
opm_sendmail | |
560 |
opm_blacklist_entry | |
561 |
error; |
562 |
|
563 |
opm_dnsbl_from: DNSBL_FROM '=' STRING ';' |
564 |
{ |
565 |
xfree(OpmItem.dnsbl_from); |
566 |
OpmItem.dnsbl_from = xstrdup($3); |
567 |
}; |
568 |
|
569 |
opm_dnsbl_to: DNSBL_TO '=' STRING ';' |
570 |
{ |
571 |
xfree(OpmItem.dnsbl_to); |
572 |
OpmItem.dnsbl_to = xstrdup($3); |
573 |
}; |
574 |
|
575 |
opm_sendmail: SENDMAIL '=' STRING ';' |
576 |
{ |
577 |
xfree(OpmItem.sendmail); |
578 |
OpmItem.sendmail = xstrdup($3); |
579 |
}; |
580 |
|
581 |
|
582 |
/************************** BLACKLIST BLOCK *************************/ |
583 |
opm_blacklist_entry: |
584 |
{ |
585 |
struct BlacklistConf *item; |
586 |
|
587 |
item = xcalloc(sizeof(*item)); |
588 |
item->name = xstrdup(""); |
589 |
item->kline = xstrdup(""); |
590 |
item->ipv4 = 1; |
591 |
item->ban_unknown = 0; |
592 |
item->type = A_BITMASK; |
593 |
|
594 |
list_add(item, node_create(), &OpmItem.blacklists); |
595 |
|
596 |
tmp = item; |
597 |
} |
598 |
BLACKLIST '{' blacklist_items '}' ';'; |
599 |
|
600 |
blacklist_items: blacklist_items blacklist_item | |
601 |
blacklist_item; |
602 |
|
603 |
blacklist_item: blacklist_name | |
604 |
blacklist_address_family | |
605 |
blacklist_type | |
606 |
blacklist_kline | |
607 |
blacklist_ban_unknown | |
608 |
blacklist_reply | |
609 |
error; |
610 |
|
611 |
blacklist_name: NAME '=' STRING ';' |
612 |
{ |
613 |
struct BlacklistConf *item = tmp; |
614 |
|
615 |
xfree(item->name); |
616 |
item->name = xstrdup($3); |
617 |
}; |
618 |
|
619 |
blacklist_address_family: ADDRESS_FAMILY |
620 |
{ |
621 |
struct BlacklistConf *item = tmp; |
622 |
|
623 |
item->ipv4 = 0; |
624 |
item->ipv6 = 0; |
625 |
} '=' blacklist_address_family_items ';' ; |
626 |
|
627 |
blacklist_address_family_items: blacklist_address_family_items ',' blacklist_address_family_item | blacklist_address_family_item; |
628 |
blacklist_address_family_item: IPV4 |
629 |
{ |
630 |
struct BlacklistConf *item = tmp; |
631 |
|
632 |
item->ipv4 = 1; |
633 |
} | IPV6 |
634 |
{ |
635 |
struct BlacklistConf *item = tmp; |
636 |
|
637 |
item->ipv6 = 1; |
638 |
}; |
639 |
|
640 |
blacklist_kline: KLINE '=' STRING ';' |
641 |
{ |
642 |
struct BlacklistConf *item = tmp; |
643 |
|
644 |
xfree(item->kline); |
645 |
item->kline = xstrdup($3); |
646 |
}; |
647 |
|
648 |
blacklist_type: TYPE '=' STRING ';' |
649 |
{ |
650 |
struct BlacklistConf *item = tmp; |
651 |
|
652 |
if (strcmp("A record bitmask", $3) == 0) |
653 |
item->type = A_BITMASK; |
654 |
else if (strcmp("A record reply", $3) == 0) |
655 |
item->type = A_REPLY; |
656 |
else |
657 |
yyerror("Unknown blacklist type defined"); |
658 |
}; |
659 |
|
660 |
blacklist_ban_unknown: BAN_UNKNOWN '=' NUMBER ';' |
661 |
{ |
662 |
struct BlacklistConf *item = tmp; |
663 |
|
664 |
item->ban_unknown = $3; |
665 |
}; |
666 |
|
667 |
blacklist_reply: REPLY '{' blacklist_reply_items '}' ';'; |
668 |
|
669 |
blacklist_reply_items: blacklist_reply_items blacklist_reply_item | |
670 |
blacklist_reply_item; |
671 |
|
672 |
blacklist_reply_item: NUMBER '=' STRING ';' |
673 |
{ |
674 |
struct BlacklistReplyConf *item; |
675 |
struct BlacklistConf *blacklist = tmp; |
676 |
|
677 |
item = xcalloc(sizeof(*item)); |
678 |
item->number = $1; |
679 |
item->type = xstrdup($3); |
680 |
|
681 |
list_add(item, node_create(), &blacklist->reply); |
682 |
}; |
683 |
|
684 |
|
685 |
/*************************** EXEMPT BLOCK ***************************/ |
686 |
exempt_entry: EXEMPT '{' exempt_items '}' ';' ; |
687 |
|
688 |
exempt_items: exempt_items exempt_item | |
689 |
exempt_item; |
690 |
|
691 |
exempt_item: exempt_mask | |
692 |
error; |
693 |
|
694 |
exempt_mask: MASK '=' STRING ';' |
695 |
{ |
696 |
list_add(xstrdup($3), node_create(), &ExemptItem.masks); |
697 |
}; |
698 |
|
699 |
%% |