1# -*- indent-tabs-mode: nil; -*-
2# vim:ft=perl:et:sw=4
3
4# Sympa - SYsteme de Multi-Postage Automatique
5#
6# Copyright 2020, 2021 The Sympa Community. See the
7# AUTHORS.md file at the top-level directory of this distribution and at
8# <https://github.com/sympa-community/sympa.git>.
9#
10# This program is free software; you can redistribute it and/or modify
11# it under the terms of the GNU General Public License as published by
12# the Free Software Foundation; either version 2 of the License, or
13# (at your option) any later version.
14#
15# This program is distributed in the hope that it will be useful,
16# but WITHOUT ANY WARRANTY; without even the implied warranty of
17# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18# GNU General Public License for more details.
19#
20# You should have received a copy of the GNU General Public License
21# along with this program.  If not, see <http://www.gnu.org/licenses/>.
22
23package Sympa::Config::Schema;
24
25use strict;
26use warnings;
27
28use Sympa::Constants;
29use Sympa::Regexps;
30
31# Parameter defaults
32my %default = (
33    occurrence => '0-1',
34    length     => 25
35);
36
37# DEPRECATED. No longer used.
38#our @param_order;
39
40# List parameter alias names
41# DEPRECATED.  Use 'obsolete' elements.
42#our %alias;
43
44our %pgroup = (
45    presentation => {
46        order           => 1,
47        gettext_id      => 'Service description',
48        gettext_comment => '',
49    },
50    database => {
51        order           => 2,
52        gettext_id      => 'Database related',
53        gettext_comment => '',
54    },
55    logging => {
56        order           => 3,
57        gettext_id      => 'System log',
58        gettext_comment => '',
59    },
60    mta => {
61        order => 4,
62        #gettext_id      => 'Alias management',
63        gettext_id      => 'Mail server',
64        gettext_comment => '',
65    },
66    description => {
67        order           => 10,
68        gettext_id      => 'List definition',
69        gettext_comment => '',
70    },
71    incoming => {
72        order           => 19,
73        gettext_id      => 'Receiving',
74        gettext_comment => '',
75    },
76    sending => {
77        order => 20,
78        #gettext_id      => 'Sending related',
79        gettext_id      => 'Sending/receiving setup',
80        gettext_comment => '',
81    },
82    outgoing => {
83        order           => 21,
84        gettext_id      => 'Distribution',
85        gettext_comment => '',
86    },
87    command => {
88        order           => 30,
89        gettext_id      => 'Privileges',
90        gettext_comment => '',
91    },
92    archives => {
93        order           => 40,
94        gettext_id      => 'Archives',
95        gettext_comment => '',
96    },
97    bounces => {
98        order => 50,
99        #gettext_id      => 'Bounce management and tracking',
100        gettext_id      => 'Bounces',
101        gettext_comment => '',
102    },
103
104    loop_prevention => {
105        order           => 51,
106        gettext_id      => 'Loop prevention',
107        gettext_comment => '',
108    },
109    automatic_lists => {
110        order           => 52,
111        gettext_id      => 'Automatic lists',
112        gettext_comment => '',
113    },
114    antispam => {
115        order           => 53,
116        gettext_id      => 'Tag based spam filtering',
117        gettext_comment => '',
118    },
119    directories => {
120        order           => 54,
121        gettext_id      => 'Directories',
122        gettext_comment => '',
123    },
124    other => {
125        order           => 90,
126        gettext_id      => 'Miscellaneous',
127        gettext_comment => '',
128    },
129
130    www_basic => {
131        order           => 110,
132        gettext_id      => 'Web interface parameters',
133        gettext_comment => '',
134    },
135    www_appearances => {
136        order           => 120,
137        gettext_id      => 'Web interface parameters: Appearances',
138        gettext_comment => '',
139    },
140    www_other => {
141        order           => 190,
142        gettext_id      => 'Web interface parameters: Miscellaneous',
143        gettext_comment => '',
144    },
145
146    crypto => {
147        order      => 59,
148        gettext_id => 'S/MIME and TLS',
149        gettext_comment =>
150            "S/MIME authentication, decryption and re-encryption. It requires these external modules: Crypt-OpenSSL-X509 and Crypt-SMIME.\nTLS client authentication. It requires an external module: IO-Socket-SSL.",
151    },
152    data_source => {
153        order      => 60,
154        gettext_id => 'Data sources setup',
155        gettext_comment =>
156            'Including subscribers, owners and moderators from data sources. Appropriate database driver (DBD) modules are required: DBD-CSV, DBD-mysql, DBD-ODBC, DBD-Oracle, DBD-Pg, DBD-SQLite and/or Net-LDAP. And also, if secure connection (LDAPS) to LDAP server is required: IO-Socket-SSL.',
157    },
158    dkim => {
159        order => 70,
160        #gettext_id => 'DKIM and ARC',
161        gettext_id => 'DKIM/DMARC/ARC',
162        gettext_comment =>
163            "DKIM signature verification and re-signing. It requires an external module: Mail-DKIM.\nARC seals on forwarded messages. It requires an external module: Mail-DKIM.",
164    },
165    dmarc_protection => {    #FIXME: Not used?
166        order      => 71,
167        gettext_id => 'DMARC protection',
168        gettext_comment =>
169            'Processes originator addresses to avoid some domains\' excessive DMARC protection. This feature requires an external module: Net-DNS.',
170    },
171
172    list_check => {
173        order      => 72,
174        gettext_id => 'List address verification',
175        gettext_comment =>
176            'Checks if an alias with the same name as the list to be created already exists on the SMTP server. This feature requires an external module: Net-SMTP.',
177    },
178    antivirus => {
179        order           => 73,
180        gettext_id      => 'Antivirus plug-in',
181        gettext_comment => '',
182    },
183
184    password_validation => {
185        order      => 153,
186        gettext_id => 'Password validation',
187        gettext_comment =>
188            'Checks if the password the user submitted has sufficient strength. This feature requires an external module: Data-Password.',
189    },
190    ldap_auth => {
191        order      => 154,
192        gettext_id => 'Authentication with LDAP',
193        gettext_comment =>
194            'Authenticates users based on the directory on LDAP server. This feature requires an external module: Net-LDAP. And also, if secure connection (LDAPS) is required: IO-Socket-SSL.',
195    },
196    sympasoap => {
197        order      => 156,
198        gettext_id => 'SOAP HTTP interface',
199        gettext_comment =>
200            'Provides some functions of Sympa through the SOAP HTTP interface. This feature requires an external module: SOAP-Lite.',
201    },
202
203    _obsoleted => {
204        order           => 99999,
205        gettext_id      => 'Obsoleted parameters',
206        gettext_comment => '',
207    },
208);
209
210my $site_obsolete =
211    {context => [qw(site)], group => '_obsoleted', obsolete => 1};
212
213our %pinfo = (
214
215    # Initial configuration
216
217    domain => {
218        context => [qw(domain site)],    #FIXME:not used in robot.conf.
219        order   => 1.01,
220        group   => 'presentation',
221        gettext_id => 'Primary mail domain name',
222        format     => '[-\w]+(?:[.][-\w]+)+',
223        sample     => 'mail.example.org',
224        occurrence => '1',
225    },
226    listmaster => {
227        context    => [qw(domain site)],
228        order      => 1.02,
229        group      => 'presentation',
230        sample     => 'your_email_address@domain.tld',
231        gettext_id => 'Email addresses of listmasters',
232        split_char => ',',                                #FIXME
233        gettext_comment =>
234            'Email addresses of the listmasters (users authorized to perform global server commands). Some error reports may also be sent to these addresses. Listmasters can be defined for each virtual host, however, the default listmasters will have privileges to manage all virtual hosts.',
235        format_s   => '$addrspec',
236        occurrence => '1-n',
237    },
238
239    ### Global definition page ###
240
241    supported_lang => {
242        context => [qw(domain site)],
243        order   => 1.10,
244        group   => 'presentation',
245        default =>
246            'ca,cs,de,el,en-US,es,et,eu,fi,fr,gl,hu,it,ja,ko,nb,nl,oc,pl,pt-BR,ru,sv,tr,vi,zh-CN,zh-TW',
247        gettext_id => 'Supported languages',
248        split_char => ',',
249        gettext_comment =>
250            'All supported languages for the user interface. Languages proper locale information not installed are ignored.',
251        format => '\w+(\-\w+)*',
252    },
253    title => {
254        context    => [qw(domain site)],
255        order      => 1.11,
256        group      => 'presentation',
257        default    => 'Mailing lists service',
258        gettext_id => 'Title of service',
259        gettext_comment =>
260            'The name of your mailing list service. It will appear in the header of web interface and subjects of several service messages.',
261        format => '.+',
262        file   => 'wwsympa.conf',
263    },
264    gecos => {
265        context    => [qw(domain site)],
266        order      => 1.12,
267        group      => 'presentation',
268        default    => 'SYMPA',
269        gettext_id => 'Display name of Sympa',
270        gettext_comment =>
271            'This parameter is used for display name in the "From:" header field for the messages sent by Sympa itself.',
272        format => '.+',
273    },
274    legacy_character_support_feature => {
275        context    => [qw(site)],
276        order      => 1.13,
277        group      => 'presentation',
278        default    => 'off',
279        gettext_id => 'Support of legacy character set',
280        gettext_comment =>
281            "If set to \"on\", enables support of legacy character set according to charset.conf(5) configuration file.\nIn some language environments, legacy encoding (character set) can be preferred for e-mail messages: for example iso-2022-jp in Japanese language.",
282        format => ['on', 'off'],    #XXX
283    },
284
285    # Database
286
287    update_db_field_types => {
288        context    => [qw(site)],
289        order      => 2.01,
290        group      => 'database',
291        gettext_id => 'Update database structure',
292        gettext_comment =>
293            "auto: Updates database table structures automatically.\nHowever, since version 5.3b.5, Sympa will not shorten field size if it already have been longer than the size defined in database definition.",
294        format  => ['auto', 'off'],
295        default => 'auto',
296    },
297    db_type => {
298        context    => [qw(site)],
299        order      => 2.10,
300        group      => 'database',
301        default    => 'mysql',
302        gettext_id => 'Type of the database',
303        gettext_comment =>
304            'Possible types are "MySQL", "PostgreSQL", "Oracle" and "SQLite".',
305        format     => '\w+',
306        occurrence => '1',
307    },
308    db_host => {
309        context => [qw(site)],
310        order   => 2.11,
311        group   => 'database',
312        #default => 'localhost',
313        sample     => 'localhost',
314        gettext_id => 'Hostname of the database server',
315        gettext_comment =>
316            'With PostgreSQL, you can also use the path to Unix Socket Directory, e.g. "/var/run/postgresql" for connection with Unix domain socket.',
317        format_s => '$host',
318    },
319    db_port => {
320        context    => [qw(site)],
321        order      => 2.12,
322        group      => 'database',
323        gettext_id => 'Port of the database server',
324        format     => '[-/\w]+',
325    },
326    db_name => {
327        context    => [qw(site)],
328        order      => 2.13,
329        group      => 'database',
330        default    => 'sympa',
331        gettext_id => 'Name of the database',
332        gettext_comment =>
333            "With SQLite, this must be the full path to database file.\nWith Oracle Database, this must be SID, net service name or easy connection identifier (to use net service name, db_host should be set to \"none\" and HOST, PORT and SERVICE_NAME should be defined in tnsnames.ora file).",
334        format => '.+',
335    },
336    db_user => {
337        context => [qw(site)],
338        order   => 2.14,
339        group   => 'database',
340        #default => 'user_name',
341        sample     => 'sympa',
342        gettext_id => 'User for the database connection',
343        format     => '.+',
344    },
345    db_passwd => {
346        context => [qw(site)],
347        order   => 2.15,
348        group   => 'database',
349        #default => 'user_password',
350        sample     => 'your_passwd',
351        gettext_id => 'Password for the database connection',
352        field_type => 'password',
353        gettext_comment =>
354            'What ever you use a password or not, you must protect the SQL server (is it not a public internet service ?)',
355        format => '.+',
356    },
357    db_options => {
358        context    => [qw(site)],
359        order      => 2.16,
360        group      => 'database',
361        gettext_id => 'Database options',
362        gettext_comment =>
363            'If these options are defined, they will be appended to data source name (DSN) fed to database driver. Check the related DBD documentation to learn about the available options.',
364        format => '.+',
365        sample =>
366            'mysql_read_default_file=/home/joe/my.cnf;mysql_socket=tmp/mysql.sock-test',
367    },
368    db_env => {
369        context    => [qw(site)],
370        order      => 2.17,
371        group      => 'database',
372        gettext_id => 'Environment variables setting for database',
373        gettext_comment =>
374            'With Oracle Database, this is useful for defining ORACLE_HOME and NLS_LANG.',
375        format => '.+',
376        sample =>
377            'NLS_LANG=American_America.AL32UTF8;ORACLE_HOME=/u01/app/oracle/product/11.2.0/server',
378    },
379    db_timeout => {
380        context    => [qw(site)],
381        order      => 2.18,
382        group      => 'database',
383        gettext_id => 'Database processing timeout',
384        gettext_comment =>
385            'Currently, this parameter may be used for SQLite only.',
386        format => '\d+',
387    },
388    db_additional_subscriber_fields => {
389        context    => [qw(site)],
390        order      => 2.20,
391        group      => 'database',
392        sample     => 'billing_delay,subscription_expiration',
393        gettext_id => 'Database private extension to subscriber table',
394        split_char => ',',                                              #FIXME
395        gettext_comment =>
396            "Adds more fields to \"subscriber_table\" table. Sympa recognizes fields defined with this parameter. You will then be able to use them from within templates and scenarios:\n* for scenarios: [subscriber->field]\n* for templates: [% subscriber.field %]\nThese fields will also appear in the list members review page and will be editable by the list owner. This parameter is a comma-separated list.\nYou need to extend the database format with these fields",
397        format     => '.+',
398        occurrence => '0-n',
399    },
400    db_additional_user_fields => {
401        context    => [qw(site)],
402        order      => 2.21,
403        group      => 'database',
404        sample     => 'age,address',
405        gettext_id => 'Database private extension to user table',
406        split_char => ',',                                              #FIXME
407        gettext_comment =>
408            "Adds more fields to \"user_table\" table. Sympa recognizes fields defined with this parameter. You will then be able to use them from within templates: [% subscriber.field %]\nThis parameter is a comma-separated list.\nYou need to extend the database format with these fields",
409        format     => '.+',
410        occurrence => '0-n',
411    },
412
413    ### System log
414
415    syslog => {
416        context         => [qw(site)],
417        order           => 3.01,
418        group           => 'logging',
419        default         => 'LOCAL1',
420        gettext_id      => 'System log facility for Sympa',
421        gettext_comment => 'Do not forget to configure syslog server.',
422        format          => '\S+',
423    },
424    log_socket_type => {
425        context    => [qw(site)],
426        order      => 3.02,
427        group      => 'logging',
428        default    => 'unix',
429        gettext_id => 'Communication mode with syslog server',
430        format     => '\w+',
431    },
432    log_level => {
433        context    => [qw(domain site)],    #FIXME "domain" possible?
434        order      => 3.03,
435        group      => 'logging',
436        default    => '0',
437        sample     => '2',
438        gettext_id => 'Log verbosity',
439        gettext_comment =>
440            "Sets the verbosity of logs.\n0: Only main operations are logged\n3: Almost everything is logged.",
441        format => '\d+',
442    },
443
444    ### Maili server (alias management & passing to the next hop)
445
446    sendmail => {
447        context    => [qw(site)],
448        order      => 4.01,
449        group      => 'mta',
450        default    => '/usr/sbin/sendmail',
451        gettext_id => 'Path to sendmail',
452        gettext_comment =>
453            "Absolute path to sendmail command line utility (e.g.: a binary named \"sendmail\" is distributed with Postfix).\nSympa expects this binary to be sendmail compatible (exim, Postfix, qmail and so on provide it).",
454        format => '.+',
455    },
456    sendmail_args => {
457        context    => [qw(site)],
458        order      => 4.02,
459        group      => 'mta',
460        default    => '-oi -odi -oem',
461        gettext_id => 'Command line parameters passed to sendmail',
462        gettext_comment =>
463            "Note that \"-f\", \"-N\" and \"-V\" options and recipient addresses should not be included, because they will be included by Sympa.",
464        format => '.+',
465    },
466
467    sendmail_aliases => {
468        context   => [qw(domain site)],
469        order     => 4.03,
470        group     => 'mta',
471        default_s => '$SENDMAIL_ALIASES',
472        gettext_id =>
473            'Path of the file that contains all list related aliases',
474        gettext_comment =>
475            "It is recommended to create a specific alias file so that Sympa never overwrites the standard alias file, but only a dedicated file.\nSet this parameter to \"none\" if you want to disable alias management in Sympa.",
476        format => '.+',
477    },
478    aliases_program => {
479        context    => [qw(domain site)],
480        order      => 4.04,
481        group      => 'mta',
482        format     => 'makemap|newaliases|postalias|postmap|/.+|none',
483        default    => 'newaliases',
484        gettext_id => 'Program used to update alias database',
485        gettext_comment =>
486            'This may be "makemap", "newaliases", "postalias", "postmap" or full path to custom program.',
487        # Option "none" was added on 6.2.61b
488    },
489    aliases_wrapper => {
490        context    => [qw(domain site)],
491        order      => 4.045,
492        group      => 'mta',
493        format     => ['off', 'on'],
494        synonym    => {'0' => 'off', '1' => 'on'},
495        default    => 'on',
496        gettext_id => 'Whether to use the alias wrapper',
497        gettext_comment =>
498            'If the program to update alias database does not require root privileges, set this parameter to "off" and remove the wrapper file sympa_newaliases-wrapper.',
499    },
500    aliases_db_type => {
501        context    => [qw(domain site)],
502        order      => 4.05,
503        group      => 'mta',
504        format     => '\w[-\w]*',
505        default    => 'hash',
506        gettext_id => 'Type of alias database',
507        gettext_comment =>
508            '"btree", "dbm", "hash" and so on.  Available when aliases_program is "makemap", "postalias" or "postmap"',
509    },
510    alias_manager => {
511        context    => [qw(site)],
512        order      => 4.06,
513        group      => 'mta',
514        gettext_id => 'Path to alias manager',
515        gettext_comment =>
516            'The absolute path to the script that will add/remove mail aliases',
517        format => '.+',
518
519        default_s => '$SBINDIR/alias_manager.pl',
520        sample    => '/usr/local/libexec/ldap_alias_manager.pl',
521    },
522
523    ### List definition page ###
524
525    subject => {
526        context    => [qw(list)],
527        order      => 10.01,
528        group      => 'description',
529        gettext_id => "Subject of the list",
530        gettext_comment =>
531            'This parameter indicates the subject of the list, which is sent in response to the LISTS mail command. The subject is a free form text limited to one line.',
532        format     => '.+',
533        occurrence => '1',
534        length     => 50
535    },
536
537    visibility => {
538        context    => [qw(list domain site)],
539        order      => 10.02,
540        group      => 'description',
541        gettext_id => "Visibility of the list",
542        gettext_comment =>
543            'This parameter indicates whether the list should feature in the output generated in response to a LISTS command or should be shown in the list overview of the web-interface.',
544        scenario => 'visibility',
545        synonym  => {
546            'public'  => 'noconceal',
547            'private' => 'conceal'
548        },
549        default => 'conceal',
550    },
551
552    owner => {
553        context  => [qw(list)],
554        obsolete => 1,
555        format   => {
556            email => {
557                context  => [qw(list)],
558                obsolete => 1,
559                format_s => '$email',
560            },
561            gecos => {
562                context  => [qw(list)],
563                obsolete => 1,
564                format   => '.+',
565            },
566            info => {
567                context  => [qw(list)],
568                obsolete => 1,
569                format   => '.+',
570            },
571            profile => {
572                context  => [qw(list)],
573                obsolete => 1,
574                format   => ['privileged', 'normal'],
575            },
576            reception => {
577                context  => [qw(list)],
578                obsolete => 1,
579                format   => ['mail', 'nomail'],
580            },
581            visibility => {
582                context  => [qw(list)],
583                obsolete => 1,
584                format   => ['conceal', 'noconceal'],
585            }
586        },
587        occurrence => '1-n'
588    },
589
590    editor => {
591        context  => [qw(list)],
592        obsolete => 1,
593        format   => {
594            email => {
595                context  => [qw(list)],
596                obsolete => 1,
597                format_s => '$email',
598            },
599            reception => {
600                context  => [qw(list)],
601                obsolete => 1,
602                format   => ['mail', 'nomail'],
603            },
604            visibility => {
605                context  => [qw(list)],
606                obsolete => 1,
607                format   => ['conceal', 'noconceal'],
608            },
609            gecos => {
610                context  => [qw(list)],
611                obsolete => 1,
612                format   => '.+',
613            },
614            info => {
615                context  => [qw(list)],
616                obsolete => 1,
617                format   => '.+',
618            }
619        },
620        occurrence => '0-n'
621    },
622
623    topics => {
624        context    => [qw(list)],
625        order      => 10.07,
626        group      => 'description',
627        gettext_id => "Topics for the list",
628        gettext_comment =>
629            "This parameter allows the classification of lists. You may define multiple topics as well as hierarchical ones. WWSympa's list of public lists uses this parameter.",
630        format     => [],            # Sympa::Robot::topic_keys() called later
631        field_type => 'listtopic',
632        split_char => ',',
633        occurrence => '0-n',
634        filters    => ['lc'],
635    },
636
637    host => {
638        context    => [qw(list domain site)],
639        order      => 10.08,
640        group      => 'description',
641        gettext_id => "Internet domain",
642        gettext_comment =>
643            'Domain name of the list, default is the robot domain name set in the related robot.conf file or in file sympa.conf.',
644        format_s => '$host',
645        filters  => ['canonic_domain'],
646        length   => 20,
647        obsolete => 1
648    },
649
650    lang => {
651        context    => [qw(list domain site)],
652        order      => 10.09,
653        group      => 'description',
654        gettext_id => "Language of the list",
655        #gettext_id => 'Default language',
656        gettext_comment =>
657            "This parameter defines the language used for the list. It is used to initialize a user's language preference; Sympa command reports are extracted from the associated message catalog.",
658        #gettext_comment =>
659        #    'This is the default language used by Sympa. One of supported languages should be chosen.',
660        format => [],    ## Sympa::get_supported_languages() called later
661        file_format => '\w+(\-\w+)*',
662        field_type  => 'lang',
663        occurrence  => '1',
664        filters     => ['canonic_lang'],
665        default     => 'en-US',
666    },
667
668    family_name => {
669        context    => [qw(list)],
670        order      => 10.10,
671        group      => 'description',
672        gettext_id => 'Family name',
673        format_s   => '$family_name',
674        occurrence => '0-1',
675        internal   => 1
676    },
677
678    max_list_members => {
679        context    => [qw(list domain site)],
680        order      => 10.11,
681        group      => 'description',                     # incoming / sending?
682        gettext_id => "Maximum number of list members",
683        gettext_comment =>
684            'limit for the number of subscribers. 0 means no limit.',
685        gettext_unit => 'list members',
686        format       => '\d+',
687        length       => 8,
688        default      => '0',
689    },
690
691    # Incoming
692    # - Approximately corresponds to ProcessIncoming and DoMessage spindles.
693    # - Does _not_ contain the parameters with List context.
694
695    sender_headers => {
696        context => [qw(site)],
697        order   => 19.00_02,
698        group   => 'incoming',
699        default => 'From',
700        sample  => 'Resent-From,From,Return-Path',
701        gettext_id =>
702            'Header field name(s) used to determine sender of the messages',
703        gettext_comment =>
704            '"Return-Path" means envelope sender (a.k.a. "UNIX From") which will be alternative to sender of messages without "From" field.  "Resent-From" may also be inserted before "From", because some mailers add it into redirected messages and keep original "From" field intact.  In particular cases, "Return-Path" can not give right sender: Several mail gateway products rewrite envelope sender and add original one as non-standard field such as "X-Envelope-From".  If that is the case, you might want to insert it in place of "Return-Path".',
705        split_char => ',',
706    },
707
708    misaddressed_commands => {
709        context    => [qw(site)],
710        order      => 19.00_03,
711        group      => 'incoming',
712        gettext_id => 'Reject misaddressed commands',
713        gettext_comment =>
714            'When a mail command is sent to a list, by default Sympa rejects this message. This feature can be turned off by setting this parameter to "ignore".',
715        default => 'reject',
716    },
717    misaddressed_commands_regexp => {
718        context => [qw(site)],
719        order   => 19.00_04,
720        group   => 'incoming',
721        gettext_id =>
722            'Regular expression matching with misaddressed commands',
723        gettext_comment =>
724            'Perl regular expression applied on messages subject and body to detect misaddressed commands.',
725        default =>
726            '((subscribe\s+(\S+)|unsubscribe\s+(\S+)|signoff\s+(\S+)|set\s+(\S+)\s+(mail|nomail|digest))\s*)',
727    },
728    sympa_priority => {
729        context    => [qw(domain site)],
730        order      => 19.00_05,
731        group      => 'incoming',
732        gettext_id => 'Priority for command messages',
733        gettext_comment =>
734            'Priority applied to messages sent to Sympa command address.',
735        format  => [0 .. 9, 'z'],
736        default => '1',
737    },
738    request_priority => {
739        context    => [qw(domain site)],
740        order      => 19.00_06,
741        group      => 'incoming',
742        gettext_id => 'Priority for messages bound for list owners',
743        gettext_comment =>
744            'Priority for processing of messages bound for "LIST-request" address, i.e. owners of the list',
745        format  => [0 .. 9, 'z'],
746        default => '0',
747    },
748    owner_priority => {
749        context    => [qw(domain site)],
750        order      => 19.00_07,
751        group      => 'incoming',
752        gettext_id => 'Priority for non-VERP bounces',
753        gettext_comment =>
754            'Priority for processing of messages bound for "LIST-owner" address, i.e. non-delivery reports (bounces).',
755        format  => [0 .. 9, 'z'],
756        default => '9',
757    },
758
759    priority => {
760        context    => [qw(list domain site)],
761        order      => 10.12,
762        group      => 'description',            # incoming / sending?
763        gettext_id => "Priority",
764        gettext_comment =>
765            'The priority with which Sympa will process messages for this list. This level of priority is applied while the message is going through the spool. The z priority will freeze the message in the spool.',
766        #gettext_comment =>
767        #    'Priority for processing of messages posted to list addresses.',
768        format     => [0 .. 9, 'z'],
769        length     => 1,
770        occurrence => '1',
771        default    => '5',
772    },
773
774    incoming_max_count => {
775        context    => [qw(site)],
776        order      => 19.00_10,
777        group      => 'incoming',
778        default    => '1',
779        gettext_id => 'Max number of sympa.pl workers',
780        gettext_comment =>
781            'Max number of workers of sympa.pl daemon processing incoming spool.',
782        format => '\d+',
783    },
784
785    sleep => {
786        context         => [qw(site)],
787        order           => 19.00_11,
788        group           => 'incoming',
789        default         => '5',
790        gettext_id      => 'Interval between scanning incoming message spool',
791        gettext_comment => 'Must not be 0.',
792        format          => '\d+',
793        gettext_unit    => 'seconds',
794    },
795
796    ### Sending page ###
797    # - Approximately corresponds to AuthorizeMessage, Transform*, ToArchive,
798    #   ToDigest and ToList spindles.
799    # - Contains the parameters with List context.
800
801    send => {
802        context    => [qw(list domain site)],
803        order      => 20.01,
804        group      => 'sending',
805        gettext_id => "Who can send messages",
806        gettext_comment =>
807            'This parameter specifies who can send messages to the list.',
808        scenario => 'send',
809        default  => 'private',
810    },
811
812    delivery_time => {
813        context    => [qw(list)],
814        order      => 20.02,
815        group      => 'sending',
816        gettext_id => "Delivery time (hh:mm)",
817        gettext_comment =>
818            'If this parameter is present, non-digest messages will be delivered to subscribers at this time: When this time has been past, delivery is postponed to the same time in next day.',
819        format     => '[0-2]?\d\:[0-6]\d',
820        occurrence => '0-1',
821        length     => 5
822    },
823
824    digest => {
825        context    => [qw(list)],
826        order      => 20.03,
827        group      => 'sending',
828        gettext_id => "Digest frequency",
829        gettext_comment =>
830            'Definition of digest mode. If this parameter is present, subscribers can select the option of receiving messages in multipart/digest MIME format, or as a plain text digest. Messages are then grouped together, and compiled messages are sent to subscribers according to the frequency selected with this parameter.',
831        file_format => '\d+(\s*,\s*\d+)*\s+\d+:\d+',
832        format      => {
833            days => {
834                context     => [qw(list)],
835                order       => 1,
836                gettext_id  => "days",
837                format      => [0 .. 6],
838                file_format => '1|2|3|4|5|6|7',
839                field_type  => 'dayofweek',
840                occurrence  => '1-n'
841            },
842            hour => {
843                context    => [qw(list)],
844                order      => 2,
845                gettext_id => "hour",
846                format     => '\d+',
847                occurrence => '1',
848                length     => 2
849            },
850            minute => {
851                context    => [qw(list)],
852                order      => 3,
853                gettext_id => "minute",
854                format     => '\d+',
855                occurrence => '1',
856                length     => 2
857            }
858        },
859    },
860
861    digest_max_size => {
862        context      => [qw(list)],
863        order        => 20.04,
864        group        => 'sending',
865        gettext_id   => "Digest maximum number of messages",
866        gettext_unit => 'messages',
867        format       => '\d+',
868        default      => 25,
869        length       => 2
870    },
871
872    available_user_options => {
873        context    => [qw(list)],
874        order      => 20.05,
875        group      => 'sending',
876        gettext_id => "Available subscription options",
877        format     => {
878            reception => {
879                context    => [qw(list)],
880                order      => 1,
881                gettext_id => "reception mode",
882                gettext_comment =>
883                    'Only these modes will be allowed for the subscribers of this list. If a subscriber has a reception mode not in the list, Sympa uses the mode specified in the default_user_options paragraph.',
884                format => [
885                    'mail',    'notice', 'digest', 'digestplain',
886                    'summary', 'nomail', 'txt',    'urlize',
887                    'not_me'
888                ],
889                synonym    => {'html' => 'mail'},
890                field_type => 'reception',
891                occurrence => '1-n',
892                split_char => ',',
893                default =>
894                    'mail,notice,digest,digestplain,summary,nomail,txt,urlize,not_me'
895            }
896        }
897    },
898
899    default_user_options => {
900        context         => [qw(list)],
901        order           => 20.06,
902        group           => 'sending',
903        gettext_id      => "Subscription profile",
904        gettext_comment => 'Default profile for the subscribers of the list.',
905        format          => {
906            reception => {
907                context         => [qw(list)],
908                order           => 1,
909                gettext_id      => "reception mode",
910                gettext_comment => 'Mail reception mode.',
911                format          => [
912                    'mail',    'notice', 'digest', 'digestplain',
913                    'summary', 'nomail', 'txt',    'urlize',
914                    'not_me'
915                ],
916                synonym    => {'html' => 'mail'},
917                field_type => 'reception',
918                occurrence => '1',
919                default    => 'mail'
920            },
921            visibility => {
922                context         => [qw(list)],
923                order           => 2,
924                gettext_id      => "visibility",
925                gettext_comment => 'Visibility of the subscriber.',
926                format          => ['conceal', 'noconceal'],
927                field_type      => 'visibility',
928                occurrence      => '1',
929                default         => 'noconceal'
930            }
931        },
932    },
933
934    msg_topic => {
935        context    => [qw(list)],
936        order      => 20.07,
937        group      => 'sending',
938        gettext_id => "Topics for message categorization",
939        gettext_comment =>
940            "This paragraph defines a topic used to tag a message of a list, named by msg_topic.name (\"other\" is a reserved word), its title is msg_topic.title. The msg_topic.keywords entry is optional and allows automatic tagging. This should be a list of keywords, separated by ','.",
941        format => {
942            name => {
943                context     => [qw(list)],
944                order       => 1,
945                gettext_id  => "Message topic name",
946                format      => '[\-\w]+',
947                occurrence  => '1',
948                length      => 15,
949                validations => ['reserved_msg_topic_name'],
950            },
951            keywords => {
952                context    => [qw(list)],
953                order      => 2,
954                gettext_id => "Message topic keywords",
955                format     => '[^,\n]+(,[^,\n]+)*',
956                occurrence => '0-1'
957            },
958            title => {
959                context    => [qw(list)],
960                order      => 3,
961                gettext_id => "Message topic title",
962                format     => '.+',
963                occurrence => '1',
964                length     => 35
965            }
966        },
967        occurrence => '0-n'
968    },
969
970    msg_topic_keywords_apply_on => {
971        context => [qw(list)],
972        order   => 20.08,
973        group   => 'sending',
974        gettext_id =>
975            "Defines to which part of messages topic keywords are applied",
976        gettext_comment =>
977            'This parameter indicates which part of the message is used to perform automatic tagging.',
978        format     => ['subject', 'body', 'subject_and_body'],
979        occurrence => '0-1',
980        default    => 'subject'
981    },
982
983    msg_topic_tagging => {
984        context    => [qw(list)],
985        order      => 20.09,
986        group      => 'sending',
987        gettext_id => "Message tagging",
988        gettext_comment =>
989            'This parameter indicates if the tagging is optional or required for a list.',
990        format     => ['required_sender', 'required_moderator', 'optional'],
991        occurrence => '1',
992        default    => 'optional'
993    },
994
995    reply_to => {
996        context    => [qw(list)],
997        group      => 'sending',
998        gettext_id => "Reply address",
999        format     => '\S+',
1000        default    => 'sender',
1001        obsolete   => 1
1002    },
1003    'reply-to' => {obsolete => 'reply_to'},
1004    replyto    => {obsolete => 'reply_to'},
1005
1006    forced_reply_to => {
1007        context    => [qw(list)],
1008        group      => 'sending',
1009        gettext_id => "Forced reply address",
1010        format     => '\S+',
1011        obsolete   => 1
1012    },
1013    forced_replyto    => {obsolete => 'forced_reply_to'},
1014    'forced_reply-to' => {obsolete => 'forced_reply_to'},
1015
1016    reply_to_header => {
1017        context    => [qw(list)],
1018        order      => 20.10,
1019        group      => 'sending',
1020        gettext_id => "Reply address",
1021        gettext_comment =>
1022            'This defines what Sympa will place in the Reply-To: SMTP header field of the messages it distributes.',
1023        format => {
1024            value => {
1025                context    => [qw(list)],
1026                order      => 1,
1027                gettext_id => "value",
1028                gettext_comment =>
1029                    "This parameter indicates whether the Reply-To: field should indicate the sender of the message (sender), the list itself (list), both list and sender (all) or an arbitrary e-mail address (defined by the other_email parameter).\nNote: it is inadvisable to change this parameter, and particularly inadvisable to set it to list. Experience has shown it to be almost inevitable that users, mistakenly believing that they are replying only to the sender, will send private messages to a list. This can lead, at the very least, to embarrassment, and sometimes to more serious consequences.",
1030                format     => ['sender', 'list', 'all', 'other_email'],
1031                default    => 'sender',
1032                occurrence => '1'
1033            },
1034            other_email => {
1035                context    => [qw(list)],
1036                order      => 2,
1037                gettext_id => "other email address",
1038                gettext_comment =>
1039                    'If value was set to other_email, this parameter defines the e-mail address used.',
1040                format_s => '$email',
1041            },
1042            apply => {
1043                context    => [qw(list)],
1044                order      => 3,
1045                gettext_id => "respect of existing header field",
1046                gettext_comment =>
1047                    'The default is to respect (preserve) the existing Reply-To: SMTP header field in incoming messages. If set to forced, Reply-To: SMTP header field will be overwritten.',
1048                format  => ['forced', 'respect'],
1049                default => 'respect'
1050            }
1051        }
1052    },
1053
1054    anonymous_sender => {
1055        context    => [qw(list)],
1056        order      => 20.11,
1057        group      => 'sending',
1058        gettext_id => "Anonymous sender",
1059        gettext_comment =>
1060            "To hide the sender's email address before distributing the message. It is replaced by the provided email address.",
1061        format => '.+'
1062    },
1063
1064    anonymous_header_fields => {
1065        context => [qw(site)],
1066        order   => 20.11_1,
1067        group   => 'sending',
1068        gettext_id =>
1069            'Header fields removed when a mailing list is setup in anonymous mode',
1070        gettext_comment =>
1071            "See \"anonymous_sender\" list parameter.\nDefault value prior to Sympa 6.1.19 is:\n  Sender,X-Sender,Received,Message-id,From,X-Envelope-To,Resent-From,Reply-To,Organization,Disposition-Notification-To,X-Envelope-From,X-X-Sender",
1072        default =>
1073            'Authentication-Results,Disposition-Notification-To,DKIM-Signature,Injection-Info,Organisation,Organization,Original-Recipient,Originator,Path,Received,Received-SPF,Reply-To,Resent-Reply-To,Return-Receipt-To,X-Envelope-From,X-Envelope-To,X-Sender,X-X-Sender',
1074        split_char => ',',
1075    },
1076
1077    custom_header => {
1078        context    => [qw(list)],
1079        order      => 20.12,
1080        group      => 'sending',
1081        gettext_id => "Custom header field",
1082        gettext_comment =>
1083            'This parameter is optional. The headers specified will be added to the headers of messages distributed via the list. As of release 1.2.2 of Sympa, it is possible to put several custom header lines in the configuration file at the same time.',
1084        format     => '\S+:\s+.*',
1085        occurrence => '0-n',
1086        length     => 30
1087    },
1088    'custom-header' => {obsolete => 'custom_header'},
1089
1090    custom_subject => {
1091        context    => [qw(list)],
1092        order      => 20.13,
1093        group      => 'sending',
1094        gettext_id => "Subject tagging",
1095        gettext_comment =>
1096            'This parameter is optional. It specifies a string which is added to the subject of distributed messages (intended to help users who do not use automatic tools to sort incoming messages). This string will be surrounded by [] characters.',
1097        format => '.+',
1098        length => 15
1099    },
1100    'custom-subject' => {obsolete => 'custom_subject'},
1101
1102    footer_type => {
1103        context    => [qw(list)],
1104        order      => 20.14,
1105        group      => 'sending',
1106        gettext_id => "Attachment type",
1107        gettext_comment =>
1108            "List owners may decide to add message headers or footers to messages sent via the list. This parameter defines the way a footer/header is added to a message.\nmime: \nThe default value. Sympa will add the footer/header as a new MIME part.\nappend: \nSympa will not create new MIME parts, but will try to append the header/footer to the body of the message. Predefined message-footers will be ignored. Headers/footers may be appended to text/plain messages only.",
1109        format  => ['mime', 'append'],
1110        default => 'mime'
1111    },
1112
1113    max_size => {
1114        context    => [qw(list domain host)],
1115        order      => 20.15,
1116        group      => 'sending',                # incoming / sending?
1117        gettext_id => "Maximum message size",
1118        gettext_comment => 'Maximum size of a message in 8-bit bytes.',
1119        #gettext_id => 'Maximum size of messages',
1120        #gettext_comment =>
1121        #    'Incoming messages smaller than this size is allowed distribution by Sympa.',
1122        gettext_unit => 'bytes',
1123        format       => '\d+',
1124        length       => 8,
1125        default      => '5242880',    ## 5 MiB
1126        sample       => '2097152',
1127    },
1128    'max-size' => {obsolete => 'max_size'},
1129
1130    personalization_feature => {
1131        context    => [qw(list domain site)],
1132        order      => 20.16,
1133        group      => 'sending',                         # outgoing / sending?
1134        gettext_id => "Allow message personalization",
1135        format     => ['on', 'off'],
1136        occurrence => '1',
1137        default    => 'off',
1138    },
1139    merge_feature => {obsolete => 'personalization_feature'},
1140
1141    personalization => {
1142        context    => [qw(list domain site)],
1143        order      => 20.161,
1144        group      => 'sending',
1145        gettext_id => "Message personalization",
1146        format     => {
1147            web_apply_on => {
1148                context    => [qw(list domain site)],
1149                order      => 1,
1150                group      => 'sending',
1151                gettext_id => 'Scope for messages from the web interface',
1152                format     => ['none', 'footer', 'all'],
1153                default    => 'footer',
1154                occurrence => '1'
1155            },
1156            mail_apply_on => {
1157                context    => [qw(list domain site)],
1158                order      => 2,
1159                group      => 'sending',
1160                gettext_id => 'Scope for messages from incoming email',
1161                format     => ['none', 'footer', 'all'],
1162                default    => 'none',
1163                occurrence => '1'
1164            },
1165        },
1166    },
1167
1168    message_hook => {
1169        context    => [qw(list)],
1170        order      => 20.17,
1171        group      => 'sending',
1172        gettext_id => 'Hook modules for message processing',
1173        format     => {
1174            pre_distribute => {
1175                context    => [qw(list)],
1176                order      => 1,
1177                gettext_id => 'A hook on the messages before distribution',
1178                format     => '(::|\w)+',
1179            },
1180            post_archive => {
1181                context    => [qw(list)],
1182                order      => 2,
1183                gettext_id => 'A hook on the messages just after archiving',
1184                format     => '(::|\w)+',
1185            },
1186        },
1187    },
1188
1189    reject_mail_from_automates_feature => {
1190        context => [qw(list site)],
1191        order   => 20.18,
1192        group   => 'sending',         # incoming / sending?
1193        gettext_id => "Reject mail from automatic processes (crontab, etc)?",
1194        #gettext_id => 'Reject mail sent from automated services to list',
1195        gettext_comment =>
1196            "Rejects messages that seem to be from automated services, based on a few header fields (\"Content-Identifier:\", \"Auto-Submitted:\").\nSympa also can be configured to reject messages based on the \"From:\" header field value (see \"loop_prevention_regex\").",
1197        format     => ['on', 'off'],
1198        occurrence => '1',
1199        default    => 'on',
1200    },
1201
1202    remove_headers => {
1203        context => [qw(list site)],
1204        order   => 20.19,
1205        group   => 'sending',         # outgoing / sending?
1206        #gettext_id => 'Incoming SMTP header fields to be removed',
1207        gettext_id => 'Header fields to be removed from incoming messages',
1208        gettext_comment =>
1209            "Use it, for example, to ensure some privacy for your users in case that \"anonymous_sender\" mode is inappropriate.\nThe removal of these header fields is applied before Sympa adds its own header fields (\"rfc2369_header_fields\" and \"custom_header\").",
1210        format => '\S+',
1211        default =>
1212            'X-Sympa-To,X-Family-To,Return-Receipt-To,Precedence,X-Sequence,Disposition-Notification-To,Sender',
1213        sample =>
1214            'Resent-Date,Resent-From,Resent-To,Resent-Message-Id,Sender,Delivered-To',
1215        occurrence => '0-n',
1216        split_char => ','
1217    },
1218
1219    remove_outgoing_headers => {
1220        context => [qw(list site)],
1221        order   => 20.20,
1222        group   => 'sending',         # outgoing /  sending?
1223        #gettext_id => 'Outgoing SMTP header fields to be removed',
1224        gettext_id =>
1225            'Header fields to be removed before message distribution',
1226        gettext_comment =>
1227            "The removal happens after Sympa's own header fields are added; therefore, it is a convenient way to remove Sympa's own header fields (like \"X-Loop:\" or \"X-no-archive:\") if you wish.",
1228        format     => '\S+',
1229        default    => 'none',
1230        sample     => 'X-no-archive',
1231        occurrence => '0-n',
1232        split_char => ','
1233    },
1234
1235    rfc2369_header_fields => {
1236        context => [qw(list site)],
1237        order   => 20.21,
1238        group   => 'sending',         # outgoing / sending?
1239        #gettext_id => "RFC 2369 Header fields",
1240        gettext_id => 'RFC 2369 header fields',
1241        gettext_comment =>
1242            "Specify which RFC 2369 mailing list header fields to be added.\n\"List-Id:\" header field defined in RFC 2919 is always added. Sympa also adds \"Archived-At:\" header field defined in RFC 5064.",
1243        format =>
1244            ['help', 'subscribe', 'unsubscribe', 'post', 'owner', 'archive'],
1245        default    => 'help,subscribe,unsubscribe,post,owner,archive',
1246        occurrence => '0-n',
1247        split_char => ','
1248    },
1249
1250    ### Outgoing
1251    # - Corresponds to ProcessOutgoing and ToMailer spindles.
1252    # - Does _not_ contain the parameters with List context.
1253
1254    urlize_min_size => {
1255        context    => [qw(domain site)],
1256        order      => 21.00_11,
1257        group      => 'outgoing',                     # 'sending'?
1258        gettext_id => 'Minimum size to be urlized',
1259        gettext_comment =>
1260            'When a subscriber chose "urlize" reception mode, attachments not smaller than this size will be urlized.',
1261        format       => '\d+',
1262        gettext_unit => 'bytes',
1263        default      => 10240,                        # 10 kiB
1264    },
1265    allowed_external_origin => {
1266        context    => [qw(domain site)],
1267        order      => 21.00_12,
1268        group      => 'outgoing',                                # 'archives'?
1269        gettext_id => 'Allowed external links in sanitized HTML',
1270        gettext_comment =>
1271            'When the HTML content of a message must be sanitized, links ("href" or "src" attributes) with the hosts listed in this parameter will not be scrubbed. If "*" character is included, it matches any subdomains. Single "*" allows any hosts.',
1272        format     => '[-\w*]+(?:[.][-\w*]+)+',
1273        split_char => ',',
1274        sample     => '*.example.org,www.example.com',
1275    },
1276
1277    sympa_packet_priority => {
1278        context    => [qw(domain site)],
1279        order      => 21.00_20,
1280        group      => 'outgoing',
1281        gettext_id => 'Default priority for a packet',
1282        default    => '5',
1283        gettext_comment =>
1284            'The default priority set to a packet to be sent by the bulk.',
1285        format => [0 .. 9, 'z'],
1286    },
1287    bulk_fork_threshold => {
1288        context    => [qw(site)],
1289        order      => 21.00_21,
1290        group      => 'outgoing',
1291        default    => '1',
1292        gettext_id => 'Fork threshold of bulk daemon',
1293        gettext_comment =>
1294            'The minimum number of packets before bulk daemon forks a new worker to increase sending rate.',
1295        format => '\d+',
1296    },
1297    bulk_max_count => {
1298        context    => [qw(site)],
1299        order      => 21.00_22,
1300        group      => 'outgoing',
1301        default    => '3',
1302        gettext_id => 'Maximum number of bulk workers',
1303        format     => '\d+',
1304    },
1305    bulk_lazytime => {
1306        context    => [qw(site)],
1307        order      => 21.00_23,
1308        group      => 'outgoing',
1309        default    => '600',
1310        gettext_id => 'Idle timeout of bulk workers',
1311        gettext_comment =>
1312            'The number of seconds a bulk worker will remain running without processing a message before it spontaneously exits.',
1313        format       => '\d+',
1314        gettext_unit => 'seconds',
1315    },
1316    bulk_sleep => {
1317        context    => [qw(site)],
1318        order      => 21.00_24,
1319        group      => 'outgoing',
1320        default    => '1',
1321        gettext_id => 'Sleep time of bulk workers',
1322        gettext_comment =>
1323            "The number of seconds a bulk worker sleeps between starting a new loop if it didn't find a message to send.\nKeep it small if you want your server to be reactive.",
1324        format       => '\d+',
1325        gettext_unit => 'seconds',
1326    },
1327    bulk_wait_to_fork => {
1328        context    => [qw(site)],
1329        order      => 21.00_25,
1330        group      => 'outgoing',
1331        default    => '10',
1332        gettext_id => 'Interval between checks of packet numbers',
1333        gettext_comment =>
1334            "Number of seconds a master bulk daemon waits between two packets number checks.\nKeep it small if you expect brutal increases in the message sending load.",
1335        format       => '\d+',
1336        gettext_unit => 'seconds',
1337    },
1338
1339    log_smtp => {
1340        context    => [qw(domain site)],
1341        order      => 21.00_32,
1342        group      => 'outgoing',
1343        gettext_id => 'Log invocation of sendmail',
1344        gettext_comment =>
1345            'This can be overwritten by "-m" option for sympa.pl.',
1346        format  => ['on', 'off'],    #XXX
1347        default => 'off',
1348    },
1349    maxsmtp => {
1350        context    => [qw(site)],
1351        order      => 21.00_33,
1352        group      => 'outgoing',
1353        default    => '40',
1354        sample     => '500',
1355        gettext_id => 'Maximum number of sendmail processes',
1356        gettext_comment =>
1357            "Maximum number of simultaneous child processes spawned by Sympa. This is the main load control parameter. \nProposed value is quite low, but you can rise it up to 100, 200 or even 300 with powerful systems.",
1358        format => '\d+',
1359    },
1360    nrcpt => {
1361        context    => [qw(site)],
1362        order      => 21.00_34,
1363        group      => 'outgoing',
1364        default    => '25',
1365        gettext_id => 'Maximum number of recipients per call to sendmail',
1366        gettext_comment =>
1367            'This grouping factor makes it possible for the sendmail processes to optimize the number of SMTP sessions for message distribution. If needed, you can limit the number of recipients for a particular domain. Check the "nrcpt_by_domain.conf" configuration file.',
1368        format => '\d+',
1369    },
1370    avg => {
1371        context => [qw(site)],
1372        order   => 21.00_35,
1373        group   => 'outgoing',
1374        default => '10',
1375        gettext_id =>
1376            'Maximum number of different mail domains per call to sendmail',
1377        format => '\d+',
1378    },
1379
1380    ### Privileges page ###
1381
1382    create_list => {
1383        context    => [qw(domain site)],
1384        order      => 30.00_01,
1385        group      => 'command',
1386        default    => 'public_listmaster',
1387        sample     => 'intranet',
1388        gettext_id => 'Who is able to create lists',
1389        gettext_comment =>
1390            'Defines who can create lists (or request list creation) by creating new lists or by renaming or copying existing lists.',
1391        scenario => 'create_list',
1392    },
1393    allow_subscribe_if_pending => {
1394        context    => [qw(domain site)],
1395        order      => 30.00_02,
1396        group      => 'command',
1397        gettext_id => 'Allow adding subscribers to a list not open',
1398        gettext_comment =>
1399            'If set to "off", adding subscribers to, or removing subscribers from a list with status other than "open" is forbidden.',
1400        format  => ['on', 'off'],    #XXX
1401        default => 'on',
1402    },
1403    global_remind => {
1404        context    => [qw(site)],
1405        order      => 30.00_03,
1406        group      => 'command',
1407        gettext_id => 'Who is able to send remind messages over all lists',
1408        default    => 'listmaster',
1409        scenario   => 'global_remind',
1410    },
1411    move_user => {
1412        context    => [qw(domain site)],
1413        order      => 30.00_04,
1414        group      => 'command',
1415        default    => 'auth',
1416        gettext_id => 'Who is able to change user\'s email',
1417        scenario   => 'move_user',
1418    },
1419    use_blocklist => {
1420        context    => [qw(domain site)],
1421        order      => 30.00_05,
1422        group      => 'command',
1423        gettext_id => 'Use blocklist',
1424        default    => 'send,create_list',
1425        split_char => ',',
1426        gettext_comment =>
1427            'List of operations separated by comma for which blocklist filter is applied.  Setting this parameter to "none" will hide the blocklist feature.',
1428        format => '[-.\w]+',
1429    },
1430    use_blacklist => {obsolete => 'use_blocklist'},
1431
1432    ### Priviledges on the lists
1433
1434    info => {
1435        context    => [qw(list domain site)],
1436        order      => 30.01,
1437        group      => 'command',
1438        gettext_id => "Who can view list information",
1439        scenario   => 'info',
1440        default    => 'open',
1441    },
1442
1443    subscribe => {
1444        context    => [qw(list domain site)],
1445        order      => 30.02,
1446        group      => 'command',
1447        gettext_id => "Who can subscribe to the list",
1448        gettext_comment =>
1449            'The subscribe parameter defines the rules for subscribing to the list.',
1450        scenario => 'subscribe',
1451        default  => 'open',
1452    },
1453    subscription => {obsolete => 'subscribe'},
1454
1455    add => {
1456        context    => [qw(list domain site)],
1457        order      => 30.03,
1458        group      => 'command',
1459        gettext_id => "Who can add subscribers",
1460        gettext_comment =>
1461            'Privilege for adding (ADD command) a subscriber to the list',
1462        scenario => 'add',
1463        default  => 'owner',
1464    },
1465
1466    unsubscribe => {
1467        context    => [qw(list domain site)],
1468        order      => 30.04,
1469        group      => 'command',
1470        gettext_id => "Who can unsubscribe",
1471        gettext_comment =>
1472            'This parameter specifies the unsubscription method for the list. Use open_notify or auth_notify to allow owner notification of each unsubscribe command.',
1473        scenario => 'unsubscribe',
1474        default  => 'open',
1475    },
1476    unsubscription => {obsolete => 'unsubscribe'},
1477
1478    del => {
1479        context    => [qw(list domain site)],
1480        order      => 30.05,
1481        group      => 'command',
1482        gettext_id => "Who can delete subscribers",
1483        scenario   => 'del',
1484        default    => 'owner',
1485    },
1486
1487    invite => {
1488        context    => [qw(list domain site)],
1489        order      => 30.06,
1490        group      => 'command',
1491        gettext_id => "Who can invite people",
1492        scenario   => 'invite',
1493        default    => 'private',
1494    },
1495
1496    remind => {
1497        context    => [qw(list domain site)],
1498        order      => 30.07,
1499        group      => 'command',
1500        gettext_id => "Who can start a remind process",
1501        gettext_comment =>
1502            'This parameter specifies who is authorized to use the remind command.',
1503        scenario => 'remind',
1504        default  => 'owner',
1505    },
1506
1507    review => {
1508        context    => [qw(list domain site)],
1509        order      => 30.08,
1510        group      => 'command',
1511        gettext_id => "Who can review subscribers",
1512        gettext_comment =>
1513            'This parameter specifies who can access the list of members. Since subscriber addresses can be abused by spammers, it is strongly recommended that you only authorize owners or subscribers to access the subscriber list. ',
1514        scenario => 'review',
1515        synonym  => {'open' => 'public',},
1516        default  => 'owner',
1517    },
1518
1519    owner_domain => {
1520        context    => [qw(list domain site)],
1521        order      => 30.085,
1522        group      => 'command',
1523        gettext_id => "Required domains for list owners",
1524        #gettext_comment =>
1525        #    'Restrict list ownership to addresses in the specified domains.',
1526        gettext_comment =>
1527            'Restrict list ownership to addresses in the specified domains. This can be used to reserve list ownership to a group of trusted users from a set of domains associated with an organization, while allowing moderators and subscribers from the Internet at large.',
1528        format_s   => '$host( +$host)*',
1529        length     => 72,
1530        occurrence => '0-1',
1531        split_char => ' ',
1532    },
1533
1534    owner_domain_min => {
1535        context    => [qw(list domain site)],
1536        order      => 30.086,
1537        group      => 'command',
1538        gettext_id => "Minimum owners in required domains",
1539        #gettext_comment =>
1540        #    'Require list ownership by a minimum number of addresses in the specified domains.',
1541        gettext_comment =>
1542            'Minimum number of owners for each list must satisfy the owner_domain restriction. The default of zero (0) means *all* list owners must match. Setting to 1 requires only one list owner to match owner_domain; all other owners can be from any domain. This setting can be used to ensure that there is always at least one known contact point for any mailing list.',
1543        format     => '\d+',
1544        length     => 2,
1545        occurrence => '0-1',
1546        default    => '0',
1547    },
1548
1549    shared_doc => {
1550        context    => [qw(list domain site)],
1551        order      => 30.09,
1552        group      => 'command',                #FIXME www_other/shared_doc
1553        gettext_id => "Shared documents",
1554        gettext_comment =>
1555            'This paragraph defines read and edit access to the shared document repository.',
1556        format => {
1557            d_read => {
1558                context    => [qw(list domain site)],
1559                order      => 1,
1560                gettext_id => "Who can view",
1561                scenario   => 'd_read',
1562                default    => 'private',
1563            },
1564            d_edit => {
1565                context    => [qw(list domain site)],
1566                order      => 2,
1567                gettext_id => "Who can edit",
1568                scenario   => 'd_edit',
1569                default    => 'owner',
1570            },
1571            quota => {
1572                context => [qw(list domain site)],
1573                order   => 3,
1574                #FIXME: group www_other/shared_doc
1575                gettext_id   => "quota",
1576                gettext_unit => 'Kbytes',
1577                format       => '\d+',
1578                length       => 8
1579            }
1580        }
1581    },
1582
1583    ### Archives page ###
1584
1585    ignore_x_no_archive_header_feature => {
1586        context    => [qw(site)],
1587        order      => 40.00_01,
1588        group      => 'archives',
1589        gettext_id => 'Ignore "X-no-archive:" header field',
1590        gettext_comment =>
1591            'Sympa\'s default behavior is to skip archiving of incoming messages that have an "X-no-archive:" header field set. This parameter allows one to change this behavior.',
1592        format  => ['on', 'off'],
1593        default => 'off',
1594        sample  => 'on',
1595    },
1596    custom_archiver => {
1597        context    => [qw(site)],
1598        order      => 40.00_02,
1599        group      => 'archives',
1600        gettext_id => 'Custom archiver',
1601        gettext_comment =>
1602            "Activates a custom archiver to use instead of MHonArc. The value of this parameter is the absolute path to the executable file.\nSympa invokes this file with these two arguments:\n--list\nThe address of the list including domain part.\n--file\nAbsolute path to the message to be archived.",
1603        format => '.+',
1604        file   => 'wwsympa.conf',
1605    },
1606
1607    process_archive => {
1608        context    => [qw(list domain site)],
1609        order      => 40.01,
1610        group      => 'archives',
1611        gettext_id => "Store distributed messages into archive",
1612        gettext_comment =>
1613            "If enabled, distributed messages via lists will be archived. Otherwise archiving is disabled.\nNote that even if setting this parameter disabled, past archives will not be removed and will be accessible according to access settings by each list.",
1614        format     => ['on', 'off'],
1615        occurrence => '1',
1616        default    => 'off',
1617    },
1618
1619    web_archive => {
1620        context    => [qw(list domain site)],
1621        obsolete   => '1',                      # Merged into archive.
1622        group      => 'archives',
1623        gettext_id => "Web archives",
1624        format     => {
1625            access => {
1626                context    => [qw(list domain site)],
1627                order      => 1,
1628                gettext_id => "access right",
1629                scenario   => 'archive_web_access',
1630                default    => 'closed',
1631                obsolete   => 1,                      # Use archive.web_access
1632            },
1633            quota => {
1634                context      => [qw(list site)],
1635                order        => 2,
1636                gettext_id   => "quota",
1637                gettext_unit => 'Kbytes',
1638                format       => '\d+',
1639                length       => 8,
1640                obsolete     => 1,                    # Use archive.quota
1641            },
1642            max_month => {
1643                context    => [qw(list)],
1644                order      => 3,
1645                gettext_id => "Maximum number of month archived",
1646                format     => '\d+',
1647                length     => 3,
1648                obsolete => 1,                        # Use archive.max_month
1649            }
1650        }
1651    },
1652    archive => {
1653        context    => [qw(list domain site)],
1654        order      => 40.02,
1655        group      => 'archives',
1656        gettext_id => "Archives",
1657        gettext_comment =>
1658            "Privilege for reading mail archives and frequency of archiving.\nDefines who can access the list's web archive.",
1659        format => {
1660            period => {
1661                context    => [qw(list)],
1662                order      => 1,
1663                gettext_id => "frequency",
1664                format     => ['day', 'week', 'month', 'quarter', 'year'],
1665                synonym    => {'weekly' => 'week'},
1666                obsolete => 1,    # Not yet implemented.
1667            },
1668            access => {
1669                context    => [qw(list)],
1670                order      => 2,
1671                gettext_id => "access right",
1672                format  => ['open', 'private', 'public', 'owner', 'closed'],
1673                synonym => {'open' => 'public'},
1674                obsolete => 1,    # Use archive.mail_access
1675            },
1676            web_access => {
1677                context    => [qw(list domain site)],
1678                order      => 3,
1679                gettext_id => "access right",
1680                scenario   => 'archive_web_access',
1681                default    => 'closed',
1682            },
1683            mail_access => {
1684                context    => [qw(list domain site)],
1685                order      => 4,
1686                gettext_id => "access right by mail commands",
1687                scenario   => 'archive_mail_access',
1688                synonym    => {
1689                    'open' => 'public',    # Compat. with <=6.2b.3.
1690                },
1691                default => 'closed',
1692            },
1693            quota => {
1694                context      => [qw(list site)],
1695                order        => 5,
1696                gettext_id   => "quota",
1697                gettext_unit => 'Kbytes',
1698                format       => '\d+',
1699                length       => 8
1700            },
1701            max_month => {
1702                context      => [qw(list)],
1703                order        => 6,
1704                gettext_id   => "Maximum number of month archived",
1705                gettext_unit => 'months',
1706                format       => '\d+',
1707                length       => 3
1708            }
1709        }
1710    },
1711
1712    archive_crypted_msg => {
1713        context    => [qw(list)],
1714        order      => 40.03,
1715        group      => 'archives',
1716        gettext_id => "Archive encrypted mails as cleartext",
1717        format     => ['original', 'decrypted'],
1718        occurrence => '1',
1719        default    => 'original'
1720    },
1721
1722    web_archive_spam_protection => {
1723        context => [qw(list domain site)],
1724        order   => 40.04,
1725        group   => 'archives',
1726        #gettext_id => "email address protection method",
1727        gettext_id => 'Protect web archive against spam harvesters',
1728        #gettext_comment =>
1729        #    'Idem spam_protection is provided but it can be used only for web archives. Access requires a cookie, and users must submit a small form in order to receive a cookie before browsing the archives. This blocks all robot, even google and co.',
1730        gettext_comment =>
1731            "The same as \"spam_protection\", but restricted to the web archive.\nIn addition to it:\ncookie: users must submit a small form in order to receive a cookie before browsing the web archive.\nconcealed: e-mail addresses will never be displayed.",
1732        format     => ['cookie', 'javascript', 'at', 'concealed', 'none'],
1733        synonym    => {'gecos' => 'concealed'},
1734        occurrence => '1',
1735        default    => 'cookie',
1736    },
1737
1738    ### Bounces page ###
1739
1740    bounce => {
1741        context    => [qw(list site)],
1742        order      => 50.01,
1743        group      => 'bounces',
1744        gettext_id => "Bounces management",
1745        format     => {
1746            warn_rate => {
1747                context    => [qw(list site)],
1748                order      => 1,
1749                gettext_id => "warn rate",
1750                gettext_comment =>
1751                    'The list owner receives a warning whenever a message is distributed and the number (percentage) of bounces exceeds this value.',
1752                gettext_unit => '%',
1753                format       => '\d+',
1754                length       => 3,
1755                default      => '30',
1756            },
1757            halt_rate => {
1758                context    => [qw(list site)],
1759                order      => 2,
1760                gettext_id => "halt rate",
1761                gettext_comment =>
1762                    'NOT USED YET. If bounce rate reaches the halt_rate, messages for the list will be halted, i.e. they are retained for subsequent moderation.',
1763                gettext_unit => '%',
1764                format       => '\d+',
1765                length       => 3,
1766                default      => '50',
1767                obsolete     => 1,       # Not yet implemented.
1768            }
1769        }
1770    },
1771
1772    bouncers_level1 => {
1773        context         => [qw(list domain site)],
1774        order           => 50.02,
1775        group           => 'bounces',
1776        gettext_id      => "Management of bouncers, 1st level",
1777        gettext_comment => 'Level 1 is the lower level of bouncing users',
1778        format          => {
1779            rate => {
1780                context    => [qw(list domain site)],
1781                order      => 1,
1782                gettext_id => "threshold",
1783                gettext_comment =>
1784                    "Each bouncing user have a score (from 0 to 100).\nThis parameter defines a lower limit for each category of bouncing users.For example, level 1 begins from 45 to level_2_treshold.",
1785                gettext_unit => 'points',
1786                format       => '\d+',
1787                length       => 2,
1788                default      => '45',
1789            },
1790            action => {
1791                context    => [qw(list)],
1792                order      => 2,
1793                gettext_id => "action for this population",
1794                gettext_comment =>
1795                    'This parameter defines which task is automatically applied on level 1 bouncers.',
1796                format     => ['remove_bouncers', 'notify_bouncers', 'none'],
1797                occurrence => '1',
1798                default    => 'notify_bouncers'
1799            },
1800            notification => {
1801                context    => [qw(list)],
1802                order      => 3,
1803                gettext_id => "notification",
1804                gettext_comment =>
1805                    'When automatic task is executed on level 1 bouncers, a notification email can be send to listowner or listmaster.',
1806                format     => ['none', 'owner', 'listmaster'],
1807                occurrence => '1',
1808                default    => 'owner'
1809            }
1810        }
1811    },
1812
1813    bouncers_level2 => {
1814        context         => [qw(list domain site)],
1815        order           => 50.03,
1816        group           => 'bounces',
1817        gettext_id      => "Management of bouncers, 2nd level",
1818        gettext_comment => 'Level 2 is the highest level of bouncing users',
1819        format          => {
1820            rate => {
1821                context    => [qw(list domain site)],
1822                order      => 1,
1823                gettext_id => "threshold",
1824                gettext_comment =>
1825                    "Each bouncing user have a score (from 0 to 100).\nThis parameter defines the score range defining each category of bouncing users.For example, level 2 is for users with a score between 80 and 100.",
1826                gettext_unit => 'points',
1827                format       => '\d+',
1828                length       => 2,
1829                default      => '75',
1830            },
1831            action => {
1832                context    => [qw(list)],
1833                order      => 2,
1834                gettext_id => "action for this population",
1835                gettext_comment =>
1836                    'This parameter defines which task is automatically applied on level 2 bouncers.',
1837                format     => ['remove_bouncers', 'notify_bouncers', 'none'],
1838                occurrence => '1',
1839                default    => 'remove_bouncers'
1840            },
1841            notification => {
1842                context    => [qw(list)],
1843                order      => 3,
1844                gettext_id => "notification",
1845                gettext_comment =>
1846                    'When automatic task is executed on level 2 bouncers, a notification email can be send to listowner or listmaster.',
1847                format     => ['none', 'owner', 'listmaster'],
1848                occurrence => '1',
1849                default    => 'owner'
1850            }
1851        }
1852    },
1853
1854    verp_rate => {
1855        context    => [qw(list domain site)],
1856        order      => 50.04,
1857        group      => 'bounces',
1858        gettext_id => "percentage of list members in VERP mode",
1859        gettext_comment =>
1860            "Uses variable envelope return path (VERP) to detect bouncing subscriber addresses.\n0%: VERP is never used.\n100%: VERP is always in use.\nVERP requires address with extension to be supported by MTA. If tracking is enabled for a list or a message, VERP is applied for 100% of subscribers.",
1861        format =>
1862            ['100%', '50%', '33%', '25%', '20%', '10%', '5%', '2%', '0%'],
1863        occurrence => '1',
1864        default    => '0%',
1865    },
1866
1867    tracking => {
1868        context    => [qw(list site)],
1869        order      => 50.05,
1870        group      => 'bounces',
1871        gettext_id => "Message tracking feature",
1872        format     => {
1873            delivery_status_notification => {
1874                context => [qw(list site)],
1875                order   => 1,
1876                gettext_id =>
1877                    "tracking message by delivery status notification",
1878                #gettext_id =>
1879                #    'Tracking message by delivery status notification (DSN)',
1880                format     => ['on', 'off'],
1881                occurrence => '1',
1882                default    => 'off',
1883            },
1884            message_disposition_notification => {
1885                context => [qw(list site)],
1886                order   => 2,
1887                gettext_id =>
1888                    "tracking message by message disposition notification",
1889                #gettext_id =>
1890                #    'Tracking message by message disposition notification (MDN)',
1891                format     => ['on', 'on_demand', 'off'],
1892                occurrence => '1',
1893                default    => 'off',
1894            },
1895            tracking => {
1896                context    => [qw(list site)],
1897                order      => 3,
1898                gettext_id => "who can view message tracking",
1899                scenario   => 'tracking',
1900                default    => 'owner',
1901            },
1902            retention_period => {
1903                context => [qw(list site)],
1904                order   => 4,
1905                gettext_id =>
1906                    "Tracking datas are removed after this number of days",
1907                #gettext_id => 'Max age of tracking information',
1908                #gettext_comment =>
1909                #    'Tracking information is removed after this number of days',
1910                gettext_unit => 'days',
1911                format       => '\d+',
1912                default      => '90',
1913                length       => 5
1914            }
1915        }
1916    },
1917
1918    welcome_return_path => {
1919        context    => [qw(list site)],
1920        order      => 50.06,
1921        group      => 'bounces',
1922        gettext_id => "Welcome return-path",
1923        #gettext_id => 'Remove bouncing new subscribers',
1924        gettext_comment =>
1925            'If set to unique, the welcome message is sent using a unique return path in order to remove the subscriber immediately in the case of a bounce.',
1926        format  => ['unique', 'owner'],
1927        default => 'owner',
1928    },
1929
1930    remind_return_path => {
1931        context    => [qw(list site)],
1932        order      => 50.07,
1933        group      => 'bounces',
1934        gettext_id => "Return-path of the REMIND command",
1935        #gettext_id => 'Remove subscribers bouncing remind message',
1936        gettext_comment =>
1937            'Same as welcome_return_path, but applied to remind messages.',
1938        format  => ['unique', 'owner'],
1939        default => 'owner',
1940    },
1941
1942    expire_bounce_task => {
1943        context    => [qw(site)],
1944        order      => 50.10_01,
1945        group      => 'bounces',
1946        default    => 'daily',
1947        gettext_id => 'Task for expiration of old bounces',
1948        gettext_comment =>
1949            'This task resets bouncing information for addresses not bouncing in the last 10 days after the latest message distribution.',
1950        task => 'expire_bounce',
1951    },
1952    purge_orphan_bounces_task => {
1953        context    => [qw(site)],
1954        order      => 50.10_02,
1955        group      => 'bounces',
1956        gettext_id => 'Task for cleaning invalidated bounces',
1957        gettext_comment =>
1958            'This task deletes bounce information for unsubscribed users.',
1959        default => 'monthly',
1960        task    => 'purge_orphan_bounces',
1961    },
1962    eval_bouncers_task => {
1963        context    => [qw(site)],
1964        order      => 50.10_03,
1965        group      => 'bounces',
1966        gettext_id => 'Task for updating bounce scores',
1967        gettext_comment =>
1968            'This task scans all bouncing users for all lists, and updates "bounce_score_subscriber" field in "subscriber_table" table. The scores may be used for management of bouncers.',
1969        default => 'daily',
1970        task    => 'eval_bouncers',
1971    },
1972    process_bouncers_task => {
1973        context    => [qw(site)],
1974        order      => 50.10_04,
1975        group      => 'bounces',
1976        gettext_id => 'Task for management of bouncers',
1977        gettext_comment =>
1978            'This task executes actions on bouncing users configured by each list, according to their scores.',
1979        default => 'weekly',
1980        task    => 'process_bouncers',
1981    },
1982    purge_tables_task => {
1983        context    => [qw(site)],
1984        order      => 50.10_05,
1985        group      => 'bounces',
1986        gettext_id => 'Task for cleaning tables',
1987        gettext_comment =>
1988            'This task cleans old tracking information from "notification_table" table.',
1989        default => 'daily',
1990        task    => 'purge_tables',
1991    },
1992    minimum_bouncing_count => {
1993        context    => [qw(site)],
1994        order      => 50.10_06,
1995        group      => 'bounces',
1996        gettext_id => 'Minimum number of bounces',
1997        gettext_comment =>
1998            'The minimum number of bounces received to update bounce score of a user.',
1999        format  => '\d+',
2000        default => '10',
2001    },
2002    minimum_bouncing_period => {
2003        context    => [qw(site)],
2004        order      => 50.10_07,
2005        group      => 'bounces',
2006        gettext_id => 'Minimum bouncing period',
2007        gettext_comment =>
2008            'The minimum period for which bouncing lasted to update bounce score of a user.',
2009        format       => '\d+',
2010        gettext_unit => 'days',
2011        default      => '10',
2012    },
2013    bounce_delay => {
2014        context    => [qw(site)],
2015        order      => 50.10_08,
2016        group      => 'bounces',
2017        gettext_id => 'Delay of bounces',
2018        gettext_comment =>
2019            'Average time for a bounce sent back to mailing list server after a post was sent to a list. Usually bounces are sent back on the same day as the original message.',
2020        format       => '\d+',
2021        gettext_unit => 'days',
2022        default      => '0',
2023    },
2024    bounce_email_prefix => {
2025        context    => [qw(site)],
2026        order      => 50.10_09,
2027        group      => 'bounces',
2028        gettext_id => 'Prefix of VERP return address',
2029        gettext_comment =>
2030            "The prefix to consist the return-path of probe messages used for bounce management, when variable envelope return path (VERP) is enabled. VERP requires address with extension to be supported by MTA.\nIf you change the default value, you must modify the mail aliases too.",
2031        format  => '\S+',
2032        default => 'bounce',
2033    },
2034    return_path_suffix => {
2035        context    => [qw(site)],
2036        order      => 50.10_10,
2037        group      => 'bounces',
2038        gettext_id => 'Suffix of list return address',
2039        gettext_comment =>
2040            'The suffix appended to the list name to form the return-path of messages distributed through the list. This address will receive all non-delivery reports (also called bounces).',
2041        format  => '\S+',
2042        default => '-owner',
2043    },
2044
2045    ### Loop prevention
2046
2047    loop_command_max => {
2048        context    => [qw(site)],
2049        order      => 51.00_01,
2050        group      => 'loop_prevention',
2051        gettext_id => 'Maximum number of responses to command message',
2052        gettext_comment =>
2053            'The maximum number of command reports sent to an email address. Messages are stored in "bad" subdirectory of incoming message spool, and reports are not longer sent.',
2054        format  => '\d+',
2055        default => '200',
2056    },
2057    loop_command_sampling_delay => {
2058        context    => [qw(site)],
2059        order      => 51.00_02,
2060        group      => 'loop_prevention',
2061        gettext_id => 'Delay before counting responses to command message',
2062        gettext_comment =>
2063            'This parameter defines the delay in seconds before decrementing the counter of reports sent to an email address.',
2064        format       => '\d+',
2065        gettext_unit => 'seconds',
2066        default      => '3600',
2067    },
2068    loop_command_decrease_factor => {
2069        context    => [qw(site)],
2070        order      => 51.00_03,
2071        group      => 'loop_prevention',
2072        gettext_id => 'Decrementing factor of responses to command message',
2073        gettext_comment =>
2074            'The decrementation factor (from 0 to 1), used to determine the new report counter after expiration of the delay.',
2075        format  => '[.\d]+',
2076        default => '0.5',
2077    },
2078
2079    msgid_table_cleanup_ttl => {
2080        context    => [qw(site)],
2081        order      => 51.00_04,
2082        group      => 'loop_prevention',
2083        gettext_id => 'Expiration period of message ID table',
2084        gettext_comment =>
2085            'Expiration period of entries in the table maintained by sympa_msg.pl daemon to prevent delivery of duplicate messages caused by loop.',
2086        format       => '\d+',
2087        gettext_unit => 'seconds',
2088        default      => '86400',
2089    },
2090    msgid_table_cleanup_frequency => {
2091        context    => [qw(site)],
2092        order      => 51.00_05,
2093        group      => 'loop_prevention',
2094        gettext_id => 'Cleanup interval of message ID table',
2095        gettext_comment =>
2096            'Interval between cleanups of the table maintained by sympa_msg.pl daemon to prevent delivery of duplicate messages caused by loop.',
2097        format       => '\d+',
2098        gettext_unit => 'seconds',
2099        default      => '3600',
2100    },
2101
2102    ### Automatic list creation
2103
2104    automatic_list_feature => {
2105        context    => [qw(domain site)],
2106        order      => 52.00_01,
2107        group      => 'automatic_lists',
2108        gettext_id => 'Automatic list',
2109        format     => ['on', 'off'],       #XXX
2110        default    => 'off',
2111    },
2112    automatic_list_removal => {
2113        context    => [qw(domain site)],
2114        order      => 52.00_02,
2115        group      => 'automatic_lists',
2116        gettext_id => 'Remove empty automatic list',
2117        gettext_comment =>
2118            'If set to "if_empty", then Sympa will remove automatically created mailing lists just after their creation, if they contain no list member.',
2119        format  => ['none', 'if_empty'],
2120        default => 'none',
2121        sample  => 'if_empty',
2122    },
2123    automatic_list_creation => {
2124        context    => [qw(domain site)],
2125        order      => 52.00_03,
2126        group      => 'automatic_lists',
2127        gettext_id => 'Who is able to create automatic list',
2128        default    => 'public',
2129        scenario   => 'automatic_list_creation',
2130    },
2131    automatic_list_families => {
2132        context => [qw(domain site)],
2133        order   => 52.00_04,
2134        group   => 'automatic_lists',
2135        sample =>
2136            'name=family_one:prefix=f1:display=My automatic lists:prefix_separator=+:classes separator=-:family_owners_list=alist@domain.tld;name=family_two:prefix=f2:display=My other automatic lists:prefix_separator=+:classes separator=-:family_owners_list=anotherlist@domain.tld;',
2137        gettext_id => 'Definition of automatic list families',
2138        gettext_comment =>
2139            "Defines the families the automatic lists are based on. It is a character string structured as follows:\n* each family is separated from the other by a semicolon (;)\n* inside a family definition, each field is separated from the other by a colon (:)\n* each field has the structure: \"<field name>=<field value>\"\nBasically, each time Sympa uses the automatic lists families, the values defined in this parameter will be available in the family object.\n* for scenarios: [family->name]\n* for templates: [% family.name %]",
2140        format => '.+',    #FIXME: use paragraph
2141    },
2142    parsed_family_files => {
2143        context    => [qw(domain site)],
2144        order      => 52.00_05,
2145        group      => 'automatic_lists',
2146        gettext_id => 'Parsed files for families',
2147        gettext_comment =>
2148            'comma-separated list of files that will be parsed by Sympa when instantiating a family (no space allowed in file names)',
2149        format     => '[-.\w]+',
2150        split_char => ',',
2151        default =>
2152            'message_header,message_header.mime,message_footer,message_footer.mime,info',
2153    },
2154    family_signoff => {
2155        context    => [qw(domain site)],
2156        order      => 52.00_06,
2157        group      => 'automatic_lists',
2158        gettext_id => 'Global unsubscription',
2159        default    => 'auth',                    # Compat. to <=6.2.52
2160        scenario   => 'family_signoff',
2161    },
2162
2163    ### Tag-based spam filtering
2164
2165    antispam_feature => {
2166        context    => [qw(domain site)],
2167        order      => 53.00_01,
2168        group      => 'antispam',
2169        gettext_id => 'Tag based spam filtering',
2170        format     => ['on', 'off'],
2171        default    => 'off',
2172    },
2173    antispam_tag_header_name => {
2174        context    => [qw(domain site)],
2175        order      => 53.00_02,
2176        group      => 'antispam',
2177        default    => 'X-Spam-Status',
2178        gettext_id => 'Header field to tag spams',
2179        gettext_comment =>
2180            'If a spam filter (like spamassassin or j-chkmail) add a header field to tag spams, name of this header field (example X-Spam-Status)',
2181        format => '\S+',
2182    },
2183    antispam_tag_header_spam_regexp => {
2184        context    => [qw(domain site)],
2185        order      => 53.00_03,
2186        group      => 'antispam',
2187        default    => '^\s*Yes',
2188        gettext_id => 'Regular expression to check header field to tag spams',
2189        gettext_comment =>
2190            'Regular expression applied on this header to verify message is a spam (example Yes)',
2191        format => '.+',    #FIXME: Check regexp
2192    },
2193    antispam_tag_header_ham_regexp => {
2194        context    => [qw(domain site)],
2195        order      => 53.00_04,
2196        group      => 'antispam',
2197        default    => '^\s*No',
2198        gettext_id => 'Regular expression to determine spam or ham.',
2199        gettext_comment =>
2200            'Regular expression applied on this header field to verify message is NOT a spam (example No)',
2201        format => '.+',    #FIXME: Check regexp
2202    },
2203    spam_status => {
2204        context    => [qw(domain site)],
2205        order      => 53.00_05,
2206        group      => 'antispam',
2207        default    => 'x-spam-status',
2208        gettext_id => 'Name of header field to inform',
2209        gettext_comment =>
2210            'Messages are supposed to be filtered by an spam filter that adds them one or more headers. This parameter is used to select a special scenario in order to decide the message\'s spam status: ham, spam or unsure. This parameter replaces antispam_tag_header_name, antispam_tag_header_spam_regexp and antispam_tag_header_ham_regexp.',
2211        scenario => 'spam_status',
2212    },
2213
2214    ### Directories
2215
2216    home => {
2217        context         => [qw(site)],
2218        order           => 54.00_01,
2219        group           => 'directories',
2220        default_s       => '$EXPLDIR',
2221        gettext_id      => 'List home',
2222        gettext_comment => 'Base directory of list configurations.',
2223        format          => '.+',
2224    },
2225    etc => {
2226        context    => [qw(site)],
2227        order      => 54.00_02,
2228        group      => 'directories',
2229        default_s  => '$SYSCONFDIR',
2230        gettext_id => 'Directory for configuration files',
2231        gettext_comment =>
2232            'Base directory of global configuration (except "sympa.conf").',
2233        format => '.+',
2234    },
2235
2236    spool => {
2237        context    => [qw(site)],
2238        order      => 54.00_03,
2239        group      => 'directories',
2240        default_s  => '$SPOOLDIR',
2241        gettext_id => 'Base directory of spools',
2242        gettext_comment =>
2243            'Base directory of all spools which are created at runtime. This directory must be writable by Sympa user.',
2244        format => '.+',
2245    },
2246    queue => {
2247        context    => [qw(site)],
2248        order      => 54.00_04,
2249        group      => 'directories',
2250        default_s  => '$SPOOLDIR/msg',
2251        gettext_id => 'Directory for message incoming spool',
2252        gettext_comment =>
2253            'This spool is used both by "queue" program and "sympa_msg.pl" daemon.',
2254        format => '.+',
2255    },
2256    queuemod => {
2257        context    => [qw(site)],
2258        order      => 54.00_05,
2259        group      => 'directories',
2260        default_s  => '$SPOOLDIR/moderation',
2261        gettext_id => 'Directory for moderation spool',
2262        format     => '.+',
2263    },
2264    queuedigest => {
2265        context    => [qw(site)],
2266        order      => 54.00_06,
2267        group      => 'directories',
2268        default_s  => '$SPOOLDIR/digest',
2269        gettext_id => 'Directory for digest spool',
2270        format     => '.+',
2271    },
2272    queueauth => {
2273        context    => [qw(site)],
2274        order      => 54.00_07,
2275        group      => 'directories',
2276        default_s  => '$SPOOLDIR/auth',
2277        gettext_id => 'Directory for held message spool',
2278        gettext_comment =>
2279            'This parameter is named such by historical reason.',
2280        format => '.+',
2281    },
2282    queueoutgoing => {
2283        context    => [qw(site)],
2284        order      => 54.00_08,
2285        group      => 'directories',
2286        default_s  => '$SPOOLDIR/outgoing',
2287        gettext_id => 'Directory for archive spool',
2288        gettext_comment =>
2289            'This parameter is named such by historical reason.',
2290        format => '.+',
2291    },
2292    queuesubscribe => {
2293        context    => [qw(site)],
2294        order      => 54.00_09,
2295        group      => 'directories',
2296        default_s  => '$SPOOLDIR/subscribe',
2297        gettext_id => 'Directory for held request spool',
2298        gettext_comment =>
2299            'This parameter is named such by historical reason.',
2300        format => '.+',
2301    },
2302    queuetopic => {
2303        context    => [qw(site)],
2304        order      => 54.00_10,
2305        group      => 'directories',
2306        default_s  => '$SPOOLDIR/topic',
2307        gettext_id => 'Directory for topic spool',
2308        format     => '.+',
2309    },
2310    queuebounce => {
2311        context    => [qw(site)],
2312        order      => 54.00_11,
2313        group      => 'directories',
2314        default_s  => '$SPOOLDIR/bounce',
2315        gettext_id => 'Directory for bounce incoming spool',
2316        gettext_comment =>
2317            'This spool is used both by "bouncequeue" program and "bounced.pl" daemon.',
2318        format => '.+',
2319    },
2320    queuetask => {
2321        context    => [qw(site)],
2322        order      => 54.00_12,
2323        group      => 'directories',
2324        default_s  => '$SPOOLDIR/task',
2325        gettext_id => 'Directory for task spool',
2326        format     => '.+',
2327    },
2328    queueautomatic => {
2329        context    => [qw(site)],
2330        order      => 54.00_13,
2331        group      => 'directories',
2332        default_s  => '$SPOOLDIR/automatic',
2333        gettext_id => 'Directory for automatic list creation spool',
2334        gettext_comment =>
2335            'This spool is used both by "familyqueue" program and "sympa_automatic.pl" daemon.',
2336        format => '.+',
2337    },
2338    queuebulk => {
2339        context    => [qw(site)],
2340        order      => 54.00_14,
2341        group      => 'directories',
2342        default_s  => '$SPOOLDIR/bulk',
2343        gettext_id => 'Directory for message outgoing spool',
2344        gettext_comment =>
2345            'This parameter is named such by historical reason.',
2346        format => '.+',
2347    },
2348    tmpdir => {
2349        context   => [qw(site)],
2350        order     => 54.00_15,
2351        group     => 'directories',
2352        default_s => '$SPOOLDIR/tmp',
2353        gettext_id =>
2354            'Temporary directory used by external programs such as virus scanner. Also, outputs to daemons\' standard error are redirected to the files under this directory.',
2355        format => '.+',
2356    },
2357    viewmail_dir => {
2358        context    => [qw(site)],
2359        order      => 54.00_16,
2360        group      => 'directories',
2361        default_s  => '$SPOOLDIR/viewmail',
2362        gettext_id => 'Directory to cache formatted messages',
2363        gettext_comment =>
2364            'Base directory path of directories where HTML view of messages are cached.',
2365        format => '.+',
2366    },
2367    bounce_path => {
2368        context    => [qw(site)],
2369        order      => 54.00_17,
2370        group      => 'directories',
2371        default_s  => '$BOUNCEDIR',
2372        gettext_id => 'Directory for storing bounces',
2373        file       => 'wwsympa.conf',
2374        gettext_comment =>
2375            "The directory where bounced.pl daemon will store the last bouncing message for each user. A message is stored in the file: <bounce_path>/<list name>\@<mail domain name>/<email address>, or, if tracking is enabled: <bounce_path>/<list name>\@<mail domain name>/<email address>_<envelope ID>.\nUsers can access to these messages using web interface in the bounce management page.\nDon't confuse with \"queuebounce\" parameter which defines the spool where incoming error reports are stored and picked by bounced.pl daemon.",
2376        format => '.+',
2377    },
2378
2379    arc_path => {
2380        context    => [qw(domain site)],
2381        order      => 54.00_18,
2382        group      => 'directories',
2383        default_s  => '$ARCDIR',
2384        gettext_id => 'Directory for storing archives',
2385        file       => 'wwsympa.conf',
2386        gettext_comment =>
2387            'Where to store HTML archives. This parameter is used by the "archived.pl" daemon. It is a good idea to install the archive outside the web document hierarchy to prevent overcoming of WWSympa\'s access control.',
2388        format => '.+',
2389    },
2390
2391    purge_spools_task => {
2392        context         => [qw(site)],
2393        order           => 54.00_20,
2394        group           => 'directories',
2395        gettext_id      => 'Task for cleaning spools',
2396        gettext_comment => 'This task cleans old content in spools.',
2397        default         => 'daily',
2398        task            => 'purge_spools',
2399    },
2400    clean_delay_queue => {
2401        context    => [qw(site)],
2402        order      => 54.00_21,
2403        group      => 'directories',
2404        gettext_id => 'Max age of incoming bad messages',
2405        gettext_comment =>
2406            'Number of days "bad" messages are kept in message incoming spool (as specified by "queue" parameter). Sympa keeps messages rejected for various reasons (badly formatted, looping etc.).',
2407        format       => '\d+',
2408        gettext_unit => 'days',
2409        default      => '7',
2410    },
2411    clean_delay_queueoutgoing => {
2412        context    => [qw(site)],
2413        order      => 54.00_22,
2414        group      => 'directories',
2415        gettext_id => 'Max age of bad messages for archives',
2416        gettext_comment =>
2417            'Number of days "bad" messages are kept in message archive spool (as specified by "queueoutgoing" parameter). Sympa keeps messages rejected for various reasons (unable to create archive directory, to copy file etc.).',
2418        format       => '\d+',
2419        gettext_unit => 'days',
2420        default      => '7',
2421    },
2422    clean_delay_queuebounce => {
2423        context    => [qw(site)],
2424        order      => 54.00_23,
2425        group      => 'directories',
2426        gettext_id => 'Max age of bad bounce messages',
2427        gettext_comment =>
2428            'Number of days "bad" messages are kept in bounce spool (as specified by "queuebounce" parameter). Sympa keeps messages rejected for various reasons (unknown original sender, unknown report type).',
2429        format       => '\d+',
2430        gettext_unit => 'days',
2431        default      => '7',
2432    },
2433    #clean_delay_queuemod
2434    clean_delay_queueauth => {
2435        context    => [qw(site)],
2436        order      => 54.00_25,
2437        group      => 'directories',
2438        gettext_id => 'Max age of held messages',
2439        gettext_comment =>
2440            'Number of days messages are kept in held message spool (as specified by "queueauth" parameter). Beyond this deadline, messages that have not been confirmed are deleted.',
2441        format       => '\d+',
2442        gettext_unit => 'days',
2443        default      => '30',
2444    },
2445    clean_delay_queuesubscribe => {
2446        context    => [qw(site)],
2447        order      => 54.00_26,
2448        group      => 'directories',
2449        gettext_id => 'Max age of held requests',
2450        gettext_comment =>
2451            'Number of days requests are kept in held request spool (as specified by "queuesubscribe" parameter). Beyond this deadline, requests that have not been validated nor declined are deleted.',
2452        format       => '\d+',
2453        gettext_unit => 'days',
2454        default      => '30',
2455    },
2456    clean_delay_queuetopic => {
2457        context    => [qw(site)],
2458        order      => 54.00_27,
2459        group      => 'directories',
2460        gettext_id => 'Max age of tagged topics',
2461        gettext_comment =>
2462            'Number of days (automatically or manually) tagged topics are kept in topic spool (as specified by "queuetopic" parameter). Beyond this deadline, tagging is forgotten.',
2463        format       => '\d+',
2464        gettext_unit => 'days',
2465        default      => '30',
2466    },
2467    clean_delay_queueautomatic => {
2468        context => [qw(site)],
2469        order   => 54.00_28,
2470        group   => 'directories',
2471        gettext_id =>
2472            'Max age of incoming bad messages in automatic list creation spool',
2473        gettext_comment =>
2474            'Number of days "bad" messages are kept in automatic list creation spool (as specified by "queueautomatic" parameter). Sympa keeps messages rejected for various reasons (badly formatted, looping etc.).',
2475        format       => '\d+',
2476        gettext_unit => 'days',
2477        default      => '10',
2478    },
2479    clean_delay_queuebulk => {
2480        context    => [qw(site)],
2481        order      => 54.00_29,
2482        group      => 'directories',
2483        gettext_id => 'Max age of outgoing bad messages',
2484        gettext_comment =>
2485            'Number of days "bad" messages are kept in message outgoing spool (as specified by "queuebulk" parameter). Sympa keeps messages rejected for various reasons (failed personalization, bad configuration on MTA etc.).',
2486        format       => '\d+',
2487        gettext_unit => 'days',
2488        default      => '7',
2489    },
2490    clean_delay_queuedigest => {
2491        context    => [qw(site)],
2492        order      => 54.00_30,
2493        group      => 'directories',
2494        gettext_id => 'Max age of bad messages in digest spool',
2495        gettext_comment =>
2496            'Number of days "bad" messages are kept in digest spool (as specified by "queuedigest" parameter). Sympa keeps messages rejected for various reasons (syntax errors in "digest.tt2" template etc.).',
2497        format       => '\d+',
2498        gettext_unit => 'days',
2499        default      => '14',
2500    },
2501    clean_delay_tmpdir => {
2502        context    => [qw(site)],
2503        order      => 54.00_31,
2504        group      => 'directories',
2505        gettext_id => 'Max age of temporary files',
2506        gettext_comment =>
2507            'Number of days files in temporary directory (as specified by "tmpdir" parameter), including standard error logs, are kept.',
2508        format       => '\d+',
2509        gettext_unit => 'days',
2510        default      => '7',
2511    },
2512
2513    ####### Sympa services: Optional features
2514
2515    ### S/MIME and TLS
2516
2517    cafile => {
2518        context    => [qw(site)],
2519        order      => 59.00_01,
2520        group      => 'crypto',
2521        gettext_id => 'File containing trusted CA certificates',
2522        gettext_comment =>
2523            'This can be used alternatively and/or additionally to "capath".',
2524        format => '.+',
2525    },
2526    capath => {
2527        context    => [qw(site)],
2528        order      => 59.00_02,
2529        group      => 'crypto',
2530        gettext_id => 'Directory containing trusted CA certificates',
2531        gettext_comment =>
2532            "CA certificates in this directory are used for client authentication.\nThe certificates need to have names including hash of subject, or symbolic links to them with such names. The links may be created by using \"c_rehash\" script bundled in OpenSSL.",
2533        format => '.+',
2534    },
2535    key_passwd => {
2536        context    => [qw(site)],
2537        order      => 59.00_03,
2538        group      => 'crypto',
2539        sample     => 'your_password',
2540        gettext_id => 'Password used to crypt lists private keys',
2541        gettext_comment =>
2542            'If not defined, Sympa assumes that list private keys are not encrypted.',
2543        format     => '.+',
2544        field_type => 'password',
2545    },
2546    key_password => {
2547        context  => [qw(site)],
2548        obsolete => 'key_passwd',
2549    },
2550    ssl_cert_dir => {
2551        context    => [qw(site)],
2552        order      => 59.00_04,
2553        group      => 'crypto',
2554        default_s  => '$EXPLDIR/X509-user-certs',
2555        gettext_id => 'Directory containing user certificates',
2556        format     => '.+',
2557    },
2558    # Not yet implemented
2559    #crl_dir => {
2560    #    context   => [qw(site)],
2561    #    order     => 59.00_05,
2562    #    group => 'crypto',
2563    #    default => Sympa::Constants::EXPLDIR . '/crl',
2564    #},
2565    #chk_cert_expiration_task => {
2566    #    context   => [qw(site)],
2567    #    order     => 59.00_06,
2568    #    group => 'crypto',
2569    #},
2570    #crl_update_task => {
2571    #    context   => [qw(site)],
2572    #    order     => 59.00_07,
2573    #    group => 'crypto',
2574    #},
2575
2576    ### Data sources page ###
2577
2578    inclusion_notification_feature => {
2579        context => [qw(list)],
2580        order   => 60.01,
2581        group   => 'data_source',
2582        gettext_id =>
2583            "Notify subscribers when they are included from a data source?",
2584        format     => ['on', 'off'],
2585        occurrence => '1',
2586        default    => 'off',
2587    },
2588
2589    member_include => {
2590        context    => [qw(list)],
2591        order      => 60.02,
2592        group      => 'data_source',
2593        gettext_id => 'Subscribers defined in an external data source',
2594        format     => {
2595            source => {
2596                context    => [qw(list)],
2597                order      => 1,
2598                gettext_id => 'the data source',
2599                datasource => 1,
2600                occurrence => '1'
2601            },
2602            source_parameters => {
2603                context    => [qw(list)],
2604                order      => 2,
2605                gettext_id => 'data source parameters',
2606                format     => '.*',
2607                occurrence => '0-1'
2608            },
2609        },
2610        occurrence => '0-n'
2611    },
2612
2613    owner_include => {
2614        context    => [qw(list)],
2615        order      => 60.02_1,
2616        group      => 'data_source',
2617        gettext_id => 'Owners defined in an external data source',
2618        format     => {
2619            source => {
2620                context    => [qw(list)],
2621                order      => 1,
2622                gettext_id => 'the data source',
2623                datasource => 1,
2624                occurrence => '1'
2625            },
2626            source_parameters => {
2627                context    => [qw(list)],
2628                order      => 2,
2629                gettext_id => 'data source parameters',
2630                format     => '.*',
2631                occurrence => '0-1'
2632            },
2633            profile => {
2634                context    => [qw(list)],
2635                order      => 3,
2636                gettext_id => 'profile',
2637                format     => ['privileged', 'normal'],
2638                occurrence => '1',
2639                default    => 'normal'
2640            },
2641            reception => {
2642                context    => [qw(list)],
2643                order      => 4,
2644                gettext_id => 'reception mode',
2645                format     => ['mail', 'nomail'],
2646                occurrence => '1',
2647                default    => 'mail'
2648            },
2649            visibility => {
2650                context    => [qw(list)],
2651                order      => 5,
2652                gettext_id => "visibility",
2653                format     => ['conceal', 'noconceal'],
2654                occurrence => '1',
2655                default    => 'noconceal'
2656            },
2657        },
2658        occurrence => '0-n'
2659    },
2660
2661    editor_include => {
2662        context    => [qw(list)],
2663        order      => 60.02_2,
2664        group      => 'data_source',
2665        gettext_id => 'Moderators defined in an external data source',
2666        format     => {
2667            source => {
2668                context    => [qw(list)],
2669                order      => 1,
2670                gettext_id => 'the data source',
2671                datasource => 1,
2672                occurrence => '1'
2673            },
2674            source_parameters => {
2675                context    => [qw(list)],
2676                order      => 2,
2677                gettext_id => 'data source parameters',
2678                format     => '.*',
2679                occurrence => '0-1'
2680            },
2681            reception => {
2682                context    => [qw(list)],
2683                order      => 3,
2684                gettext_id => 'reception mode',
2685                format     => ['mail', 'nomail'],
2686                occurrence => '1',
2687                default    => 'mail'
2688            },
2689            visibility => {
2690                context    => [qw(list)],
2691                order      => 5,
2692                gettext_id => "visibility",
2693                format     => ['conceal', 'noconceal'],
2694                occurrence => '1',
2695                default    => 'noconceal'
2696            }
2697        },
2698        occurrence => '0-n'
2699    },
2700
2701    sql_fetch_timeout => {
2702        context      => [qw(list site)],
2703        order        => 60.03,
2704        group        => 'data_source',
2705        gettext_id   => "Timeout for fetch of include_sql_query",
2706        gettext_unit => 'seconds',
2707        #gettext_id => 'Default of SQL fetch timeout',
2708        #gettext_comment =>
2709        #    'Default timeout while performing a fetch with include_sql_query.',
2710        format  => '\d+',
2711        length  => 6,
2712        default => '300',
2713    },
2714
2715    user_data_source => {
2716        context    => [qw(list)],
2717        group      => 'data_source',
2718        gettext_id => "User data source",
2719        format     => '\S+',
2720        default    => 'include2',
2721        obsolete   => 1,
2722    },
2723
2724    include_file => {
2725        context    => [qw(list)],
2726        order      => 60.04,
2727        group      => 'data_source',
2728        gettext_id => "File inclusion",
2729        gettext_comment =>
2730            'Include subscribers from this file.  The file should contain one e-mail address per line (lines beginning with a "#" are ignored).',
2731        format     => '\S+',
2732        occurrence => '0-n',
2733        length     => 20,
2734    },
2735
2736    include_remote_file => {
2737        context    => [qw(list)],
2738        order      => 60.05,
2739        group      => 'data_source',
2740        gettext_id => "Remote file inclusion",
2741        format     => {
2742            name => {
2743                context    => [qw(list)],
2744                order      => 1,
2745                gettext_id => "short name for this source",
2746                format     => '.+',
2747                length     => 50,
2748            },
2749            url => {
2750                context    => [qw(list)],
2751                order      => 2,
2752                gettext_id => "data location URL",
2753                format     => '.+',
2754                occurrence => '1',
2755                length     => 50
2756            },
2757            user => {
2758                context    => [qw(list)],
2759                order      => 3,
2760                gettext_id => "remote user",
2761                format     => '.+',
2762                occurrence => '0-1'
2763            },
2764            passwd => {
2765                context    => [qw(list)],
2766                order      => 4,
2767                gettext_id => "remote password",
2768                format     => '.+',
2769                field_type => 'password',
2770                occurrence => '0-1',
2771                length     => 10
2772            },
2773            timeout => {
2774                context      => [qw(list)],
2775                order        => 5,
2776                gettext_id   => "idle timeout",
2777                gettext_unit => 'seconds',
2778                format       => '\d+',
2779                length       => 6,
2780                default      => 180,
2781            },
2782            ssl_version => {
2783                context    => [qw(list)],
2784                order      => 6,
2785                gettext_id => 'SSL version',
2786                format     => [
2787                    'ssl_any', 'sslv2',   'sslv3', 'tlsv1',
2788                    'tlsv1_1', 'tlsv1_2', 'tlsv1_3'
2789                ],
2790                synonym    => {'tls' => 'tlsv1'},
2791                occurrence => '0-1',
2792                default    => 'ssl_any',
2793            },
2794            ssl_ciphers => {
2795                context    => [qw(list)],
2796                order      => 7,
2797                gettext_id => 'SSL ciphers used',
2798                format     => '.+',
2799                default    => 'ALL'
2800            },
2801            # ssl_cert # Use cert.pem in list directory
2802            # ssl_key  # Use private_key in list directory
2803
2804            # NOTE: The default of ca_verify is "none" that is different from
2805            #   include_ldap_query (required) or include_remote_sympa_list
2806            #   (optional).
2807            ca_verify => {
2808                context    => [qw(list)],
2809                order      => 8,
2810                gettext_id => 'Certificate verification',
2811                format     => ['none', 'optional', 'required'],
2812                synonym    => {'require' => 'required'},
2813                occurrence => '0-1',
2814                default    => 'none',
2815            },
2816            # ca_path # Not yet implemented
2817            # ca_file # Not yet implemented
2818
2819            nosync_time_ranges => {
2820                context    => [qw(list)],
2821                order      => 10,
2822                gettext_id => "Time ranges when inclusion is not allowed",
2823                format_s   => '$time_ranges',
2824                occurrence => '0-1'
2825            },
2826        },
2827        occurrence => '0-n'
2828    },
2829
2830    include_list => {
2831        context    => [qw(list)],
2832        group      => 'data_source',
2833        gettext_id => "List inclusion",
2834        format_s   => '$listname(\@$host)?(\s+filter\s+.+)?',
2835        occurrence => '0-n',
2836        obsolete   => 1,                                     # 2.2.6 - 6.2.15.
2837    },
2838
2839    include_sympa_list => {
2840        context    => [qw(list)],
2841        order      => 60.06,
2842        group      => 'data_source',
2843        gettext_id => "List inclusion",
2844        gettext_comment =>
2845            'Include subscribers from other list. All subscribers of list listname become subscribers of the current list. You may include as many lists as required, using one include_sympa_list paragraph for each included list. Any list at all may be included; you may therefore include lists which are also defined by the inclusion of other lists. Be careful, however, not to include list A in list B and then list B in list A, since this will give rise to an infinite loop.',
2846        format => {
2847            name => {
2848                context    => [qw(list)],
2849                order      => 1,
2850                gettext_id => "short name for this source",
2851                format     => '.+',
2852                length     => 50,
2853            },
2854            listname => {
2855                context    => [qw(list)],
2856                order      => 2,
2857                gettext_id => "list name to include",
2858                format_s   => '$listname(\@$host)?',
2859                occurrence => '1'
2860            },
2861            filter => {
2862                context    => [qw(list)],
2863                order      => 3,
2864                gettext_id => "filter definition",
2865                format     => '.*'
2866            },
2867            nosync_time_ranges => {
2868                context    => [qw(list)],
2869                order      => 4,
2870                gettext_id => "Time ranges when inclusion is not allowed",
2871                format_s   => '$time_ranges',
2872                occurrence => '0-1'
2873            },
2874        },
2875        occurrence => '0-n'
2876    },
2877
2878    include_remote_sympa_list => {
2879        context    => [qw(list)],
2880        order      => 60.07,
2881        group      => 'data_source',
2882        gettext_id => "remote list inclusion",
2883        gettext_comment =>
2884            "Sympa can contact another Sympa service using HTTPS to fetch a remote list in order to include each member of a remote list as subscriber. You may include as many lists as required, using one include_remote_sympa_list paragraph for each included list. Be careful, however, not to give rise to an infinite loop resulting from cross includes.\nFor this operation, one Sympa site acts as a server while the other one acs as client. On the server side, the only setting needed is to give permission to the remote Sympa to review the list. This is controlled by the review scenario.",
2885        format => {
2886            name => {
2887                context    => [qw(list)],
2888                order      => 1,
2889                gettext_id => "short name for this source",
2890                format     => '.+',
2891                length     => 50,
2892            },
2893            url => {
2894                context    => [qw(list)],
2895                order      => 2,
2896                gettext_id => "data location URL",
2897                format     => '.+',
2898                occurrence => '0-1',              # Backward compat. <= 6.2.44
2899                length     => 50
2900            },
2901            user => {
2902                context    => [qw(list)],
2903                order      => 3,
2904                gettext_id => "remote user",
2905                format     => '.+',
2906                occurrence => '0-1'
2907            },
2908            passwd => {
2909                context    => [qw(list)],
2910                order      => 4,
2911                gettext_id => "remote password",
2912                format     => '.+',
2913                field_type => 'password',
2914                occurrence => '0-1',
2915                length     => 10,
2916            },
2917            host => {
2918                context         => [qw(list)],
2919                order           => 4.5,
2920                gettext_id      => "remote host",
2921                gettext_comment => 'obsoleted.  Use "data location URL".',
2922                format_s        => '$host',
2923                occurrence      => '1'
2924            },
2925            port => {
2926                context         => [qw(list)],
2927                order           => 4.6,
2928                gettext_id      => "remote port",
2929                gettext_comment => 'obsoleted.  Use "data location URL".',
2930                format          => '\d+',
2931                default         => 443,
2932                length          => 4
2933            },
2934            path => {
2935                context         => [qw(list)],
2936                order           => 4.7,
2937                gettext_id      => "remote path of sympa list dump",
2938                gettext_comment => 'obsoleted.  Use "data location URL".',
2939                format          => '\S+',
2940                occurrence      => '1',
2941                length          => 20
2942            },
2943            cert => {
2944                context => [qw(list)],
2945                order   => 4.8,
2946                gettext_id =>
2947                    "certificate for authentication by remote Sympa",
2948                format   => ['robot', 'list'],
2949                default  => 'list',
2950                obsolete => 1,
2951            },
2952            timeout => {
2953                context      => [qw(list)],
2954                order        => 5,
2955                gettext_id   => "idle timeout",
2956                gettext_unit => 'seconds',
2957                format       => '\d+',
2958                length       => 6,
2959                default      => 180,
2960            },
2961            ssl_version => {
2962                context    => [qw(list)],
2963                order      => 6,
2964                gettext_id => 'SSL version',
2965                format     => [
2966                    'ssl_any', 'sslv2',   'sslv3', 'tlsv1',
2967                    'tlsv1_1', 'tlsv1_2', 'tlsv1_3'
2968                ],
2969                synonym    => {'tls' => 'tlsv1'},
2970                occurrence => '0-1',
2971                default    => 'ssl_any',
2972            },
2973            ssl_ciphers => {
2974                context    => [qw(list)],
2975                order      => 7,
2976                gettext_id => 'SSL ciphers used',
2977                format     => '.+',
2978                default    => 'ALL'
2979            },
2980            # ssl_cert # Use cert.pem in list directory
2981            # ssl_key  # Use private_key in list directory
2982
2983            # NOTE: The default of ca_verify is "none" that is different from
2984            #   include_ldap_query (required) or include_remote_file (none).
2985            ca_verify => {
2986                context    => [qw(list)],
2987                order      => 8,
2988                gettext_id => 'Certificate verification',
2989                format     => ['none', 'optional', 'required'],
2990                synonym    => {'require' => 'required'},
2991                occurrence => '0-1',
2992                default    => 'optional',
2993            },
2994            # ca_path # Not yet implemented
2995            # ca_file # Not yet implemented
2996
2997            nosync_time_ranges => {
2998                context    => [qw(list)],
2999                order      => 10,
3000                gettext_id => "Time ranges when inclusion is not allowed",
3001                format_s   => '$time_ranges',
3002                occurrence => '0-1'
3003            },
3004        },
3005        occurrence => '0-n'
3006    },
3007
3008    include_ldap_query => {
3009        context    => [qw(list)],
3010        order      => 60.08,
3011        group      => 'data_source',
3012        gettext_id => "LDAP query inclusion",
3013        gettext_comment =>
3014            'This paragraph defines parameters for a query returning a list of subscribers. This feature requires the Net::LDAP (perlldap) PERL module.',
3015        format => {
3016            name => {
3017                context    => [qw(list)],
3018                order      => 1,
3019                gettext_id => "short name for this source",
3020                format     => '.+',
3021                length     => 50,
3022            },
3023            host => {
3024                context    => [qw(list)],
3025                order      => 2,
3026                gettext_id => "remote host",
3027                format_s   => '$multiple_host_or_url',
3028                occurrence => '1'
3029            },
3030            port => {
3031                context    => [qw(list)],
3032                order      => 2.1,
3033                gettext_id => "remote port",
3034                format     => '\d+',
3035                obsolete   => 1,
3036                length     => 4
3037            },
3038            use_tls => {
3039                context    => [qw(list)],
3040                order      => 2.4,
3041                gettext_id => 'use TLS (formerly SSL)',
3042                format     => ['starttls', 'ldaps', 'none'],
3043                synonym    => {'yes' => 'ldaps', 'no' => 'none'},
3044                occurrence => '1',
3045                default    => 'none',
3046            },
3047            use_ssl => {
3048                context => [qw(list)],
3049                #order => 2.5,
3050                #gettext_id => 'use SSL (LDAPS)',
3051                #format => ['yes', 'no'],
3052                #default => 'no'
3053                obsolete => 'use_tls',    # 5.3a.2 - 6.2.14
3054            },
3055            ssl_version => {
3056                context    => [qw(list)],
3057                order      => 2.6,
3058                gettext_id => 'SSL version',
3059                format     => [
3060                    'sslv2',   'sslv3', 'tlsv1', 'tlsv1_1',
3061                    'tlsv1_2', 'tlsv1_3'
3062                ],
3063                synonym    => {'tls' => 'tlsv1'},
3064                occurrence => '1',
3065                default    => 'tlsv1'
3066            },
3067            ssl_ciphers => {
3068                context    => [qw(list)],
3069                order      => 2.7,
3070                gettext_id => 'SSL ciphers used',
3071                format     => '.+',
3072                default    => 'ALL',
3073            },
3074            # ssl_cert # Not yet implemented
3075            # ssl_key # Not yet implemented
3076            ca_verify => {
3077                context    => [qw(list)],
3078                order      => 2.8,
3079                gettext_id => 'Certificate verification',
3080                format     => ['none', 'optional', 'required'],
3081                synonym    => {'require' => 'required'},
3082                occurrence => '1',
3083                default    => 'required',
3084            },
3085            # ca_path # Not yet implemented
3086            # ca_file # Not yet implemented
3087            bind_dn => {
3088                context    => [qw(list)],
3089                order      => 3,
3090                gettext_id => "remote user",
3091                format     => '.+'
3092            },
3093            user => {
3094                context  => [qw(list)],
3095                obsolete => 'bind_dn'
3096            },
3097            bind_password => {
3098                context    => [qw(list)],
3099                order      => 3.5,
3100                gettext_id => "remote password",
3101                format     => '.+',
3102                field_type => 'password',
3103                length     => 10
3104            },
3105            passwd => {
3106                context  => [qw(list)],
3107                obsolete => 'bind_password'
3108            },
3109            suffix => {
3110                context    => [qw(list)],
3111                order      => 4,
3112                gettext_id => "suffix",
3113                format     => '.+'
3114            },
3115            scope => {
3116                context    => [qw(list)],
3117                order      => 5,
3118                gettext_id => "search scope",
3119                format     => ['base', 'one', 'sub'],
3120                occurrence => '1',
3121                default    => 'sub'
3122            },
3123            timeout => {
3124                context      => [qw(list)],
3125                order        => 6,
3126                gettext_id   => "connection timeout",
3127                gettext_unit => 'seconds',
3128                format       => '\w+',
3129                length       => 6,
3130                default      => 30
3131            },
3132            filter => {
3133                context    => [qw(list)],
3134                order      => 7,
3135                gettext_id => "filter",
3136                format     => '.+',
3137                occurrence => '1',
3138                length     => 50
3139            },
3140            attrs => {
3141                context    => [qw(list)],
3142                order      => 8,
3143                gettext_id => "extracted attribute",
3144                format_s   => '$ldap_attrdesc(\s*,\s*$ldap_attrdesc)?',
3145                default    => 'mail',
3146                length     => 50
3147            },
3148            select => {
3149                context    => [qw(list)],
3150                order      => 9,
3151                gettext_id => "selection (if multiple)",
3152                format     => ['all', 'first', 'regex'],
3153                occurrence => '1',
3154                default    => 'first'
3155            },
3156            regex => {
3157                context    => [qw(list)],
3158                order      => 10,
3159                gettext_id => "regular expression",
3160                format     => '.+',
3161                default    => '',
3162                length     => 50
3163            },
3164            nosync_time_ranges => {
3165                context    => [qw(list)],
3166                order      => 11,
3167                gettext_id => "Time ranges when inclusion is not allowed",
3168                format_s   => '$time_ranges',
3169                occurrence => '0-1'
3170            }
3171        },
3172        occurrence => '0-n'
3173    },
3174
3175    include_ldap_2level_query => {
3176        context    => [qw(list)],
3177        order      => 60.09,
3178        group      => 'data_source',
3179        gettext_id => "LDAP 2-level query inclusion",
3180        gettext_comment =>
3181            'This paragraph defines parameters for a two-level query returning a list of subscribers. Usually the first-level query returns a list of DNs and the second-level queries convert the DNs into e-mail addresses. This feature requires the Net::LDAP (perlldap) PERL module.',
3182        format => {
3183            name => {
3184                context    => [qw(list)],
3185                order      => 1,
3186                gettext_id => "short name for this source",
3187                format     => '.+',
3188                length     => 50,
3189            },
3190            host => {
3191                context    => [qw(list)],
3192                order      => 2,
3193                gettext_id => "remote host",
3194                format_s   => '$multiple_host_or_url',
3195                occurrence => '1'
3196            },
3197            port => {
3198                context    => [qw(list)],
3199                order      => 2.1,
3200                gettext_id => "remote port",
3201                format     => '\d+',
3202                obsolete   => 1,
3203                length     => 4
3204            },
3205            use_tls => {
3206                context    => [qw(list)],
3207                order      => 2.4,
3208                gettext_id => 'use TLS (formerly SSL)',
3209                format     => ['starttls', 'ldaps', 'none'],
3210                synonym    => {'yes' => 'ldaps', 'no' => 'none'},
3211                occurrence => '1',
3212                default    => 'none',
3213            },
3214            use_ssl => {
3215                context => [qw(list)],
3216                #order => 2.5,
3217                #gettext_id => 'use SSL (LDAPS)',
3218                #format => ['yes', 'no'],
3219                #default => 'no'
3220                obsolete => 'use_tls',    # 5.3a.2 - 6.2.14
3221            },
3222            ssl_version => {
3223                context    => [qw(list)],
3224                order      => 2.6,
3225                gettext_id => 'SSL version',
3226                format     => [
3227                    'sslv2',   'sslv3', 'tlsv1', 'tlsv1_1',
3228                    'tlsv1_2', 'tlsv1_3'
3229                ],
3230                synonym    => {'tls' => 'tlsv1'},
3231                occurrence => '1',
3232                default    => 'tlsv1'
3233            },
3234            ssl_ciphers => {
3235                context    => [qw(list)],
3236                order      => 2.7,
3237                gettext_id => 'SSL ciphers used',
3238                format     => '.+',
3239                default    => 'ALL'
3240            },
3241            # ssl_cert # Not yet implemented
3242            # ssl_key # Not yet implemented
3243            ca_verify => {
3244                context    => [qw(list)],
3245                order      => 2.8,
3246                gettext_id => 'Certificate verification',
3247                format     => ['none', 'optional', 'required'],
3248                synonym    => {'require' => 'required'},
3249                occurrence => '1',
3250                default    => 'required',
3251            },
3252            # ca_path # Not yet implemented
3253            # ca_file # Not yet implemented
3254            bind_dn => {
3255                context    => [qw(list)],
3256                order      => 3,
3257                gettext_id => "remote user",
3258                format     => '.+'
3259            },
3260            user => {
3261                context  => [qw(list)],
3262                obsolete => 'bind_dn'
3263            },
3264            bind_password => {
3265                context    => [qw(list)],
3266                order      => 3.5,
3267                gettext_id => "remote password",
3268                format     => '.+',
3269                field_type => 'password',
3270                length     => 10
3271            },
3272            passwd => {
3273                context  => [qw(list)],
3274                obsolete => 'bind_password'
3275            },
3276            suffix1 => {
3277                context    => [qw(list)],
3278                order      => 4,
3279                gettext_id => "first-level suffix",
3280                format     => '.+'
3281            },
3282            scope1 => {
3283                context    => [qw(list)],
3284                order      => 5,
3285                gettext_id => "first-level search scope",
3286                format     => ['base', 'one', 'sub'],
3287                default    => 'sub'
3288            },
3289            timeout1 => {
3290                context      => [qw(list)],
3291                order        => 6,
3292                gettext_id   => "first-level connection timeout",
3293                gettext_unit => 'seconds',
3294                format       => '\w+',
3295                length       => 6,
3296                default      => 30
3297            },
3298            filter1 => {
3299                context    => [qw(list)],
3300                order      => 7,
3301                gettext_id => "first-level filter",
3302                format     => '.+',
3303                occurrence => '1',
3304                length     => 50
3305            },
3306            attrs1 => {
3307                context    => [qw(list)],
3308                order      => 8,
3309                gettext_id => "first-level extracted attribute",
3310                format_s   => '$ldap_attrdesc',
3311                length     => 15
3312            },
3313            select1 => {
3314                context    => [qw(list)],
3315                order      => 9,
3316                gettext_id => "first-level selection",
3317                format     => ['all', 'first', 'regex'],
3318                occurrence => '1',
3319                default    => 'first'
3320            },
3321            regex1 => {
3322                context    => [qw(list)],
3323                order      => 10,
3324                gettext_id => "first-level regular expression",
3325                format     => '.+',
3326                default    => '',
3327                length     => 50
3328            },
3329            suffix2 => {
3330                context    => [qw(list)],
3331                order      => 11,
3332                gettext_id => "second-level suffix template",
3333                format     => '.+'
3334            },
3335            scope2 => {
3336                context    => [qw(list)],
3337                order      => 12,
3338                gettext_id => "second-level search scope",
3339                format     => ['base', 'one', 'sub'],
3340                occurrence => '1',
3341                default    => 'sub'
3342            },
3343            timeout2 => {
3344                context      => [qw(list)],
3345                order        => 13,
3346                gettext_id   => "second-level connection timeout",
3347                gettext_unit => 'seconds',
3348                format       => '\w+',
3349                length       => 6,
3350                default      => 30
3351            },
3352            filter2 => {
3353                context    => [qw(list)],
3354                order      => 14,
3355                gettext_id => "second-level filter template",
3356                format     => '.+',
3357                occurrence => '1',
3358                length     => 50
3359            },
3360            attrs2 => {
3361                context    => [qw(list)],
3362                order      => 15,
3363                gettext_id => "second-level extracted attribute",
3364                format_s   => '$ldap_attrdesc(\s*,\s*$ldap_attrdesc)?',
3365                default    => 'mail',
3366                length     => 50
3367            },
3368            select2 => {
3369                context    => [qw(list)],
3370                order      => 16,
3371                gettext_id => "second-level selection",
3372                format     => ['all', 'first', 'regex'],
3373                occurrence => '1',
3374                default    => 'first'
3375            },
3376            regex2 => {
3377                context    => [qw(list)],
3378                order      => 17,
3379                gettext_id => "second-level regular expression",
3380                format     => '.+',
3381                default    => '',
3382                length     => 50
3383            },
3384            nosync_time_ranges => {
3385                context    => [qw(list)],
3386                order      => 18,
3387                gettext_id => "Time ranges when inclusion is not allowed",
3388                format_s   => '$time_ranges',
3389                occurrence => '0-1'
3390            }
3391        },
3392        occurrence => '0-n'
3393    },
3394
3395    include_sql_query => {
3396        context    => [qw(list)],
3397        order      => 60.10,
3398        group      => 'data_source',
3399        gettext_id => "SQL query inclusion",
3400        gettext_comment =>
3401            'This parameter is used to define the SQL query parameters. ',
3402        format => {
3403            name => {
3404                context    => [qw(list)],
3405                order      => 1,
3406                gettext_id => "short name for this source",
3407                format     => '.+',
3408                length     => 50,
3409            },
3410            db_type => {
3411                context    => [qw(list)],
3412                order      => 1.5,
3413                gettext_id => "database type",
3414                format     => '\S+',
3415                occurrence => '1'
3416            },
3417            db_host => {
3418                context    => [qw(list)],
3419                order      => 2,
3420                gettext_id => "remote host",
3421                format_s   => '$host',
3422                # Not required for ODBC
3423                # occurrence => '1'
3424            },
3425            host => {
3426                context  => [qw(list)],
3427                obsolete => 'db_host'
3428            },
3429            db_port => {
3430                context    => [qw(list)],
3431                order      => 3,
3432                gettext_id => "database port",
3433                format     => '\d+'
3434            },
3435            db_name => {
3436                context    => [qw(list)],
3437                order      => 4,
3438                gettext_id => "database name",
3439                format     => '\S+',
3440                occurrence => '1'
3441            },
3442            db_options => {
3443                context    => [qw(list)],
3444                order      => 4,
3445                gettext_id => "connection options",
3446                format     => '.+'
3447            },
3448            connect_options => {
3449                context  => [qw(list)],
3450                obsolete => 'db_options'
3451            },
3452            db_env => {
3453                context    => [qw(list)],
3454                order      => 5,
3455                gettext_id => "environment variables for database connection",
3456                format     => '\w+\=\S+(;\w+\=\S+)*'
3457            },
3458            db_user => {
3459                context    => [qw(list)],
3460                order      => 6,
3461                gettext_id => "remote user",
3462                format     => '\S+',
3463                occurrence => '1'
3464            },
3465            user => {
3466                context  => [qw(list)],
3467                obsolete => 'db_user'
3468            },
3469            db_passwd => {
3470                context    => [qw(list)],
3471                order      => 7,
3472                gettext_id => "remote password",
3473                format     => '.+',
3474                field_type => 'password'
3475            },
3476            passwd => {
3477                context  => [qw(list)],
3478                obsolete => 'db_passwd'
3479            },
3480            sql_query => {
3481                context    => [qw(list)],
3482                order      => 8,
3483                gettext_id => "SQL query",
3484                format_s   => '$sql_query',
3485                occurrence => '1',
3486                length     => 50
3487            },
3488            f_dir => {
3489                context => [qw(list)],
3490                order   => 9,
3491                gettext_id =>
3492                    "Directory where the database is stored (used for DBD::CSV only)",
3493                format => '.+'
3494            },
3495            nosync_time_ranges => {
3496                context    => [qw(list)],
3497                order      => 10,
3498                gettext_id => "Time ranges when inclusion is not allowed",
3499                format_s   => '$time_ranges',
3500                occurrence => '0-1'
3501            }
3502        },
3503        occurrence => '0-n'
3504    },
3505
3506    ttl => {
3507        context    => [qw(list site)],
3508        order      => 60.12,
3509        group      => 'data_source',
3510        gettext_id => "Inclusions timeout",
3511        gettext_comment =>
3512            'Sympa caches user data extracted using the include parameter. Their TTL (time-to-live) within Sympa can be controlled using this parameter. The default value is 3600',
3513        #gettext_comment =>
3514        #    'Default timeout between two scheduled synchronizations of list members with data sources.',
3515        gettext_unit => 'seconds',
3516        format       => '\d+',
3517        default      => '3600',
3518        length       => 6
3519    },
3520
3521    distribution_ttl => {
3522        context => [qw(list)],      #FIXME: No site-wide default
3523        order   => 60.13,
3524        group   => 'data_source',
3525        gettext_id => "Inclusions timeout for message distribution",
3526        gettext_comment =>
3527            "This parameter defines the delay since the last synchronization after which the user's list will be updated before performing either of following actions:\n* Reviewing list members\n* Message distribution",
3528        gettext_unit => 'seconds',
3529        format       => '\d+',
3530        length       => 6
3531    },
3532
3533    include_ldap_ca => {
3534        context    => [qw(list)],
3535        order      => 60.14,
3536        group      => 'data_source',
3537        gettext_id => "LDAP query custom attribute",
3538        format     => {
3539            name => {
3540                context    => [qw(list)],
3541                order      => 1,
3542                gettext_id => "short name for this source",
3543                format     => '.+',
3544                length     => 50,
3545            },
3546            host => {
3547                context    => [qw(list)],
3548                order      => 2,
3549                gettext_id => "remote host",
3550                format_s   => '$multiple_host_or_url',
3551                occurrence => '1'
3552            },
3553            port => {
3554                context    => [qw(list)],
3555                order      => 2.1,
3556                gettext_id => "remote port",
3557                format     => '\d+',
3558                obsolete   => 1,
3559                length     => 4
3560            },
3561            use_tls => {
3562                context    => [qw(list)],
3563                order      => 2.4,
3564                gettext_id => 'use TLS (formerly SSL)',
3565                format     => ['starttls', 'ldaps', 'none'],
3566                synonym    => {'yes' => 'ldaps', 'no' => 'none'},
3567                occurrence => '1',
3568                default    => 'none',
3569            },
3570            use_ssl => {
3571                context => [qw(list)],
3572                #order => 2.5,
3573                #gettext_id => 'use SSL (LDAPS)',
3574                #format => ['yes', 'no'],
3575                #default => 'no'
3576                obsolete => 'use_tls',    # 6.2a? - 6.2.14
3577            },
3578            ssl_version => {
3579                context    => [qw(list)],
3580                order      => 2.6,
3581                gettext_id => 'SSL version',
3582                format     => [
3583                    'sslv2',   'sslv3', 'tlsv1', 'tlsv1_1',
3584                    'tlsv1_2', 'tlsv1_3'
3585                ],
3586                synonym    => {'tls' => 'tlsv1'},
3587                occurrence => '1',
3588                default    => 'tlsv1'
3589            },
3590            ssl_ciphers => {
3591                context    => [qw(list)],
3592                order      => 2.7,
3593                gettext_id => 'SSL ciphers used',
3594                format     => '.+',
3595                default    => 'ALL'
3596            },
3597            # ssl_cert # Not yet implemented
3598            # ssl_key # Not yet implemented
3599            ca_verify => {
3600                context    => [qw(list)],
3601                order      => 2.8,
3602                gettext_id => 'Certificate verification',
3603                format     => ['none', 'optional', 'required'],
3604                synonym    => {'require' => 'required'},
3605                occurrence => '1',
3606                default    => 'required',
3607            },
3608            # ca_path # Not yet implemented
3609            # ca_file # Not yet implemented
3610            bind_dn => {
3611                context    => [qw(list)],
3612                order      => 3,
3613                gettext_id => "remote user",
3614                format     => '.+'
3615            },
3616            user => {
3617                context  => [qw(list)],
3618                obsolete => 'bind_dn'
3619            },
3620            bind_password => {
3621                context    => [qw(list)],
3622                order      => 3.5,
3623                gettext_id => "remote password",
3624                format     => '.+',
3625                field_type => 'password',
3626                length     => 10
3627            },
3628            passwd => {
3629                context  => [qw(list)],
3630                obsolete => 'bind_password'
3631            },
3632            suffix => {
3633                context    => [qw(list)],
3634                order      => 4,
3635                gettext_id => "suffix",
3636                format     => '.+'
3637            },
3638            scope => {
3639                context    => [qw(list)],
3640                order      => 5,
3641                gettext_id => "search scope",
3642                format     => ['base', 'one', 'sub'],
3643                occurrence => '1',
3644                default    => 'sub'
3645            },
3646            timeout => {
3647                context      => [qw(list)],
3648                order        => 6,
3649                gettext_id   => "connection timeout",
3650                gettext_unit => 'seconds',
3651                format       => '\w+',
3652                length       => 6,
3653                default      => 30
3654            },
3655            filter => {
3656                context    => [qw(list)],
3657                order      => 7,
3658                gettext_id => "filter",
3659                format     => '.+',
3660                occurrence => '1',
3661                length     => 50
3662            },
3663            attrs => {
3664                context    => [qw(list)],
3665                order      => 8,
3666                gettext_id => "extracted attribute",
3667                format_s   => '$ldap_attrdesc(\s*,\s*$ldap_attrdesc)?',
3668                default    => 'mail',
3669                length     => 15
3670            },
3671            email_entry => {
3672                context    => [qw(list)],
3673                order      => 9,
3674                gettext_id => "Name of email entry",
3675                format     => '\S+',
3676                occurrence => '1'
3677            },
3678            select => {
3679                context    => [qw(list)],
3680                order      => 10,
3681                gettext_id => "selection (if multiple)",
3682                format     => ['all', 'first', 'regex'],
3683                occurrence => '1',
3684                default    => 'first'
3685            },
3686            regex => {
3687                context    => [qw(list)],
3688                order      => 11,
3689                gettext_id => "regular expression",
3690                format     => '.+',
3691                default    => '',
3692                length     => 50
3693            },
3694            nosync_time_ranges => {
3695                context    => [qw(list)],
3696                order      => 12,
3697                gettext_id => "Time ranges when inclusion is not allowed",
3698                format_s   => '$time_ranges',
3699                occurrence => '0-1'
3700            }
3701        },
3702        occurrence => '0-n'
3703    },
3704
3705    include_ldap_2level_ca => {
3706        context    => [qw(list)],
3707        order      => 60.15,
3708        group      => 'data_source',
3709        gettext_id => "LDAP 2-level query custom attribute",
3710        format     => {
3711            name => {
3712                context    => [qw(list)],
3713                format     => '.+',
3714                gettext_id => "short name for this source",
3715                length     => 50,
3716                order      => 1,
3717            },
3718            host => {
3719                context    => [qw(list)],
3720                order      => 2,
3721                gettext_id => "remote host",
3722                format_s   => '$multiple_host_or_url',
3723                occurrence => '1'
3724            },
3725            port => {
3726                context    => [qw(list)],
3727                order      => 2.1,
3728                gettext_id => "remote port",
3729                format     => '\d+',
3730                obsolete   => 1,
3731                length     => 4
3732            },
3733            use_tls => {
3734                context    => [qw(list)],
3735                order      => 2.4,
3736                gettext_id => 'use TLS (formerly SSL)',
3737                format     => ['starttls', 'ldaps', 'none'],
3738                synonym    => {'yes' => 'ldaps', 'no' => 'none'},
3739                occurrence => '1',
3740                default    => 'none',
3741            },
3742            use_ssl => {
3743                context => [qw(list)],
3744                #order => 2.5,
3745                #gettext_id => 'use SSL (LDAPS)',
3746                #format => ['yes', 'no'],
3747                #default => 'no'
3748                obsolete => 'use_tls',    # 6.2a? - 6.2.14
3749            },
3750            ssl_version => {
3751                context    => [qw(list)],
3752                order      => 2.6,
3753                gettext_id => 'SSL version',
3754                format     => [
3755                    'sslv2',   'sslv3', 'tlsv1', 'tlsv1_1',
3756                    'tlsv1_2', 'tlsv1_3'
3757                ],
3758                synonym    => {'tls' => 'tlsv1'},
3759                occurrence => '1',
3760                default    => 'tlsv1'
3761            },
3762            ssl_ciphers => {
3763                context    => [qw(list)],
3764                order      => 2.7,
3765                gettext_id => 'SSL ciphers used',
3766                format     => '.+',
3767                default    => 'ALL'
3768            },
3769            # ssl_cert # Not yet implemented
3770            # ssl_key # Not yet implemented
3771            ca_verify => {
3772                context    => [qw(list)],
3773                order      => 2.8,
3774                gettext_id => 'Certificate verification',
3775                format     => ['none', 'optional', 'required'],
3776                synonym    => {'require' => 'required'},
3777                occurrence => '1',
3778                default    => 'required',
3779            },
3780            # ca_path # Not yet implemented
3781            # ca_file # Not yet implemented
3782            bind_dn => {
3783                context    => [qw(list)],
3784                order      => 3,
3785                gettext_id => "remote user",
3786                format     => '.+',
3787            },
3788            user => {
3789                context  => [qw(list)],
3790                obsolete => 'bind_dn'
3791            },
3792            bind_password => {
3793                context    => [qw(list)],
3794                order      => 3.5,
3795                gettext_id => "remote password",
3796                format     => '.+',
3797                field_type => 'password',
3798                length     => 10
3799            },
3800            passwd => {
3801                context  => [qw(list)],
3802                obsolete => 'bind_password'
3803            },
3804            suffix1 => {
3805                context    => [qw(list)],
3806                order      => 4,
3807                gettext_id => "first-level suffix",
3808                format     => '.+'
3809            },
3810            scope1 => {
3811                context    => [qw(list)],
3812                order      => 5,
3813                gettext_id => "first-level search scope",
3814                format     => ['base', 'one', 'sub'],
3815                occurrence => '1',
3816                default    => 'sub'
3817            },
3818            timeout1 => {
3819                context      => [qw(list)],
3820                order        => 6,
3821                gettext_id   => "first-level connection timeout",
3822                gettext_unit => 'seconds',
3823                format       => '\w+',
3824                length       => 6,
3825                default      => 30
3826            },
3827            filter1 => {
3828                context    => [qw(list)],
3829                order      => 7,
3830                gettext_id => "first-level filter",
3831                format     => '.+',
3832                occurrence => '1',
3833                length     => 50
3834            },
3835            attrs1 => {
3836                context    => [qw(list)],
3837                order      => 8,
3838                gettext_id => "first-level extracted attribute",
3839                format_s   => '$ldap_attrdesc',
3840                length     => 15
3841            },
3842            select1 => {
3843                context    => [qw(list)],
3844                order      => 9,
3845                gettext_id => "first-level selection",
3846                format     => ['all', 'first', 'regex'],
3847                occurrence => '1',
3848                default    => 'first'
3849            },
3850            regex1 => {
3851                context    => [qw(list)],
3852                order      => 10,
3853                gettext_id => "first-level regular expression",
3854                format     => '.+',
3855                default    => '',
3856                length     => 50
3857            },
3858            suffix2 => {
3859                context    => [qw(list)],
3860                order      => 11,
3861                gettext_id => "second-level suffix template",
3862                format     => '.+'
3863            },
3864            scope2 => {
3865                context    => [qw(list)],
3866                order      => 12,
3867                gettext_id => "second-level search scope",
3868                format     => ['base', 'one', 'sub'],
3869                occurrence => '1',
3870                default    => 'sub'
3871            },
3872            timeout2 => {
3873                context      => [qw(list)],
3874                order        => 13,
3875                gettext_id   => "second-level connection timeout",
3876                gettext_unit => 'seconds',
3877                format       => '\w+',
3878                length       => 6,
3879                default      => 30
3880            },
3881            filter2 => {
3882                context    => [qw(list)],
3883                order      => 14,
3884                gettext_id => "second-level filter template",
3885                format     => '.+',
3886                occurrence => '1',
3887                length     => 50
3888            },
3889            attrs2 => {
3890                context    => [qw(list)],
3891                order      => 15,
3892                gettext_id => "second-level extracted attribute",
3893                format_s   => '$ldap_attrdesc',
3894                default    => 'mail',
3895                length     => 15
3896            },
3897            select2 => {
3898                context    => [qw(list)],
3899                order      => 16,
3900                gettext_id => "second-level selection",
3901                format     => ['all', 'first', 'regex'],
3902                occurrence => '1',
3903                default    => 'first'
3904            },
3905            regex2 => {
3906                context    => [qw(list)],
3907                order      => 17,
3908                gettext_id => "second-level regular expression",
3909                format     => '.+',
3910                default    => '',
3911                length     => 50
3912            },
3913            email_entry => {
3914                context    => [qw(list)],
3915                order      => 18,
3916                gettext_id => "Name of email entry",
3917                format     => '\S+',
3918                occurrence => '1'
3919            },
3920            nosync_time_ranges => {
3921                context    => [qw(list)],
3922                order      => 19,
3923                gettext_id => "Time ranges when inclusion is not allowed",
3924                format_s   => '$time_ranges',
3925                occurrence => '0-1'
3926            }
3927        },
3928        occurrence => '0-n'
3929    },
3930
3931    include_sql_ca => {
3932        context    => [qw(list)],
3933        order      => 60.16,
3934        group      => 'data_source',
3935        gettext_id => "SQL query custom attribute",
3936        format     => {
3937            name => {
3938                context    => [qw(list)],
3939                order      => 1,
3940                gettext_id => "short name for this source",
3941                format     => '.+',
3942                length     => 50,
3943            },
3944            db_type => {
3945                context    => [qw(list)],
3946                order      => 1.5,
3947                gettext_id => "database type",
3948                format     => '\S+',
3949                occurrence => '1'
3950            },
3951            db_host => {
3952                context    => [qw(list)],
3953                order      => 2,
3954                gettext_id => "remote host",
3955                format_s   => '$host',
3956                # Not required for ODBC and SQLite. Optional for Oracle.
3957                #occurrence => '1'
3958            },
3959            host => {
3960                context  => [qw(list)],
3961                obsolete => 'db_host'
3962            },
3963            db_port => {
3964                context    => [qw(list)],
3965                order      => 3,
3966                gettext_id => "database port",
3967                format     => '\d+'
3968            },
3969            db_name => {
3970                context    => [qw(list)],
3971                order      => 4,
3972                gettext_id => "database name",
3973                format     => '\S+',
3974                occurrence => '1'
3975            },
3976            db_options => {
3977                context    => [qw(list)],
3978                order      => 4.5,
3979                gettext_id => "connection options",
3980                format     => '.+'
3981            },
3982            connect_options => {
3983                context  => [qw(list)],
3984                obsolete => 'db_options'
3985            },
3986            db_env => {
3987                context    => [qw(list)],
3988                order      => 5,
3989                gettext_id => "environment variables for database connection",
3990                format     => '\w+\=\S+(;\w+\=\S+)*'
3991            },
3992            db_user => {
3993                context    => [qw(list)],
3994                order      => 6,
3995                gettext_id => "remote user",
3996                format     => '\S+',
3997                occurrence => '1'
3998            },
3999            user => {
4000                context  => [qw(list)],
4001                obsolete => 'db_user'
4002            },
4003            db_passwd => {
4004                context    => [qw(list)],
4005                order      => 7,
4006                gettext_id => "remote password",
4007                format     => '.+',
4008                field_type => 'password'
4009            },
4010            passwd => {
4011                context  => [qw(list)],
4012                obsolete => 'db_passwd'
4013            },
4014            sql_query => {
4015                context    => [qw(list)],
4016                order      => 8,
4017                gettext_id => "SQL query",
4018                format_s   => '$sql_query',
4019                occurrence => '1',
4020                length     => 50
4021            },
4022            f_dir => {
4023                context => [qw(list)],
4024                order   => 9,
4025                gettext_id =>
4026                    "Directory where the database is stored (used for DBD::CSV only)",
4027                format => '.+'
4028            },
4029            email_entry => {
4030                context    => [qw(list)],
4031                order      => 10,
4032                gettext_id => "Name of email entry",
4033                format     => '\S+',
4034                occurrence => '1'
4035            },
4036            nosync_time_ranges => {
4037                context    => [qw(list)],
4038                order      => 11,
4039                gettext_id => "Time ranges when inclusion is not allowed",
4040                format_s   => '$time_ranges',
4041                occurrence => '0-1'
4042            }
4043        },
4044        occurrence => '0-n'
4045    },
4046
4047    ### DKIM page ###
4048
4049    dkim_add_signature_to => {
4050        context    => [qw(domain site)],
4051        order      => 70.00_01,
4052        group      => 'dkim',
4053        default    => 'robot,list',
4054        gettext_id => 'Which service messages to be signed',
4055        gettext_comment =>
4056            'Inserts a DKIM signature to service messages in context of robot, list or both',
4057        format     => '(?:list|robot)(?:,(?:list|robot))*',    #FIXME
4058        split_char => ',',
4059    },
4060
4061    dkim_signer_identity => {    # Not derived by list config
4062        context         => [qw(domain site)],
4063        order           => 70.00_03,
4064        group           => 'dkim',
4065        gettext_id      => 'The "i=" tag as defined in rfc 4871',
4066        gettext_comment => 'Default is null.',
4067        format_s        => '\S+',
4068    },
4069
4070    dkim_feature => {
4071        context => [qw(domain site)],
4072        order   => 70.01,
4073        group   => 'dkim',
4074        #gettext_id => 'Enable DKIM',
4075        #gettext_comment =>
4076        #    "Enable/Disable DKIM. This feature requires Mail::DKIM to be installed, and maybe some custom scenario to be updated",
4077        gettext_id => "Insert DKIM signature to messages sent to the list",
4078        gettext_comment =>
4079            'If set to "on", Sympa may verify DKIM signatures of incoming messages and/or insert DKIM signature to outgoing messages.',
4080        format     => ['on', 'off'],
4081        occurrence => '1',
4082        default    => 'off',
4083    },
4084
4085    dkim_parameters => {
4086        context    => [qw(list domain site)],
4087        order      => 70.02,
4088        group      => 'dkim',
4089        gettext_id => "DKIM configuration",
4090        gettext_comment =>
4091            'A set of parameters in order to define outgoing DKIM signature',
4092        format => {
4093            private_key_path => {
4094                context => [qw(list domain site)],
4095                order   => 1,
4096                #gettext_id => "File path for list DKIM private key",
4097                #gettext_comment =>
4098                #    "The file must contain a RSA pem encoded private key",
4099                gettext_id => 'File path for DKIM private key',
4100                gettext_comment =>
4101                    'The file must contain a PEM encoded private key',
4102                format     => '\S+',
4103                occurrence => '0-1',
4104            },
4105            selector => {
4106                context    => [qw(list domain site)],
4107                order      => 2,
4108                gettext_id => "Selector for DNS lookup of DKIM public key",
4109                #gettext_comment =>
4110                #    "The selector is used in order to build the DNS query for public key. It is up to you to choose the value you want but verify that you can query the public DKIM key for <selector>._domainkey.your_domain",
4111                gettext_comment =>
4112                    'The selector is used in order to build the DNS query for public key. It is up to you to choose the value you want but verify that you can query the public DKIM key for "<selector>._domainkey.your_domain"',
4113                format     => '\S+',
4114                occurrence => '0-1',
4115            },
4116            header_list => {
4117                obsolete => 1,                        # Not yet implemented
4118                context  => [qw(list domain site)],
4119                order    => 4,
4120                gettext_id =>
4121                    'List of headers to be included into the message for signature',
4122                gettext_comment =>
4123                    'You should probably use the default value which is the value recommended by RFC4871',
4124                format     => '\S+',
4125                occurrence => '1-n',
4126                split_char => ':',                    #FIXME
4127                default =>
4128                    'from:sender:reply-to:subject:date:message-id:to:cc:list-id:list-help:list-unsubscribe:list-subscribe:list-post:list-owner:list-archive:in-reply-to:references:resent-date:resent-from:resent-sender:resent-to:resent-cc:resent-message-id:mime-version:content-type:content-transfer-encoding:content-id:content-description',
4129            },
4130            signer_domain => {
4131                context => [qw(list domain site)],
4132                order   => 5,
4133                gettext_id =>
4134                    'DKIM "d=" tag, you should probably use the default value',
4135                gettext_comment =>
4136                    'The DKIM "d=" tag, is the domain of the signing entity. The list domain MUST be included in the "d=" domain',
4137                #gettext_id => 'The "d=" tag as defined in rfc 4871',
4138                #gettext_comment =>
4139                #    'The DKIM "d=" tag is the domain of the signing entity. The virtual host domain name is used as its default value',
4140                format     => '\S+',
4141                occurrence => '0-1',
4142            },
4143            signer_identity => {
4144                context => [qw(list)],    # Not deriving domain conf
4145                order   => 6,
4146                gettext_id =>
4147                    'DKIM "i=" tag, you should probably leave this parameter empty',
4148                gettext_comment =>
4149                    'DKIM "i=" tag, you should probably not use this parameter, as recommended by RFC 4871, default for list brodcasted messages is i=<listname>-request@<domain>',
4150                format     => '\S+',
4151                occurrence => '0-1'
4152            },
4153        },
4154        occurrence => '0-1'
4155    },
4156
4157    dkim_signature_apply_on => {
4158        context => [qw(list domain site)],
4159        order   => 70.03,
4160        group   => 'dkim',
4161        gettext_id =>
4162            "The categories of messages sent to the list that will be signed using DKIM.",
4163        gettext_comment =>
4164            "This parameter controls in which case messages must be signed using DKIM, you may sign every message choosing 'any' or a subset. The parameter value is a comma separated list of keywords",
4165        #gettext_id => 'Which messages delivered via lists to be signed',
4166        #gettext_comment =>
4167        #    'Type of message that is added a DKIM signature before distribution to subscribers. Possible values are "none", "any" or a list of the following keywords: "md5_authenticated_messages", "smime_authenticated_messages", "dkim_authenticated_messages", "editor_validated_messages".',
4168        format => [
4169            'md5_authenticated_messages',  'smime_authenticated_messages',
4170            'dkim_authenticated_messages', 'editor_validated_messages',
4171            'none',                        'any'
4172        ],
4173        occurrence => '0-n',
4174        split_char => ',',
4175        default =>
4176            'md5_authenticated_messages,smime_authenticated_messages,dkim_authenticated_messages,editor_validated_messages',
4177    },
4178
4179    arc_feature => {
4180        context    => [qw(list domain site)],
4181        order      => 70.04,
4182        group      => 'dkim',
4183        gettext_id => "Add ARC seals to messages sent to the list",
4184        gettext_comment =>
4185            "Enable/Disable ARC. This feature requires Mail::DKIM::ARC to be installed, and maybe some custom scenario to be updated",
4186        #gettext_id => 'Enable ARC',
4187        #gettext_comment =>
4188        #    'If set to "on", Sympa may add ARC seals to outgoing messages.',
4189        format     => ['on', 'off'],
4190        occurrence => '1',
4191        default    => 'off',
4192    },
4193
4194    arc_srvid => {
4195        context    => [qw(domain site)],
4196        order      => 70.05,
4197        group      => 'dkim',
4198        gettext_id => 'SRV ID for Authentication-Results used in ARC seal',
4199        gettext_comment => 'Typically the domain of the mail server',
4200        format => '\S+',    # "value" defined in RFC 2045, 5.1
4201    },
4202
4203    arc_parameters => {
4204        context    => [qw(list domain site)],
4205        order      => 70.06,
4206        group      => 'dkim',
4207        gettext_id => "ARC configuration",
4208        gettext_comment =>
4209            'A set of parameters in order to define outgoing ARC seal',
4210        format => {
4211            arc_private_key_path => {
4212                context => [qw(list domain site)],
4213                order   => 1,
4214                #gettext_id => "File path for list ARC private key",
4215                #gettext_comment =>
4216                #    "The file must contain a RSA pem encoded private key. Default is DKIM private key.",
4217                gettext_id => 'File path for ARC private key',
4218                gettext_comment =>
4219                    'The file must contain a PEM encoded private key. Defaults to same file as DKIM private key',
4220                format     => '\S+',
4221                occurrence => '0-1',
4222            },
4223            arc_selector => {
4224                context    => [qw(list domain site)],
4225                order      => 2,
4226                gettext_id => "Selector for DNS lookup of ARC public key",
4227                #gettext_comment =>
4228                #    "The selector is used in order to build the DNS query for public key. It is up to you to choose the value you want but verify that you can query the public DKIM key for <selector>._domainkey.your_domain.  Default is selector for DKIM signature",
4229                gettext_comment =>
4230                    'The selector is used in order to build the DNS query for public key. It is up to you to choose the value you want but verify that you can query the public DKIM key for "<selector>._domainkey.your_domain". Default is the same selector as for DKIM signatures',
4231                format     => '\S+',
4232                occurrence => '0-1',
4233            },
4234            arc_signer_domain => {
4235                context => [qw(list domain site)],
4236                order   => 3,
4237                gettext_id =>
4238                    'ARC "d=" tag, you should probably use the default value',
4239                gettext_comment =>
4240                    'The ARC "d=" tag is the domain of the signing entity. The DKIM d= domain name is used as its default value',
4241                #gettext_id => 'The "d=" tag as defined in ARC',
4242                #gettext_comment =>
4243                #    'The ARC "d=" tag, is the domain of the sealing entity. The list domain MUST be included in the "d=" domain',
4244                format     => '\S+',
4245                occurrence => '0-1',
4246            },
4247        },
4248        occurrence => '0-1'
4249    },
4250
4251    dmarc_protection => {
4252        context => [qw(list domain site)],
4253        order   => 70.07,
4254        format  => {
4255            mode => {
4256                context => [qw(list domain site)],
4257                format  => [
4258                    'none',           'all',
4259                    'dkim_signature', 'dmarc_reject',
4260                    'dmarc_any',      'dmarc_quarantine',
4261                    'domain_regex'
4262                ],
4263                synonym => {
4264                    'dkim'         => 'dkim_signature',
4265                    'dkim_exists'  => 'dkim_signature',
4266                    'dmarc_exists' => 'dmarc_any',
4267                    'domain'       => 'domain_regex',
4268                    'domain_match' => 'domain_regex',
4269                },
4270                sample     => 'dmarc_reject,dkim_signature',
4271                gettext_id => "Protection modes",
4272                split_char => ',',
4273                occurrence => '0-n',
4274                gettext_comment =>
4275                    'Select one or more operation modes.  "Domain matching regular expression" (domain_regex) matches the specified Domain regular expression; "DKIM signature exists" (dkim_signature) matches any message with a DKIM signature header; "DMARC policy ..." (dmarc_*) matches messages from sender domains with a DMARC policy as given; "all" (all) matches all messages.',
4276                #gettext_id => 'Test mode(s) for DMARC Protection',
4277                #gettext_comment =>
4278                #    "Do not set unless you want to use DMARC protection.\nThis is a comma separated list of test modes; if multiple are selected then protection is activated if ANY match.  Do not use dmarc_* modes unless you have a local DNS cache as they do a DNS lookup for each received message.",
4279                order => 1
4280            },
4281            domain_regex => {
4282                context    => [qw(list domain site)],
4283                order      => 2,
4284                gettext_id => 'Regular expression for domain name match',
4285                gettext_comment =>
4286                    'Regular expression match pattern for From domain',
4287                #gettext_id => "Match domain regular expression",
4288                #gettext_comment =>
4289                #    'This is used for the "domain_regex" protection mode.',
4290                occurrence => '0-1',
4291                format     => '.+',
4292            },
4293            other_email => {
4294                context    => [qw(list domain site)],
4295                format     => '.+',
4296                gettext_id => "New From address",
4297                occurrence => '0-1',
4298                gettext_comment =>
4299                    'This is the email address to use when modifying the From header.  It defaults to the list address.  This is similar to Anonymisation but preserves the original sender details in the From address phrase.',
4300                order => 3,
4301            },
4302            phrase => {
4303                context => [qw(list domain site)],
4304                format  => [
4305                    'display_name',   'name_and_email',
4306                    'name_via_list',  'name_email_via_list',
4307                    'list_for_email', 'list_for_name',
4308                ],
4309                synonym =>
4310                    {'name' => 'display_name', 'prefixed' => 'list_for_name'},
4311                default    => 'name_via_list',
4312                gettext_id => "New From name format",
4313                occurrence => '0-1',
4314                #gettext_comment =>
4315                #    'This is the format to be used for the sender name part of the new From header.',
4316                gettext_comment =>
4317                    'This is the format to be used for the sender name part of the new From header field.',
4318                order => 4,
4319            },
4320        },
4321        gettext_id => "DMARC Protection",
4322        group      => 'dkim',
4323        gettext_comment =>
4324            "Parameters to define how to manage From address processing to avoid some domains' excessive DMARC protection",
4325        occurrence => '0-1',
4326    },
4327
4328    ### Optional features
4329
4330    ### List address verification
4331
4332    list_check_helo => {
4333        context => [qw(domain site)],
4334        order   => 72.00_01,
4335        group   => 'list_check',
4336        gettext_id =>
4337            'SMTP HELO (EHLO) parameter used for address verification',
4338        gettext_comment =>
4339            'Default value is the host part of "list_check_smtp" parameter.',
4340        format => '\S+',
4341    },
4342    list_check_smtp => {
4343        context => [qw(domain site)],
4344        order   => 72.00_02,
4345        group   => 'list_check',
4346        gettext_id =>
4347            'SMTP server to verify existence of the same addresses as the list to be created',
4348        gettext_comment =>
4349            "This is needed if you are running Sympa on a host but you handle all your mail on a separate mail relay.\nDefault value is real FQDN of the host. Port number may be specified as \"mail.example.org:25\" or \"203.0.113.1:25\".  If port is not specified, standard port (25) will be used.",
4350        format_s => '$hostport',
4351    },
4352    list_check_suffixes => {
4353        context    => [qw(domain site)],
4354        order      => 72.00_03,
4355        group      => 'list_check',
4356        gettext_id => 'Address suffixes to verify',
4357        gettext_comment =>
4358            "List of suffixes you are using for list addresses, i.e. \"mylist-request\", \"mylist-owner\" and so on.\nThis parameter is used with the \"list_check_smtp\" parameter. It is also used to check list names at list creation time.",
4359        format     => '\S+',                                          #FIXME
4360        default    => 'request,owner,editor,unsubscribe,subscribe',
4361        split_char => ',',
4362    },
4363
4364    ### Antivirus plug-in
4365
4366    antivirus_path => {
4367        context    => [qw(domain site)],
4368        order      => 73.00_01,
4369        group      => 'antivirus',
4370        sample     => '/usr/local/bin/clamscan',
4371        gettext_id => 'Path to the antivirus scanner engine',
4372        gettext_comment =>
4373            'Supported antivirus: Clam AntiVirus/clamscan & clamdscan, McAfee/uvscan, Fsecure/fsav, Sophos, AVP and Trend Micro/VirusWall',
4374        format => '.+',
4375    },
4376    antivirus_args => {
4377        context    => [qw(domain site)],
4378        order      => 73.00_02,
4379        group      => 'antivirus',
4380        sample     => '--no-summary --database /usr/local/share/clamav',
4381        gettext_id => 'Antivirus plugin command line arguments',
4382        format     => '.+',
4383    },
4384    antivirus_notify => {
4385        context => [qw(domain site)],
4386        order   => 73.00_03,
4387        group   => 'antivirus',
4388        gettext_id =>
4389            'Notify sender if virus checker detects malicious content',
4390        default => 'sender',
4391        gettext_comment =>
4392            '"sender" to notify originator of the message, "delivery_status" to send delivery status, or "none"',
4393        format => ['sender', 'delivery_status', 'none'],
4394    },
4395
4396    ### Miscelaneous page ###
4397
4398    email => {
4399        context    => [qw(domain site)],
4400        order      => 90.00_01,
4401        group      => 'other',
4402        default    => 'sympa',
4403        gettext_id => 'Local part of Sympa email address',
4404        gettext_comment =>
4405            "Local part (the part preceding the \"\@\" sign) of the address by which mail interface of Sympa accepts mail commands.\nIf you change the default value, you must modify the mail aliases too.",
4406        format => '\S+',
4407    },
4408    listmaster_email => {
4409        context    => [qw(domain site)],
4410        order      => 90.00_02,
4411        group      => 'other',
4412        default    => 'listmaster',
4413        gettext_id => 'Local part of listmaster email address',
4414        gettext_comment =>
4415            "Local part (the part preceding the \"\@\" sign) of the address by which listmasters receive messages.\nIf you change the default value, you must modify the mail aliases too.",
4416        format => '\S+',
4417    },
4418    custom_robot_parameter => {
4419        order      => 90.00_03,
4420        context    => [qw(domain site)],
4421        group      => 'other',
4422        gettext_id => 'Custom robot parameter',
4423        gettext_comment =>
4424            "Used to define a custom parameter for your server. Do not forget the semicolon between the parameter name and the parameter value.\nYou will be able to access the custom parameter value in web templates by variable \"conf.custom_robot_parameter.<param_name>\"",
4425        format     => '.+',
4426        sample     => 'param_name ; param_value',
4427        occurrence => '0-n',
4428    },
4429
4430    cache_list_config => {
4431        order      => 90.00_04,
4432        context    => [qw(site)],
4433        group      => 'other',
4434        default    => 'none',
4435        gettext_id => 'Use of binary cache of list configuration',
4436        gettext_comment =>
4437            "binary_file: Sympa processes will maintain a binary version of the list configuration, \"config.bin\" file on local disk. If you manage a big amount of lists (1000+), it should make the web interface startup faster.\nYou can recreate cache by running \"sympa.pl --reload_list_config\".",
4438        format => ['binary_file', 'none'],    #FIXME: "on"/"off" is better
4439    },
4440    db_list_cache => {
4441        order      => 90.00_05,
4442        context    => [qw(site)],
4443        group      => 'other',
4444        default    => 'off',
4445        gettext_id => 'Use database cache to search lists',
4446        gettext_comment =>
4447            "Note that \"list_table\" database table should be filled at the first time by running:\n  # sympa.pl --sync_list_db",
4448        format => ['on', 'off'],              #XXX
4449    },
4450    purge_user_table_task => {
4451        context    => [qw(site)],
4452        order      => 90.00_06,
4453        group      => 'other',
4454        gettext_id => 'Task for expiring inactive users',
4455        gettext_comment =>
4456            'This task removes rows in the "user_table" table which have not corresponding entries in the "subscriber_table" table.',
4457        default => 'monthly',
4458        task    => 'purge_user_table',
4459    },
4460    purge_logs_table_task => {
4461        context    => [qw(site)],
4462        order      => 90.00_07,
4463        group      => 'other',
4464        gettext_id => 'Task for cleaning tables',
4465        gettext_comment =>
4466            'This task cleans old logs from "logs_table" table.',
4467        default => 'daily',
4468        task    => 'purge_logs_table',
4469    },
4470    logs_expiration_period => {
4471        context    => [qw(site)],
4472        order      => 90.00_08,
4473        group      => 'other',
4474        gettext_id => 'Max age of logs in database',
4475        gettext_comment =>
4476            'Number of months that elapse before a log is expired',
4477        format       => '\d+',
4478        gettext_unit => 'months',
4479        default      => '3',
4480    },
4481    stats_expiration_period => {
4482        context    => [qw(site)],
4483        order      => 90.00_09,
4484        group      => 'other',
4485        gettext_id => 'Max age of statistics information in database',
4486        gettext_comment =>
4487            'Number of months that elapse before statistics information are expired',
4488        format       => '\d+',
4489        gettext_unit => 'months',
4490        default      => '3',
4491    },
4492
4493    umask => {
4494        context    => [qw(site)],
4495        order      => 90.00_10,
4496        group      => 'other',
4497        default    => '027',
4498        gettext_id => 'Umask',
4499        gettext_comment =>
4500            'Default mask for file creation (see umask(2)). Note that it will be interpreted as an octal value.',
4501        format     => '[0-7]+',
4502        occurrence => '1',
4503    },
4504
4505    ### Miscelaneous (list)
4506
4507    account => {
4508        context    => [qw(list)],
4509        group      => 'other',
4510        gettext_id => "Account",
4511        format     => '\S+',
4512        length     => 10,
4513        obsolete   => 1,
4514    },
4515
4516    clean_delay_queuemod => {
4517        context => [qw(list site)],
4518        order   => 90.01,
4519        group   => 'other',           # directories
4520        #gettext_id => "Expiration of unmoderated messages",
4521        gettext_id => 'Max age of moderated messages',
4522        gettext_comment =>
4523            'Number of days messages are kept in moderation spool (as specified by "queuemod" parameter). Beyond this deadline, messages that have not been processed are deleted.',
4524        gettext_unit => 'days',
4525        format       => '\d+',
4526        length       => 3,
4527        default      => '30',
4528    },
4529
4530    cookie => {
4531        context    => [qw(list site)],
4532        order      => 90.02,
4533        group      => 'other',
4534        sample     => '123456789',
4535        gettext_id => 'Secret string for generating unique keys',
4536        #gettext_comment =>
4537        #    'This parameter is a confidential item for generating authentication keys for administrative commands (ADD, DELETE, etc.). This parameter should remain concealed, even for owners. The cookie is applied to all list owners, and is only taken into account when the owner has the auth parameter.',
4538        gettext_comment =>
4539            "This allows generated authentication keys to differ from a site to another. It is also used for encryption of user passwords stored in the database. The presence of this string is one reason why access to \"sympa.conf\" needs to be restricted to the \"sympa\" user.\nNote that changing this parameter will break all HTTP cookies stored in users' browsers, as well as all user passwords and lists X509 private keys. To prevent a catastrophe, Sympa refuses to start if this \"cookie\" parameter was changed.",
4540        format     => '\S+',
4541        field_type => 'password',
4542        length     => 15,
4543        obsolete   => 1,
4544    },
4545
4546    custom_attribute => {
4547        context    => [qw(list)],
4548        order      => 90.03,
4549        group      => 'other',
4550        gettext_id => "Custom user attributes",
4551        format     => {
4552            id => {
4553                context    => [qw(list)],
4554                order      => 1,
4555                gettext_id => "internal identifier",
4556                format     => '\w+',
4557                occurrence => '1',
4558                length     => 20
4559            },
4560            name => {
4561                context    => [qw(list)],
4562                order      => 2,
4563                gettext_id => "label",
4564                format     => '.+',
4565                occurrence => '1',
4566                length     => 30
4567            },
4568            comment => {
4569                context    => [qw(list)],
4570                order      => 3,
4571                gettext_id => "additional comment",
4572                format     => '.+',
4573                length     => 100
4574            },
4575            type => {
4576                context    => [qw(list)],
4577                order      => 4,
4578                gettext_id => "type",
4579                format     => ['string', 'text', 'integer', 'enum'],
4580                default    => 'string',
4581                occurrence => 1
4582            },
4583            enum_values => {
4584                context    => [qw(list)],
4585                order      => 5,
4586                gettext_id => "possible attribute values (if enum is used)",
4587                format     => '.+',
4588                length     => 100
4589            },
4590            optional => {
4591                context    => [qw(list)],
4592                order      => 6,
4593                gettext_id => "is the attribute optional?",
4594                format     => ['required', 'optional'],
4595                default    => 'optional',
4596                occurrence => 1
4597            }
4598        },
4599        occurrence => '0-n'
4600    },
4601
4602    custom_vars => {
4603        context    => [qw(list)],
4604        order      => 90.04,
4605        group      => 'other',
4606        gettext_id => "custom parameters",
4607        format     => {
4608            name => {
4609                context    => [qw(list)],
4610                order      => 1,
4611                gettext_id => 'var name',
4612                format     => '\S+',
4613                occurrence => '1'
4614            },
4615            value => {
4616                context    => [qw(list)],
4617                order      => 2,
4618                gettext_id => 'var value',
4619                format     => '.+',
4620                occurrence => '1',
4621            }
4622        },
4623        occurrence => '0-n'
4624    },
4625
4626    expire_task => {
4627        context    => [qw(list)],
4628        order      => 90.05,
4629        group      => 'other',
4630        gettext_id => "Periodical subscription expiration task",
4631        gettext_comment =>
4632            "This parameter states which model is used to create an expire task. An expire task regularly checks the subscription or resubscription  date of subscribers and asks them to renew their subscription. If they don't they are deleted.",
4633        task     => 'expire',
4634        obsolete => 1,
4635    },
4636
4637    loop_prevention_regex => {
4638        context => [qw(list domain site)],
4639        order   => 90.06,
4640        group   => 'other',                  #loop_prevention
4641        gettext_id =>
4642            "Regular expression applied to prevent loops with robots",
4643        #gettext_id => 'Regular expression to prevent loop',
4644        gettext_comment =>
4645            'If the sender address matches the regular expression, then the message is rejected.',
4646        format  => '\S*',
4647        length  => 70,
4648        default => 'mailer-daemon|sympa|listserv|majordomo|smartlist|mailman',
4649    },
4650
4651    pictures_feature => {
4652        context => [qw(list domain site)],
4653        order   => 90.07,
4654        group   => 'other',                  #FIXME: www_other/pictures
4655        #gettext_id =>
4656        #    "Allow picture display? (must be enabled for the current robot)",
4657        gettext_id => 'Pictures',
4658        gettext_comment =>
4659            "Enables or disables the pictures feature by default.  If enabled, subscribers can upload their picture (from the \"Subscriber option\" page) to use as an avatar.\nPictures are stored in a directory specified by the \"static_content_path\" parameter.",
4660        format     => ['on', 'off'],
4661        occurrence => '1',
4662        default    => 'on',
4663    },
4664
4665    remind_task => {
4666        context    => [qw(list site)],
4667        order      => 90.08,
4668        group      => 'other',
4669        gettext_id => 'Periodical subscription reminder task',
4670        gettext_comment =>
4671            'This parameter states which model is used to create a remind task. A remind task regularly sends  subscribers a message which reminds them of their list subscriptions.',
4672        #gettext_comment =>
4673        #    'This task regularly sends subscribers a message which reminds them of their list subscriptions.',
4674        task => 'remind',
4675    },
4676
4677    ### Other (internal attributes of the list)
4678
4679    latest_instantiation => {
4680        context    => [qw(list)],
4681        order      => 99.01,
4682        group      => 'other',
4683        gettext_id => 'Latest family instantiation',
4684        format     => {
4685            email => {
4686                context    => [qw(list)],
4687                order      => 1,
4688                gettext_id => 'who ran the instantiation',
4689                format_s   => 'listmaster|$email',
4690                occurrence => '0-1'
4691            },
4692            date => {
4693                context => [qw(list)],
4694                #order => 2,
4695                obsolete   => 1,
4696                gettext_id => 'date',
4697                format     => '.+'
4698            },
4699            date_epoch => {
4700                context    => [qw(list)],
4701                order      => 3,
4702                gettext_id => 'date',
4703                format     => '\d+',
4704                field_type => 'unixtime',
4705                occurrence => '1',
4706                length     => 10,
4707            }
4708        },
4709        internal => 1
4710    },
4711
4712    creation => {
4713        context    => [qw(list)],
4714        order      => 99.02,
4715        group      => 'other',
4716        gettext_id => "Creation of the list",
4717        format     => {
4718            email => {
4719                context    => [qw(list)],
4720                order      => 1,
4721                gettext_id => "who created the list",
4722                format_s   => 'listmaster|$email',
4723                occurrence => '1'
4724            },
4725            date => {
4726                context => [qw(list)],
4727                #order => 2,
4728                obsolete   => 1,
4729                gettext_id => "human readable",
4730                format     => '.+'
4731            },
4732            date_epoch => {
4733                context    => [qw(list)],
4734                order      => 3,
4735                gettext_id => "date",
4736                format     => '\d+',
4737                field_type => 'unixtime',
4738                occurrence => '1',
4739                length     => 10,
4740            },
4741        },
4742        occurrence => '0-1',
4743        internal   => 1
4744    },
4745
4746    update => {
4747        context    => [qw(list)],
4748        order      => 99.03,
4749        group      => 'other',
4750        gettext_id => "Last update of config",
4751        format     => {
4752            email => {
4753                context    => [qw(list)],
4754                order      => 1,
4755                gettext_id => 'who updated the config',
4756                format_s   => '(listmaster|automatic|$email)',
4757                occurrence => '0-1',
4758                length     => 30
4759            },
4760            date => {
4761                context => [qw(list)],
4762                #order => 2,
4763                obsolete   => 1,
4764                gettext_id => 'date',
4765                format     => '.+',
4766                length     => 30
4767            },
4768            date_epoch => {
4769                context    => [qw(list)],
4770                order      => 3,
4771                gettext_id => 'date',
4772                format     => '\d+',
4773                field_type => 'unixtime',
4774                occurrence => '1',
4775                length     => 10,
4776            }
4777        },
4778        internal => 1,
4779    },
4780
4781    status => {
4782        context    => [qw(list)],
4783        order      => 99.04,
4784        group      => 'other',
4785        gettext_id => "Status of the list",
4786        format =>
4787            ['open', 'closed', 'pending', 'error_config', 'family_closed'],
4788        field_type => 'status',
4789        default    => 'open',
4790        internal   => 1
4791    },
4792
4793    serial => {
4794        context    => [qw(list)],
4795        order      => 99.05,
4796        group      => 'other',
4797        gettext_id => "Serial number of the config",
4798        format     => '\d+',
4799        default    => 0,
4800        internal   => 1,
4801        length     => 3
4802    },
4803
4804    # WWSympa: Basic configuration
4805
4806    wwsympa_url => {
4807        context    => [qw(domain site)],
4808        order      => 110.01,
4809        group      => 'www_basic',
4810        sample     => 'https://web.example.org/sympa',
4811        gettext_id => 'URL prefix of web interface',
4812        gettext_comment =>
4813            'This is used to construct URLs of web interface. The protocol (either https:// or http://) is required.',
4814    },
4815    wwsympa_url_local => {
4816        context    => [qw(domain site)],
4817        order      => 110.02,
4818        group      => 'www_basic',
4819        gettext_id => 'URL prefix of WWSympa behind proxy',
4820    },
4821    static_content_url => {
4822        context    => [qw(domain site)],
4823        order      => 110.03,
4824        group      => 'www_basic',
4825        default    => '/static-sympa',
4826        gettext_id => 'URL for static contents',
4827        gettext_comment =>
4828            'HTTP server have to map it with "static_content_path" directory.',
4829    },
4830    static_content_path => {
4831        context    => [qw(domain site)],
4832        order      => 110.04,
4833        group      => 'www_basic',
4834        default_s  => '$STATICDIR',
4835        gettext_id => 'Directory for static contents',
4836    },
4837    css_path => {
4838        context    => [qw(site)],
4839        order      => 110.05,
4840        group      => 'www_basic',
4841        default_s  => '$CSSDIR',
4842        gettext_id => 'Directory for static style sheets (CSS)',
4843        gettext_comment =>
4844            'After an upgrade, static CSS files are upgraded with the newly installed "css.tt2" template. Therefore, this is not a good place to store customized CSS files.',
4845    },
4846    css_url => {
4847        context    => [qw(site)],
4848        order      => 110.06,
4849        group      => 'www_basic',
4850        default    => '/static-sympa/css',
4851        gettext_id => 'URL for style sheets (CSS)',
4852        gettext_comment =>
4853            'To use auto-generated static CSS, HTTP server have to map it with "css_path".',
4854    },
4855    pictures_path => {
4856        context    => [qw(site)],
4857        order      => 110.07,
4858        group      => 'www_basic',
4859        default_s  => '$PICTURESDIR',
4860        gettext_id => 'Directory for subscribers pictures',
4861    },
4862    pictures_url => {
4863        context    => [qw(site)],
4864        order      => 110.08,
4865        group      => 'www_basic',
4866        default    => '/static-sympa/pictures',
4867        gettext_id => 'URL for subscribers pictures',
4868        gettext_comment =>
4869            'HTTP server have to map it with "pictures_path" directory.',
4870    },
4871    mhonarc => {
4872        context         => [qw(domain site)],
4873        order           => 110.10,
4874        group           => 'www_basic',
4875        default         => '/usr/bin/mhonarc',
4876        gettext_id      => 'Path to MHonArc mail-to-HTML converter',
4877        file            => 'wwsympa.conf',
4878        gettext_comment => 'This is required for HTML mail archiving.',
4879    },
4880    log_facility => {
4881        context    => [qw(site)],
4882        order      => 110.20,
4883        group      => 'www_basic',
4884        default    => 'LOCAL1',
4885        gettext_id => 'System log facility for web interface',
4886        gettext_comment =>
4887            'System log facility for WWSympa, archived.pl and bounced.pl. Default is to use value of "syslog" parameter.',
4888        file => 'wwsympa.conf',
4889    },
4890
4891    use_fast_cgi => {
4892        context    => [qw(site)],
4893        default    => '1',
4894        gettext_id => 'Enable FastCGI',
4895        file       => 'wwsympa.conf',
4896        gettext_comment =>
4897            'Is FastCGI module for HTTP server installed? This module provides a much faster web interface.',
4898        obsolete => 1,
4899    },
4900
4901    logo_html_definition => {
4902        context    => [qw(domain site)],
4903        order      => 120.01,
4904        group      => 'www_appearances',
4905        gettext_id => 'Custom logo',
4906        gettext_comment =>
4907            'HTML fragment to insert a logo in the page of web interface.',
4908        sample =>
4909            '<a href="http://www.example.com"><img style="float: left; margin-top: 7px; margin-left: 37px;" src="http://www.example.com/logos/mylogo.jpg" alt="My Company" /></a>',
4910    },
4911    favicon_url => {
4912        context         => [qw(domain site)],
4913        order           => 120.02,
4914        group           => 'www_appearances',
4915        gettext_id      => 'Custom favicon',
4916        gettext_comment => 'URL of favicon image',
4917    },
4918
4919    color_0 => {
4920        context    => [qw(domain site)],
4921        order      => 120.10,
4922        group      => 'www_appearances',
4923        gettext_id => 'Colors for web interface',
4924        gettext_comment =>
4925            'Colors are used in style sheet (CSS). They may be changed using web interface by listmasters.',
4926        default => '#f7f7f7',    # very light grey use in tables,
4927        db      => 'db_first',
4928    },
4929    color_1 => {
4930        context => [qw(domain site)],
4931        order   => 120.11,
4932        group   => 'www_appearances',
4933        default => '#222222',           # main menu button color,
4934        db      => 'db_first',
4935    },
4936    color_2 => {
4937        context => [qw(domain site)],
4938        order   => 120.12,
4939        group   => 'www_appearances',
4940        default => '#004b94',           # font color,
4941        db      => 'db_first',
4942    },
4943    color_3 => {
4944        context => [qw(domain site)],
4945        order   => 120.13,
4946        group   => 'www_appearances',
4947        default => '#5e5e5e',    # top boxe and footer box bacground color,
4948        db      => 'db_first',
4949    },
4950    color_4 => {
4951        context => [qw(domain site)],
4952        order   => 120.14,
4953        group   => 'www_appearances',
4954        default => '#4c4c4c',           #  page backgound color,
4955        db      => 'db_first',
4956    },
4957    color_5 => {
4958        context => [qw(domain site)],
4959        order   => 120.15,
4960        group   => 'www_appearances',
4961        default => '#0090e9',
4962        db      => 'db_first',
4963    },
4964    color_6 => {
4965        context => [qw(domain site)],
4966        order   => 120.16,
4967        group   => 'www_appearances',
4968        default => '#005ab2',           # list menu current button,
4969        db      => 'db_first',
4970    },
4971    color_7 => {
4972        context => [qw(domain site)],
4973        order   => 120.17,
4974        group   => 'www_appearances',
4975        default => '#ffffff',           # errorbackground color,
4976        db      => 'db_first',
4977    },
4978    color_8 => {
4979        context => [qw(domain site)],
4980        order   => 120.18,
4981        group   => 'www_appearances',
4982        default => '#f2f6f9',
4983        db      => 'db_first',
4984    },
4985    color_9 => {
4986        context => [qw(domain site)],
4987        order   => 120.19,
4988        group   => 'www_appearances',
4989        default => '#bfd2e1',
4990        db      => 'db_first',
4991    },
4992    color_10 => {
4993        context => [qw(domain site)],
4994        order   => 120.20,
4995        group   => 'www_appearances',
4996        default => '#983222',           # inactive button,
4997        db      => 'db_first',
4998    },
4999    color_11 => {
5000        context => [qw(domain site)],
5001        order   => 120.21,
5002        group   => 'www_appearances',
5003        default => '#66aaff',
5004        db      => 'db_first',
5005    },
5006    color_12 => {
5007        context => [qw(domain site)],
5008        order   => 120.22,
5009        group   => 'www_appearances',
5010        default => '#ffe7e7',
5011        db      => 'db_first',
5012    },
5013    color_13 => {
5014        context => [qw(domain site)],
5015        order   => 120.23,
5016        group   => 'www_appearances',
5017        default => '#f48a7b',           # input backgound  | transparent,
5018        db      => 'db_first',
5019    },
5020    color_14 => {
5021        context => [qw(domain site)],
5022        order   => 120.24,
5023        group   => 'www_appearances',
5024        default => '#ffff99',
5025        db      => 'db_first',
5026    },
5027    color_15 => {
5028        context => [qw(domain site)],
5029        order   => 120.25,
5030        group   => 'www_appearances',
5031        default => '#fe57a1',
5032        db      => 'db_first',
5033    },
5034    dark_color => {
5035        context    => [qw(domain site)],
5036        order      => 120.30,
5037        group      => 'www_appearances',
5038        gettext_id => 'Colors for web interface, obsoleted',
5039        default    => '#c0c0c0',                               # 'silver'
5040        db         => 'db_first',
5041    },
5042    light_color => {
5043        context => [qw(domain site)],
5044        order   => 120.31,
5045        group   => 'www_appearances',
5046        default => '#aaddff',
5047        db      => 'db_first',
5048    },
5049    text_color => {
5050        context => [qw(domain site)],
5051        order   => 120.32,
5052        group   => 'www_appearances',
5053        default => '#000000',
5054        db      => 'db_first',
5055    },
5056    bg_color => {
5057        context => [qw(domain site)],
5058        order   => 120.33,
5059        group   => 'www_appearances',
5060        default => '#ffffcc',
5061        db      => 'db_first',
5062    },
5063    error_color => {
5064        context => [qw(domain site)],
5065        order   => 120.34,
5066        group   => 'www_appearances',
5067        default => '#ff6666',
5068        db      => 'db_first',
5069    },
5070    selected_color => {
5071        context => [qw(domain site)],
5072        order   => 120.35,
5073        group   => 'www_appearances',
5074        default => '#c0c0c0',           # 'silver'
5075        db      => 'db_first',
5076    },
5077    shaded_color => {
5078        context => [qw(domain site)],
5079        order   => 120.36,
5080        group   => 'www_appearances',
5081        default => '#66cccc',
5082        db      => 'db_first',
5083    },
5084    default_home => {
5085        context    => [qw(domain site)],
5086        order      => 120.40,
5087        group      => 'www_appearances',
5088        default    => 'home',
5089        gettext_id => 'Type of main web page',
5090        gettext_comment =>
5091            '"lists" for the page of list of lists. "home" for home page.',
5092        file => 'wwsympa.conf',
5093    },
5094    archive_default_index => {
5095        context    => [qw(site)],
5096        order      => 120.41,
5097        group      => 'www_appearances',
5098        default    => 'thrd',
5099        gettext_id => 'Default index organization of web archive',
5100        gettext_comment =>
5101            "thrd: Threaded index.\nmail: Chronological index.",
5102        file => 'wwsympa.conf',
5103    },
5104    # { your_lists_size: not yet implemented. }
5105    review_page_size => {
5106        context    => [qw(domain site)],
5107        order      => 120.42,
5108        group      => 'www_appearances',
5109        gettext_id => 'Size of review page',
5110        gettext_comment =>
5111            'Default number of lines of the array displaying users in the review page',
5112        default => 25,
5113        file    => 'wwsympa.conf',
5114    },
5115    viewlogs_page_size => {
5116        context    => [qw(domain site)],
5117        order      => 120.43,
5118        group      => 'www_appearances',
5119        gettext_id => 'Size of viewlogs page',
5120        gettext_comment =>
5121            'Default number of lines of the array displaying the log entries in the logs page.',
5122        default => 25,
5123        file    => 'wwsympa.conf',
5124    },
5125    main_menu_custom_button_1_title => {
5126        context    => [qw(domain site)],
5127        order      => 120.51,
5128        group      => 'www_appearances',
5129        gettext_id => 'Custom menus',
5130        gettext_comment =>
5131            'You may modify the main menu content by editing the menu.tt2 file, but you can also edit these parameters in order to add up to 3 buttons. Each button is defined by a title (the text in the button), an URL and, optionally, a target.',
5132        sample => 'FAQ',
5133    },
5134    main_menu_custom_button_2_title => {
5135        context => [qw(domain site)],
5136        order   => 120.52,
5137        group   => 'www_appearances',
5138    },
5139    main_menu_custom_button_3_title => {
5140        context => [qw(domain site)],
5141        order   => 120.53,
5142        group   => 'www_appearances',
5143    },
5144    main_menu_custom_button_1_url => {
5145        context => [qw(domain site)],
5146        order   => 120.54,
5147        group   => 'www_appearances',
5148        sample  => 'http://www.renater.fr/faq/universalistes/index',
5149    },
5150    main_menu_custom_button_2_url => {
5151        context => [qw(domain site)],
5152        order   => 120.55,
5153        group   => 'www_appearances',
5154    },
5155    main_menu_custom_button_3_url => {
5156        context => [qw(domain site)],
5157        order   => 120.56,
5158        group   => 'www_appearances',
5159    },
5160    main_menu_custom_button_1_target => {
5161        context => [qw(domain site)],
5162        order   => 120.57,
5163        group   => 'www_appearances',
5164        sample  => 'Help',
5165    },
5166    main_menu_custom_button_2_target => {
5167        context => [qw(domain site)],
5168        order   => 120.58,
5169        group   => 'www_appearances',
5170    },
5171    main_menu_custom_button_3_target => {
5172        context => [qw(domain site)],
5173        order   => 120.59,
5174        group   => 'www_appearances',
5175    },
5176
5177    # Web interface: Session and cookie:
5178
5179    cookie_domain => {
5180        context    => [qw(domain site)],
5181        order      => 190.01,
5182        group      => 'www_other',
5183        default    => 'localhost',
5184        sample     => '.renater.fr',
5185        gettext_id => 'HTTP cookies validity domain',
5186        gettext_comment =>
5187            'If beginning with a dot ("."), the cookie is available within the specified Internet domain. Otherwise, for the specified host. The only reason for replacing the default value would be where WWSympa\'s authentication process is shared with an application running on another host.',
5188        file => 'wwsympa.conf',
5189    },
5190    cookie_expire => {
5191        context    => [qw(site)],
5192        order      => 190.02,
5193        group      => 'www_other',
5194        default    => '0',
5195        gettext_id => 'HTTP cookies lifetime',
5196        gettext_comment =>
5197            'This is the default value when not set explicitly by users. "0" means the cookie may be retained during browser sessions.',
5198        file => 'wwsympa.conf',
5199    },
5200    cookie_refresh => {
5201        context    => [qw(site)],
5202        order      => 190.03,
5203        group      => 'www_other',
5204        default    => '60',
5205        gettext_id => 'Average interval to refresh HTTP session ID.',
5206        file       => 'wwsympa.conf',
5207    },
5208    purge_session_table_task => {
5209        context    => [qw(site)],
5210        order      => 190.04,
5211        group      => 'www_other',
5212        gettext_id => 'Task for cleaning old sessions',
5213        gettext_comment =>
5214            'This task removes old entries in the "session_table" table.',
5215        default => 'daily',
5216        task    => 'purge_session_table',
5217    },
5218    session_table_ttl => {
5219        context    => [qw(site)],
5220        order      => 190.05,
5221        group      => 'www_other',
5222        gettext_id => 'Max age of sessions',
5223        gettext_comment =>
5224            "Session duration is controlled by \"sympa_session\" cookie validity attribute. However, by security reason, this delay also need to be controlled by server side. This task removes old entries in the \"session_table\" table.\nFormat of values is a string without spaces including \"y\" for years, \"m\" for months, \"d\" for days, \"h\" for hours, \"min\" for minutes and \"sec\" for seconds.",
5225        default => '2d',
5226    },
5227    anonymous_session_table_ttl => {
5228        context    => [qw(site)],
5229        order      => 190.06,
5230        group      => 'www_other',
5231        gettext_id => 'Max age of sessions for anonymous users',
5232        default    => '1h',
5233    },
5234
5235    # Shared document repository
5236
5237    shared_feature => {
5238        context    => [qw(domain site)],
5239        order      => 190.10,
5240        group      => 'www_other',
5241        format     => ['on', 'off'],                #XXX
5242        gettext_id => 'Enable shared repository',
5243        gettext_comment =>
5244            'If set to "on", list owners can open shared repository.',
5245        default => 'off',
5246    },
5247    #shared_doc
5248
5249    # HTML editor
5250
5251    htmlarea_url => {    # Deprecated on 6.2.36
5252        context    => [qw(site)],
5253        gettext_id => '',
5254        file       => 'wwsympa.conf',
5255        obsolete   => 1,
5256    },
5257    use_html_editor => {
5258        context    => [qw(domain site)],
5259        order      => 190.20,
5260        group      => 'www_other',
5261        gettext_id => 'Use HTML editor',
5262        gettext_comment =>
5263            'If set to "on", users will be able to post messages in HTML using a javascript WYSIWYG editor.',
5264        format  => ['off', 'on'],
5265        synonym => {'0' => 'off', '1' => 'on'},
5266        default => 'off',
5267        sample  => 'on',
5268        file    => 'wwsympa.conf',
5269    },
5270    html_editor_url => {
5271        context    => [qw(domain site)],
5272        order      => 190.21,
5273        group      => 'www_other',
5274        gettext_id => 'URL of HTML editor',
5275        gettext_comment =>
5276            "URL path to the javascript file making the WYSIWYG HTML editor available.  Relative path under <static_content_url> or absolute path.\nExample is for TinyMCE 4 installed under <static_content_path>/js/tinymce/.",
5277        sample => 'js/tinymce/tinymce.min.js',
5278    },
5279    html_editor_init => {
5280        context    => [qw(domain site)],
5281        order      => 190.22,
5282        group      => 'www_other',
5283        gettext_id => 'HTML editor initialization',
5284        gettext_comment =>
5285            'Javascript excerpt that enables and configures the WYSIWYG HTML editor.',
5286        sample =>
5287            'tinymce.init({selector:"#body",language:lang.split(/[^a-zA-Z]+/).join("_")});',
5288        file => 'wwsympa.conf',
5289    },
5290    ##{ html_editor_hide: not yet implemented. },
5291    ##{ html_editor_show: not yet implemented. },
5292
5293    # Password
5294
5295    max_wrong_password => {
5296        context    => [qw(domain site)],
5297        order      => 190.31,
5298        group      => 'www_other',
5299        gettext_id => 'Count limit of wrong password submission',
5300        gettext_comment =>
5301            'If this limit is reached, the account is locked until the user renews their password. The default value is chosen in order to block bots trying to log in using brute force strategy. This value should never be reached by real users that will probably uses the renew password service before they performs so many tries.',
5302        default => '19',
5303    },
5304    password_case => {
5305        context    => [qw(site)],        # per-robot config is impossible.
5306        order      => 190.32,
5307        group      => 'www_other',
5308        default    => 'insensitive',
5309        gettext_id => 'Password case',
5310        file       => 'wwsympa.conf',
5311        gettext_comment =>
5312            "\"insensitive\" or \"sensitive\".\nIf set to \"insensitive\", WWSympa's password check will be insensitive. This only concerns passwords stored in the Sympa database, not the ones in LDAP.\nShould not be changed! May invalid all user password.",
5313    },
5314    password_hash => {
5315        context => [qw(site)],           # per-robot config is impossible.
5316        order   => 190.33,
5317        group   => 'www_other',
5318        default => 'md5',
5319        gettext_id => 'Password hashing algorithm',
5320        file       => 'wwsympa.conf',
5321        gettext_comment =>
5322            "\"md5\" or \"bcrypt\".\nIf set to \"md5\", Sympa will use MD5 password hashes. If set to \"bcrypt\", bcrypt hashes will be used instead. This only concerns passwords stored in the Sympa database, not the ones in LDAP.\nShould not be changed! May invalid all user passwords.",
5323    },
5324    password_hash_update => {
5325        context => [qw(site)],           # per-robot config is impossible.
5326        order   => 190.34,
5327        group   => 'www_other',
5328        default => '1',
5329        gettext_id => 'Update password hashing algorithm when users log in',
5330        file       => 'wwsympa.conf',
5331        gettext_comment =>
5332            "On successful login, update the encrypted user password to use the algorithm specified by \"password_hash\". This allows for a graceful transition to a new password hash algorithm. A value of 0 disables updating of existing password hashes.  New and reset passwords will use the \"password_hash\" setting in all cases.",
5333    },
5334    bcrypt_cost => {
5335        context    => [qw(site)],           # per-robot config is impossible.
5336        order      => 190.35,
5337        group      => 'www_other',
5338        default    => '12',
5339        gettext_id => 'Bcrypt hash cost',
5340        file       => 'wwsympa.conf',
5341        gettext_comment =>
5342            "When \"password_hash\" is set to \"bcrypt\", this sets the \"cost\" parameter of the bcrypt hash function. The default of 12 is expected to require approximately 250ms to calculate the password hash on a 3.2GHz CPU. This only concerns passwords stored in the Sympa database, not the ones in LDAP.\nCan be changed but any new cost setting will only apply to new passwords.",
5343    },
5344
5345    # One time ticket
5346
5347    one_time_ticket_lifetime => {
5348        context         => [qw(site)],
5349        order           => 190.41,
5350        group           => 'www_other',
5351        default         => '2d',
5352        gettext_id      => 'Age of one time ticket',
5353        gettext_comment => 'Duration before the one time tickets are expired',
5354    },
5355    one_time_ticket_lockout => {
5356        context    => [qw(domain site)],
5357        order      => 190.42,
5358        group      => 'www_other',
5359        default    => 'one_time',
5360        gettext_id => 'Restrict access to one time ticket',
5361        gettext_comment =>
5362            'Is access to the one time ticket restricted, if any users previously accessed? (one_time | remote_addr | open)',
5363    },
5364    purge_one_time_ticket_table_task => {
5365        context    => [qw(site)],
5366        order      => 190.43,
5367        group      => 'www_other',
5368        gettext_id => 'Task for expiring old one time tickets',
5369        default    => 'daily',
5370        task       => 'purge_one_time_ticket_table',
5371    },
5372    one_time_ticket_table_ttl => {
5373        context    => [qw(site)],
5374        order      => 190.44,
5375        group      => 'www_other',
5376        gettext_id => 'Expiration period of one time ticket',
5377        default    => '10d',
5378    },
5379
5380    # Pictures
5381
5382    ##pictures_feature
5383
5384    pictures_max_size => {
5385        context      => [qw(domain site)],
5386        order        => 190.51,
5387        group        => 'www_other',
5388        gettext_id   => 'The maximum size of uploaded picture',
5389        gettext_unit => 'bytes',
5390        default      => 102400,                                   # 100 kiB
5391    },
5392
5393    # Protection against spam harvesters
5394
5395    spam_protection => {
5396        context => [qw(list domain site)],
5397        order   => 190.61,
5398        group   => 'www_other',
5399        #gettext_id => "email address protection method",
5400        gettext_id => 'Protect web interface against spam harvesters',
5401        gettext_comment =>
5402            "There is a need to protect Sympa web sites against spambots which collect email addresses from public web sites. Various methods are available in Sympa and you can choose to use them with the spam_protection and web_archive_spam_protection parameters. Possible value are:\njavascript: \nthe address is hidden using a javascript. A user who enables javascript can see a nice mailto address where others have nothing.\nat: \nthe \@ char is replaced by the string \" AT \".\nnone: \nno protection against spammer.",
5403        #gettext_comment =>
5404        #    "These values are supported:\njavascript: the address is hidden using a javascript. Users who enable Javascript can see nice mailto addresses where others have nothing.\nat: the \"\@\" character is replaced by the string \"AT\".\nnone: no protection against spam harvesters.",
5405        format     => ['at', 'javascript', 'none'],
5406        occurrence => '1',
5407        default    => 'javascript'
5408    },
5409    ##web_archive_spam_protection
5410    reporting_spam_script_path => {
5411        context    => [qw(domain site)],
5412        order      => 190.62,
5413        group      => 'www_other',
5414        gettext_id => 'Script to report spam',
5415        gettext_comment =>
5416            'If set, when a list moderator report undetected spams for list moderation, this external script is invoked and the message is injected into standard input of the script.',
5417    },
5418
5419    # Various miscellaneous
5420
5421    domains_blocklist => {
5422        context => [qw(site)],
5423        order   => 190.71,
5424        group   => 'www_other',
5425        gettext_id =>
5426            'Prevent people to subscribe to a list with adresses using these domains',
5427        gettext_comment => 'This parameter is a comma-separated list.',
5428        sample          => 'example.org,spammer.com',
5429        split_char      => ',',
5430    },
5431    domains_blacklist => {obsolete => 'domains_blocklist'},
5432
5433    quiet_subscription => {
5434        context    => [qw(site)],
5435        order      => 190.72,
5436        group      => 'www_other',
5437        gettext_id => 'Quiet subscriptions policy',
5438        gettext_comment =>
5439            'Global policy for quiet subscriptions: "on" means that subscriptions will never send a notice to the subscriber, "off" will enforce a notice sending, and "optional" (default) allows the use of the list policy.',
5440        format  => ['on', 'optional', 'off'],    #XXX
5441        default => 'optional',
5442    },
5443
5444    show_report_abuse => {
5445        context => [qw(site)],
5446        order   => 190.73,
5447        group   => 'www_other',
5448        gettext_id =>
5449            'Add a "Report abuse" link in the side menu of the lists',
5450        gettext_comment =>
5451            'The link is a mailto link, you can change that by overriding web_tt2/report_abuse.tt2',
5452        format  => ['on', 'off'],
5453        synonym => {'1' => 'on', '0' => 'off'},
5454        default => 'off',
5455    },
5456    allow_account_deletion => {
5457        context => [qw(site)],
5458        order   => 190.74,
5459        group   => 'www_other',
5460        gettext_id =>
5461            'EXPERIMENTAL! Allow users to delete their account. If enabled, shows a "delete my account" form in user\'s preferences page.',
5462        gettext_comment =>
5463            'Account deletion unsubscribes the users from his/her lists and removes him/her from lists ownership. It is only available to users using internal authentication (i.e. no LDAP, no SSO...). See https://github.com/sympa-community/sympa/issues/300 for details',
5464        format  => ['on', 'off'],
5465        synonym => {'1' => 'on', '0' => 'off'},
5466        default => 'off',
5467    },
5468
5469    # Web interface: Optional features
5470
5471    password_validation => {
5472        context    => [qw(site)],
5473        order      => 153.01,
5474        group      => 'password_validation',
5475        gettext_id => 'Password validation',
5476        gettext_comment =>
5477            'The password validation techniques to be used against user passwords that are added to mailing lists. Options come from Data::Password (http://search.cpan.org/~razinf/Data-Password-1.07/Password.pm#VARIABLES)',
5478        sample =>
5479            'MINLEN=8,GROUPS=3,DICTIONARY=4,DICTIONARIES=/pentest/dictionaries',
5480    },
5481
5482    ldap_force_canonical_email => {
5483        context    => [qw(domain site)],
5484        order      => 154.01,
5485        group      => 'ldap_auth',
5486        default    => '1',
5487        gettext_id => 'Use canonical email address for LDAP authentication',
5488        gettext_comment =>
5489            'When using LDAP authentication, if the identifier provided by the user was a valid email, if this parameter is set to false, then the provided email will be used to authenticate the user. Otherwise, use of the first email returned by the LDAP server will be used.',
5490        file => 'wwsympa.conf',
5491    },
5492
5493    soap_url => {
5494        context    => [qw(domain site)],
5495        order      => 156.01,
5496        group      => 'sympasoap',
5497        sample     => 'http://web.example.org/sympasoap',
5498        gettext_id => 'URL of SympaSOAP',
5499        gettext_comment =>
5500            'WSDL document of SympaSOAP refers to this URL in its service section.',
5501    },
5502    soap_url_local => {
5503        context    => [qw(domain site)],
5504        order      => 156.02,
5505        group      => 'sympasoap',
5506        gettext_id => 'URL of SympaSOAP behind proxy',
5507    },
5508
5509    #### End of living parameters ####
5510
5511    ## Parameters which have not been implemented yet.
5512    #purge_challenge_table_task => {
5513    #    default => 'daily',
5514    #},
5515    #challenge_table_ttl => {
5516    #    default => '5d',
5517    #},
5518
5519    #FIXME: Probablly not available now.
5520    automatic_list_prefix => {
5521        context => [qw(site)],
5522        gettext_id =>
5523            'Defines the prefix allowing to recognize that a list is an automatic list.',
5524        obsolete => 1,    # Maybe not used
5525    },
5526    default_distribution_ttl => {
5527        context => [qw(site)],
5528        gettext_id =>
5529            'Default timeout between two action-triggered synchronizations of list members with data sources.',
5530        default  => '300',
5531        obsolete => 1,       # Maybe not used
5532    },
5533    edit_list => {
5534        context  => [qw(site)],
5535        default  => 'owner',
5536        obsolete => 1,            # Maybe not used
5537    },
5538
5539    ## Obsoleted parameters
5540
5541    trusted_ca_options             => $site_obsolete,    # cf. capath & cafile
5542    msgcat                         => $site_obsolete,
5543    queueexpire                    => $site_obsolete,
5544    clean_delay_queueother         => $site_obsolete,
5545    web_recode_to                  => $site_obsolete,    # ??? - 5.2
5546    localedir                      => $site_obsolete,
5547    ldap_export_connection_timeout => $site_obsolete,    # 3.3b3 - 4.1?
5548    ldap_export_dnmanager          => $site_obsolete,    # ,,
5549    ldap_export_host               => $site_obsolete,    # ,,
5550    ldap_export_name               => $site_obsolete,    # ,,
5551    ldap_export_password           => $site_obsolete,    # ,,
5552    ldap_export_suffix             => $site_obsolete,    # ,,
5553    tri                            => $site_obsolete,    # ??? - 1.3.4-1
5554    sort                           => $site_obsolete,    # 1.4.0 - ???
5555    pidfile                        => $site_obsolete,    # ??? - 6.1.17
5556    pidfile_distribute             => $site_obsolete,    # ,,
5557    pidfile_creation               => $site_obsolete,    # ,,
5558    pidfile_bulk                   => $site_obsolete,    # ,,
5559    archived_pidfile               => $site_obsolete,    # ,,
5560    bounced_pidfile                => $site_obsolete,    # ,,
5561    task_manager_pidfile           => $site_obsolete,    # ,,
5562    email_gecos                    => $site_obsolete,    # 6.2a.?? - 6.2a.33
5563    lock_method                    => $site_obsolete,    # 5.3b.3 - 6.2a.33
5564    html_editor_file               => $site_obsolete,    # 6.2a
5565    openssl                        => $site_obsolete,    # ?? - 6.2a.40
5566    distribution_mode              => $site_obsolete,    # 5.0a.1 - 6.2a.40
5567    queuedistribute                => $site_obsolete,    # ,,
5568
5569    log_condition => {
5570        context  => [qw(domain site)],
5571        file     => 'wwsympa.conf',
5572        obsolete => 1,                                   # 6.2a.29 - 6.2.41b.1
5573    },
5574    log_module => {
5575        context  => [qw(domain site)],
5576        file     => 'wwsympa.conf',
5577        obsolete => 1,                                   # 6.2a.29 - 6.2.41b.1
5578    },
5579    filesystem_encoding => {
5580        context  => [qw(site)],
5581        default  => 'utf-8',
5582        obsolete => 1,                                   # 5.3a.7 - 6.2.52
5583    },
5584    http_host => {
5585        context  => [qw(domain site)],
5586        obsolete => 1,                                   # ?? - 6.2.54
5587    },
5588
5589);
5590
5591our %user_info = (
5592    owner => {
5593        order      => 10.03,
5594        group      => 'description',
5595        gettext_id => "Owners",
5596        gettext_comment =>
5597            'Owners are managing subscribers of the list. They may review subscribers and add or delete email addresses from the mailing list. If you are a privileged owner of the list, you can choose other owners for the mailing list. Privileged owners may edit a few more options than other owners. ',
5598        format => {
5599            profile => {
5600                order      => 1,
5601                gettext_id => "profile",
5602                format     => ['privileged', 'normal'],
5603                occurrence => '1',
5604                default    => 'normal'
5605            },
5606            email => {
5607                order       => 2,
5608                gettext_id  => "email address",
5609                format_s    => '$email',
5610                occurrence  => '1',
5611                length      => 30,
5612                filters     => ['canonic_email'],
5613                validations => [
5614                    qw(list_address list_special_addresses unique_paragraph_key)
5615                ],
5616            },
5617            gecos => {
5618                order      => 3,
5619                gettext_id => "name",
5620                format     => '.+',
5621                length     => 30
5622            },
5623            reception => {
5624                order      => 4,
5625                gettext_id => "reception mode",
5626                format     => ['mail', 'nomail'],
5627                occurrence => '1',
5628                default    => 'mail'
5629            },
5630            visibility => {
5631                order      => 5,
5632                gettext_id => "visibility",
5633                format     => ['conceal', 'noconceal'],
5634                occurrence => '1',
5635                default    => 'noconceal'
5636            },
5637            info => {
5638                order      => 6,
5639                gettext_id => "private information",
5640                format     => '.+',
5641                length     => 30
5642            },
5643            subscribed => {
5644                order      => 11,
5645                gettext_id => 'subscribed',
5646                format     => ['0', '1'],
5647                occurrence => '1',
5648                default    => '1',
5649                internal   => 1,
5650            },
5651            included => {
5652                #order      => 12,
5653                obsolete   => 1,
5654                gettext_id => 'included',
5655                format     => ['0', '1'],
5656                occurrence => '1',
5657                default    => '0',
5658                internal   => 1,
5659            },
5660            id => {
5661                #order      => 13,
5662                obsolete   => 1,
5663                gettext_id => 'name of external datasource',
5664                internal   => 1,
5665            },
5666            date => {
5667                order      => 14,
5668                gettext_id => 'delegated since',
5669                format     => '\d+',
5670                field_type => 'unixtime',
5671                internal   => 1,
5672            },
5673            update_date => {
5674                order      => 14.5,
5675                gettext_id => 'last update time',
5676                format     => '\d+',
5677                field_type => 'unixtime',
5678                internal   => 1,
5679            },
5680            inclusion => {
5681                order      => 14.6,
5682                gettext_id => 'last inclusion time',
5683                format     => '\d+',
5684                field_type => 'unixtime',
5685                internal   => 1,
5686            },
5687            inclusion_ext => {
5688                order      => 14.7,
5689                gettext_id => 'last inclusion time from external data source',
5690                format     => '\d+',
5691                field_type => 'unixtime',
5692                internal   => 1,
5693            },
5694        },
5695        occurrence => '1-n'
5696    },
5697
5698    editor => {
5699        order      => 10.05,
5700        group      => 'description',
5701        gettext_id => "Moderators",
5702        gettext_comment =>
5703            "Moderators are responsible for moderating messages. If the mailing list is moderated, messages posted to the list will first be passed to the moderators, who will decide whether to distribute or reject it.\nFYI: Defining moderators will not make the list moderated; you will have to set the \"send\" parameter.\nFYI: If the list is moderated, any moderator can distribute or reject a message without the knowledge or consent of the other moderators. Messages that have not been distributed or rejected will remain in the moderation spool until they are acted on.",
5704        format => {
5705            email => {
5706                order       => 1,
5707                gettext_id  => "email address",
5708                format_s    => '$email',
5709                occurrence  => '1',
5710                length      => 30,
5711                filters     => ['canonic_email'],
5712                validations => [
5713                    qw(list_address list_editor_address unique_paragraph_key)
5714                ],
5715            },
5716            gecos => {
5717                order      => 2,
5718                gettext_id => "name",
5719                format     => '.+',
5720                length     => 30
5721            },
5722            reception => {
5723                order      => 3,
5724                gettext_id => "reception mode",
5725                format     => ['mail', 'nomail'],
5726                occurrence => '1',
5727                default    => 'mail'
5728            },
5729            visibility => {
5730                order      => 4,
5731                gettext_id => "visibility",
5732                format     => ['conceal', 'noconceal'],
5733                occurrence => '1',
5734                default    => 'noconceal'
5735            },
5736            info => {
5737                order      => 5,
5738                gettext_id => "private information",
5739                format     => '.+',
5740                length     => 30
5741            },
5742            subscribed => {
5743                order      => 11,
5744                gettext_id => 'subscribed',
5745                format     => ['0', '1'],
5746                occurrence => '1',
5747                default    => '1',
5748                internal   => 1,
5749            },
5750            included => {
5751                #order      => 12,
5752                obsolete   => 1,
5753                gettext_id => 'included',
5754                format     => ['0', '1'],
5755                occurrence => '1',
5756                default    => '0',
5757                internal   => 1,
5758            },
5759            id => {
5760                #order      => 13,
5761                obsolete   => 1,
5762                gettext_id => 'name of external datasource',
5763                internal   => 1,
5764            },
5765            date => {
5766                order      => 14,
5767                gettext_id => 'delegated since',
5768                format     => '\d+',
5769                field_type => 'unixtime',
5770                internal   => 1,
5771            },
5772            update_date => {
5773                order      => 14.5,
5774                gettext_id => 'last update time',
5775                format     => '\d+',
5776                field_type => 'unixtime',
5777                internal   => 1,
5778            },
5779            inclusion => {
5780                order      => 14.6,
5781                gettext_id => 'last inclusion time',
5782                format     => '\d+',
5783                field_type => 'unixtime',
5784                internal   => 1,
5785            },
5786            inclusion_ext => {
5787                order      => 14.7,
5788                gettext_id => 'last inclusion time from external data source',
5789                format     => '\d+',
5790                field_type => 'unixtime',
5791                internal   => 1,
5792            },
5793        },
5794        occurrence => '0-n'
5795    },
5796);
5797
5798our %obsolete_robot_params = (
5799    arc_private_key_path          => 'arc_parameters.arc_private_key_path',
5800    arc_selector                  => 'arc_parameters.arc_selector',
5801    arc_signer_domain             => 'arc_parameters.arc_signer_domain',
5802    archive_mail_access           => 'archive.mail_access',
5803    archive_web_access            => 'archive.web_access',
5804    bounce_halt_rate              => 'bounce.halt_rate',
5805    bounce_warn_rate              => 'bounce.warn_rate',
5806    d_edit                        => 'shared_doc.d_edit',
5807    d_read                        => 'shared_doc.d_read',
5808    default_archive_quota         => 'archive.quota',
5809    default_bounce_level1_rate    => 'bouncers_level1.rate',
5810    default_bounce_level2_rate    => 'bouncers_level2.rate',
5811    default_list_priority         => 'priority',
5812    default_max_list_members      => 'max_list_members',
5813    default_remind_task           => 'remind_task',
5814    default_shared_quota          => 'shared_doc.quota',
5815    default_sql_fetch_timeout     => 'sql_fetch_timeout',
5816    default_ttl                   => 'ttl',
5817    dkim_header_list              => 'dkim_parameters.header_list',
5818    dkim_private_key_path         => 'dkim_parameters.private_key_path',
5819    dkim_selector                 => 'dkim_parameters.selector',
5820    dkim_signer_domain            => 'dkim_parameters.signer_domain',
5821    dmarc_protection_domain_regex => 'dmarc_protection.domain_regex',
5822    dmarc_protection_mode         => 'dmarc_protection.mode',
5823    dmarc_protection_other_email  => 'dmarc_protection.other_email',
5824    dmarc_protection_phrase       => 'dmarc_protection.phrase',
5825    tracking                      => 'tracking.tracking',
5826    tracking_default_retention_period => 'tracking.retention_period',
5827    tracking_delivery_status_notification =>
5828        'tracking.delivery_status_notification',
5829    tracking_message_disposition_notification =>
5830        'tracking.message_disposition_notification',
5831);
5832
5833_apply_defaults();
5834
5835## Apply defaults to parameters definition (%pinfo)
5836sub _apply_defaults {
5837    foreach my $p (keys %pinfo) {
5838        cleanup($p, $pinfo{$p});
5839    }
5840    foreach my $p (keys %user_info) {
5841        cleanup($p, $user_info{$p});
5842    }
5843}
5844
5845sub cleanup {
5846    my $p = shift;
5847    my $v = shift;
5848
5849    ## Apply defaults to %pinfo
5850    foreach my $d (keys %default) {
5851        unless (defined $v->{$d}) {
5852            $v->{$d} = $default{$d};
5853        }
5854    }
5855
5856    if (exists $v->{default_s}) {
5857        my $default = $v->{default_s};
5858        $default =~ s{\$(\w\w+)}{
5859            Sympa::Constants->can($1)->();
5860        }eg;
5861        $v->{default} = $default;
5862    }
5863
5864    if (exists $v->{format_s}) {
5865        my $format = $v->{format_s};
5866        if ($format =~ /\A\$(\w+)\z/) {
5867            $format = Sympa::Regexps->can($1)->();
5868        } else {
5869            $format =~ s/\$(\w+)/Sympa::Regexps->can($1)->()/eg;
5870        }
5871        $v->{format} = $format;
5872    } elsif ($v->{'scenario'}) {
5873        # Scenario format
5874        $v->{'format'} = Sympa::Regexps::scenario_config();
5875        #XXX$v->{'default'} = 'default';
5876    } elsif ($v->{'task'}) {
5877        # Task format
5878        $v->{'format'} = Sympa::Regexps::task();
5879    } elsif ($v->{'datasource'}) {
5880        # Data source format
5881        $v->{'format'} = Sympa::Regexps::datasource();
5882    }
5883
5884    ## Enumeration
5885    if (ref($v->{'format'}) eq 'ARRAY') {
5886        $v->{'file_format'} ||= join '|', @{$v->{'format'}},
5887            keys %{$v->{synonym} || {}};
5888    }
5889
5890    ## Set 'format' as default for 'file_format'
5891    $v->{'file_format'} ||= $v->{'format'};
5892
5893    if (    $v->{'occurrence'} =~ /n$/
5894        and $v->{'split_char'}
5895        and $v->{'format'}) {
5896        my $format = $v->{'file_format'};
5897        my $char   = $v->{'split_char'};
5898        $v->{'file_format'} = "($format)*(\\s*$char\\s*($format))*";
5899    }
5900
5901    ref $v->{'format'} eq 'HASH' && ref $v->{'file_format'} eq 'HASH'
5902        or return;
5903
5904    ## Parameter is a Paragraph)
5905    foreach my $k (keys %{$v->{'format'}}) {
5906        ## Defaults
5907        foreach my $d (keys %default) {
5908            unless (defined $v->{'format'}{$k}{$d}) {
5909                $v->{'format'}{$k}{$d} = $default{$d};
5910            }
5911        }
5912
5913        if (ref $v->{'format'}{$k}) {
5914            if (exists $v->{'format'}{$k}{default_s}) {
5915                my $default = $v->{'format'}{$k}{default_s};
5916                $default =~ s{\$(\w\w+)}{
5917                    Sympa::Constants->can($1)->();
5918                }eg;
5919                $v->{'format'}{$k}{default} = $default;
5920            }
5921
5922            if (exists $v->{'format'}{$k}{format_s}) {
5923                my $format = $v->{'format'}{$k}{format_s};
5924                if ($format =~ /\A\$(\w+)\z/) {
5925                    $format = Sympa::Regexps->can($1)->();
5926                } else {
5927                    $format =~ s/\$(\w+)/Sympa::Regexps->can($1)->()/eg;
5928                }
5929                $v->{'format'}{$k}{format} = $format;
5930            } elsif ($v->{'format'}{$k}{'scenario'}) {
5931                # Scenario format
5932                $v->{'format'}{$k}{'format'} =
5933                    Sympa::Regexps::scenario_config();
5934                #XXX$v->{'format'}{$k}{'default'} = 'default'
5935                #XXX    unless ($p eq 'web_archive' and $k eq 'access')
5936                #XXX    or ($p eq 'archive' and $k eq 'web_access');
5937            } elsif ($v->{'format'}{$k}{'task'}) {
5938                # Task format
5939                $v->{'format'}{$k}{'format'} = Sympa::Regexps::task();
5940            } elsif ($v->{'format'}{$k}{'datasource'}) {
5941                # Data source format
5942                $v->{'format'}{$k}{'format'} = Sympa::Regexps::datasource();
5943            }
5944        }
5945
5946        ## Enumeration
5947        if (ref($v->{'format'}{$k}{'format'}) eq 'ARRAY') {
5948            $v->{'file_format'}{$k}{'file_format'} ||= join '|',
5949                @{$v->{'format'}{$k}{'format'}},
5950                keys %{$v->{'format'}{$k}{synonym} || {}};
5951        }
5952
5953        next if $v->{format}{$k}{'obsolete'};
5954
5955        #FIXME
5956        if (($v->{'file_format'}{$k}{'occurrence'} =~ /n$/)
5957            && $v->{'file_format'}{$k}{'split_char'}) {
5958            my $format = $v->{'file_format'}{$k}{'file_format'};
5959            my $char   = $v->{'file_format'}{$k}{'split_char'};
5960            $v->{'file_format'}{$k}{'file_format'} =
5961                "($format)*(\\s*$char\\s*($format))*";
5962        }
5963
5964    }
5965
5966    ref $v->{'file_format'} eq 'HASH'
5967        or return;
5968
5969    foreach my $k (keys %{$v->{'file_format'}}) {
5970        ## Set 'format' as default for 'file_format'
5971        $v->{'file_format'}{$k}{'file_format'} ||=
5972            $v->{'file_format'}{$k}{'format'};
5973    }
5974}
5975
59761;
5977__END__
5978
5979=encoding utf-8
5980
5981=head1 NAME
5982
5983Sympa::ListDef - Definition of list configuration parameters
5984
5985=head1 DESCRIPTION
5986
5987This module keeps definition of configuration parameters for each list.
5988
5989=head2 Global variable
5990
5991=over
5992
5993=item %alias
5994
5995Deprecated by Sympa 6.2.16.
5996
5997=item %pgroup
5998
5999TBD.
6000
6001=item %pinfo
6002
6003This hash COMPLETELY defines ALL list parameters.
6004It is then used to load, save, view, edit list config files.
6005
6006List parameters format accepts the following keywords :
6007
6008=over
6009
6010=item context
6011
6012TBD.
6013
6014Introduced on Sympa 6.2.57b.
6015
6016=item format
6017
6018Regexp applied to the configuration file entry.
6019Or arrayref containing all possible values of parameter.
6020
6021Or, if the parameter is paragraph, value of this item is a hashref containing
6022definitions of sub-parameters.
6023
6024See also L<Sympa::List::Config/"Node types">.
6025
6026=item format_s
6027
6028Template of regexp applied to the configuration file entry;
6029see also L</format>.
6030
6031Subpatterns C<$word> indicate the name of pattern defined in
6032L<Sympa::Regexps>.
6033
6034This was introduced on Sympa 6.2.19b.2.
6035
6036=item file_format
6037
6038Config file format of the parameter might not be
6039the same in memory.
6040
6041=item split_char
6042
6043Character used to separate multiple parameters.
6044Used with the set or the array of scalars.
6045
6046=item length
6047
6048Length of a scalar variable ; used in web forms.
6049
6050=item scenario
6051
6052Tells that the parameter is a scenario, providing its name.
6053
6054=item default
6055
6056Default value for the param ; may be a robot configuration
6057parameter (conf).
6058
6059If occurrence is C<0-1> or C<0-n>,
6060default value will be assigned
6061only when list is created or new node is added to configuration.
6062
6063=item default_s
6064
6065Template of constant used as default value in configuration file entry;
6066see also L</default>.
6067
6068Subpatterns C<$WORD> indicate the name of constant defined in
6069L<Sympa::Constants>.
6070
6071=item synonym
6072
6073Defines synonyms for parameter values (for compatibility
6074reasons).
6075
6076=item gettext_unit
6077
6078Unit of the parameter ; this is used in web forms and refers
6079to translated
6080strings in NLS catalogs.
6081
6082=item occurrence
6083
6084Occurrence of the parameter in the config file
6085possible values: C<0-1>, C<1>, C<0-n> and C<1-n>.
6086Example: A list may have multiple owner.
6087
6088See also L<Sympa::List::Config/"Node types">.
6089
6090=item gettext_id
6091
6092Title reference in NLS catalogs.
6093
6094=item gettext_comment
6095
6096Description text of a parameter.
6097
6098=item group
6099
6100Group of parameters.
6101
6102=item obsolete
6103
6104Obsolete parameter ; should not be displayed
6105nor saved.
6106
6107As of 6.2.16, if the value is true value and is not C<1>,
6108defines parameter alias name mainly for backward compatibility.
6109
6110=item obsolete_values
6111
6112B<Deprecated>.
6113
6114Defined obsolete values for a parameter.
6115These values should not get proposed on the web interface
6116edition form.
6117
6118=item order
6119
6120Order of parameters within paragraph.
6121
6122=item internal
6123
6124Indicates that the parameter is an internal parameter
6125that should always be saved in the config file.
6126
6127=item field_type
6128
6129Used to special treatment of parameter value to show it.
6130
6131=over
6132
6133=item C<'dayofweek'>
6134
6135Day of week, C<0> - C<6>.
6136
6137=item C<'lang'>
6138
6139Language tag.
6140
6141=item C<'password'>
6142
6143The value to be concealed.
6144
6145=item C<'reception'>
6146
6147Reception mode of list member.
6148
6149=item C<'status'>
6150
6151Status of list.
6152
6153=item C<'listtopic'>
6154
6155List topic.
6156
6157=item C<'unixtime'>
6158
6159The time in second from Unix epoch.
6160
6161=item C<'visibility'>
6162
6163Visibility mode of list member.
6164
6165=back
6166
6167Most of field types were introduced on Sympa 6.2.17.
6168
6169=item filters
6170
6171See L<Sympa::List::Config/"Filters">.
6172
6173Introduced on Sympa 6.2.17.
6174
6175=item validations
6176
6177See L<Sympa::List::Config/"Validations">.
6178
6179Introduced on Sympa 6.2.17.
6180
6181=item privilege
6182
6183I<Dynamically assigned>.
6184Privilege for specified user:
6185C<'write'>, C<'read'> or C<'hidden'>.
6186
6187Introduced on Sympa 6.2.17.
6188
6189=item enum
6190
6191I<Automatically assigned>.
6192TBD.
6193
6194Introduced on Sympa 6.2.17.
6195
6196=item file
6197
6198Conf file where the parameter is defined.
6199"wwsympa.conf" is a synonym of "sympa.conf".
6200It remains there in order to migrating older versions of config.
6201
6202=item db
6203
6204'db_first', 'file_first' or 'no'.
6205TBD.
6206
6207=back
6208
6209=item %user_info
6210
6211TBD.
6212
6213=back
6214
6215=head1 SEE ALSO
6216
6217L<list_config(5)>,
6218L<Sympa::List::Config>,
6219L<Sympa::ListOpt>.
6220
6221L<sympa.conf(5)>, L<robot.conf(5)>.
6222
6223=head1 HISTORY
6224
6225L<Sympa::ListDef> was separated from L<List> module on Sympa 6.2.
6226On Sympa 6.2.57b, its content was moved to L<Sympa::Config::Schema>.
6227
6228L<confdef> was separated from L<Conf> on Sympa 6.0a,
6229and renamed to L<Sympa::ConfDef> on 6.2a.39.
6230On Sympa 6.2.57b, its content was moved to L<Sympa::Config::Schema>.
6231
6232Descriptions of parameters in this source file were partially taken from
6233chapters "sympa.conf parameters" in
6234I<Sympa, Mailing List Management Software - Reference manual>, written by
6235Serge Aumont, Stefan Hornburg, Soji Ikeda, Olivier SalaE<252>n and
6236David Verdin.
6237
6238=cut
6239