fml 8 tutorial Dr . Ken'ichi Fukamachi FML.ORG < fukachan@fml.org > Copyright © 2001-2018 Ken'ichi Fukamachi All rights reserved. This program is free software; you can redistribute it and /or modify it under the same terms as Perl itself. The current status of fml8 is PRE ALPHA. The version is 7.98.x. We plan to assign version 7.99.x to fml 8 ALPHA through fml 8 RC (release candidate). The current TODO is seen at http://www.fml.org/software/fml-devel/fml/doc/ja/ todo/STATUS.html (Japanese only now, sorry). See Chapter 8 on the changes between fml 4 and fml8. It is verified that fml8 works on the following environemnt now. perl 5.8.5 on NetBSD 2.0 perl 5.8.5 on NetBSD 1.6 perl 5.6.1 on NetBSD 1.5.x (1.5 stable) perl 5.6.1 on NetBSD 1.6 perl 5.6.1 on FreeBSD 5.2.1 perl 5.00503 on FreeBSD 4.3 STABLE perl ? on FreeBSD 4.6 RELEASE perl 5.00503 on FreeBSD 4.7 RELEASE-p3 perl 5.00503 on FreeBSD 4.6.2 RELEASE perl 5.6.1 on Turbolinux Server 8 (qmail) perl 5.6.1 on Redhat Linux 7.2 (postfix) perl 5.00503 on Redhat Linux 6.2 (sendmail8.11.6) postfix + perl 5.6.1 on Solaris 7 postfix 2.0.3 + perl 5.6.1 on Solaris 9 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Table of Contents Preface fml8 Status The Road To The Next Generation Of Fml Relation Between fml4 And fml8 Development Branch. Mailing List Please Let Me Know Your Opinion ... On This Tutorial Technical terms in this tutorial I. Fml Fundamental Usage 1. What Is Mailing List ? Email Mailing List (Ml) 2. fml8 Overview fml8 Features Installation Overview Create An ML Add A New User To ML Remove The User Customize Recipes II. How To Set Up ML 3. Download fml8 Source Code. Download Via FTP. Access To GitHUB. 4. fml8 Installation On Unix Preparation Of Installation Run Configure Appendix: Directory Roles Fml Installation: make install Edit main.cf Edit site_default_config.cf (optional) Filter Virtual Domain MTA Configuration (postfix) MTA configuration (qmail) recipes 5. Create ML On Unix Run "makefml newml" To Create An ML (In The Case Of Default Domain) Run "makefml newml" To Create An ML (In The Case Of Virtual Domain) MTA Configuration (postfix) MTA Configuration (qmail) Customize config.cf Recipes 6. fml8 installation on Microsft 2000/NT 7. Convert fml4 Style ML To fml8 Style ML Overview: fml4 To fml8 (1) Overview: Convert fml4 To fml8 (2) Overview: Difference Between fml4 and fml8 Discussion 8. Difference Between fml4 And fml8 Difference Between fml4 And fml8: License. Difference Between fml4 And fml8: Command Mail And Error Messages. Difference Between fml4 And fml8: CUI Difference Between fml4 And fml8: GUI (CGI) File Naming Convention 9. Upgrade And Downgrade Of fml8 Upgrade downgrade. 10. Configure CGI "makefml newml" Creates CGI Script Always Edit .htaccess Example: Master Cgi CGI Example: Create ML CGI Example: subscribe CGI Skin Selection 11. Apache Configuration Use Suexec Of Apache 12. Test Before Test Test Of MTA Send A Mail To ML Test Of fml8 Itself. Reset After Test. III. How To Customise 13. What A User Can Get ML Guide Subscribe Posting Article Help: When You Want To know The Usage Get Past Articles Unsubscribe Command Mail (Control fml By Sending Mail) 14. What Can You Do On The Mailing List Server On The Host Policy Of Command Creation Common Command Line Options Create A New ML Remove An ML Subscribe and Unsubscribe Change the registered address Stop Realtime Delivery Start Realtime Delivery See Log See The Member List Modify Configuration Add or Remove A Remote Administrator. Add or Remove A Modrator "fml" And "makefml" Command Show Addresses (Users + Aliases) Show Alias Show Configuration Show Perl Module Document Convert Articles To HTML Form Recipes 15. Modify Configuration Files Change Default For All ML's On Thie Host 16. [Caution] File Names Filename Structure Case Study: Address List Case Study: List Of Remote Administrators Case Study: List Of Moderators Case Study: Remote Administrator Password Files 17. Case Studies Of Customization Case Study: Auto File Responder Case Study: Anyonen Can Use Command Mail. Case Study: Disable Command Mail Case Study: Mail Magazine (1) Case Study: Mail Magazine (2) Case Study: Anyone Can Post. Case Study: Article Posting Allowd If It Is A Reply To The Former One. Case Study: PGP/PGP Based Authentication In Posting Case Study: Authenticate command mail by PGP/GPG case study: hierarchical ML I Want To Use ML By My Account. Case Study: Office (1) Case Study: Office (2) 18. Header Rewriting Recipe's 19. Extend Command Case Study: Create Your Own Help Command. Recipes 20. Filtering 21. Extend Message Case Study: Customize Message 22. Be ML Articles public via WWW Recipes IV. Operations 23. Logging See Log Show Computer Oriented Log Recipes 24. Back Up Of Configurations Back Up fml8 Configurations Back Up All Files Except For Some Large Directories. V. Troubleshoot 25. Troubleshoot When The File System Error Ocuurs VI. fml8 Design 26. [LOG] Original Idea Of fml8 Project The Original Idea Of fml8 (fml-devel) Project Details Of Idea Refactoring Architecture image release engineering 27. Programming Style Variable Naming Convension A Few Topics On Design And Coding Style Programming Style Original Idea VII. fml8 Internals 28. fml8 Boot Loader To Resolve Version Dependence Dynamically Case: Distribution FML::Process:: Class Structure Modules In Process Execution Discussion: Where Function Should Resolve $ml_name And $ml_domain. 29. Configuration File: config.cf ML Specific Configuration File: config.cf config.cf Format Extension To Postfix Style Overload Variables In config.cf Modifying/Adding Variables After All Configuration Files Have Been Loaded. Variable List (Alphabetical Order) Variable List (Class Based) Recipes 30. Create A New Program Create A Program (CUI) Create A Program (CGI) 31. fml8 Mail Delivery System The Difference Between fml4 And fml8 Mail::Message Object Incoming Queuing fml Sends Back A Mail Message Mail Queue And Delivery System Mail Queue Directory Queue Management System Discussion: FML::Mailer Is Apropriate ? Delivery TIPS 32. Digest Delivery Files Used For Digest Delivery Control Idea: Digest Related Commands recipes 33. Language Preference In Processing Problems Of Language Preference Japanese Preferred ML English preferred ML 34. Manipulate Message (Mail Message) Mail::Message Class Mail::Message::Parse Class Mail::Message::Compose Class Message Internationalization: The Usage Of reply_message_nl() Discussion: How To Send Back Language Dependent Error Mesages 35. Filter Overview Of Filter System Configuration Variables Size Limit Limit For Command Mail Mime Component Filter Rules Discussion: Mime Component Filter Needs What Functions ? 36. Subscribe / Unsubscribe Which Map Subscribe/Unsubscribe Is Operated To ? 37. Command (Command Mail, CUI And GUI) Modules for commands Data Flow Of Command Request Processing Command Extension: Command Mail CUI Command Extension: makefml/fml GUI Command Extension: CGI How Differ Coding Style Among fml4 And fml8 38. Internal Of CGI Process Method Screen Of CGI And The Method Screen And Trampolin Mechanism MISC: Hard Coding Is Mandatory ? CGI Implementation: Inheritance Among CGI Classes CGI Implementation: config.cgi 39. Directory Q: How Recursively Sub Directory Can Be Created ? Recipes 40. Restrict Input Data Overview: Checks Of Input Data FML::Restriction Class How CGI Restricts The Input Discussion: FML::Restriction Is Too Restrictive ? 41. User Authentication Discussion: FML::Credential Implementation 42. Hook Overview Hook Naming Convension Recipes 43. Virtual Domain Overview: virtual domain handling in fml8 Case study: movement ? 44. Errormail Analyzer (libexec/error) Overview Algorithm Of Error Detection Cache Of Error Messages Data Forward Error Messages 45. IO Interface And Operations Fundamentals Of IO::Adapter Methods / Operation Vector Discussion 46. Lock Overview: Lock TODO 47. Database Related Modules Overview Persistent Data Use Tie::JournaledFile Class FML::Cache::Ring Class 48. Database Management System Overview 49. Convert Another ML System To fml8 Implementation: fml4 To fml8 VIII. Modules 50. IO Abstraction Layer (IO::Adapter Class) IO::Adapter Overview IO::Adapter Methods Argument Type Of Methods File Map Unixgroup Map Nis Map MySQL Map 51. Mail::Message Module Mail::Message Overview Mail::Message Module: Analyze Mail::Message Module: Create A New Object Mail::Message Module: Header Manipulations Mail::Message Module: Manipulate Messabe Body Mail::Message Module: Search Mail::Message Module: Print Mail::Message Module: Utility Functions References 52. Language Dependent Functions Something::Language:: Class 53. Mail::Message::Encode Class Mail::Message::Encode Specification run_in_chcode() 54. Execise: Create A New Program Case Study: Create A fmlsch Case Study: fmlsch.cgi IX. Apendixes Glossary (function and variable names convention) A. Struct curproc (Object In Fact) curproc Object PCB Category List List of Tables 4-1. directory structure 8-1. Difference between fml4 and fml8: CUI 26-1. refactoring TODO 26-2. release interval 29-1. table description ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Preface fml8 Status ┌─────────────────────────────────────────────────────────────────────────────┐ │ Warning │ ├─────────────────────────────────────────────────────────────────────────────┤ │fml8 has already implemented fundamental functions. Several people uses fml8 │ │as hobby and office mailing list system under normal operations. │ │ │ │When you configure fml8, you need to edit configuration files since │ │configuration helper tool has basic functions now. Except it, you can use │ │fml8 as same as fml4. │ │ │ │See http://www.fml.org/software/fml-devel/fml/doc/ja/todo/STATUS.html for the│ │current status of fml8. │ │ │ │See Chapter 8 on the difference between fml4 and fml8. │ └─────────────────────────────────────────────────────────────────────────────┘ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ The Road To The Next Generation Of Fml fml8 is fully rewritten mailing list driver from scratch to re-implement fml4. The main purpose of this project is re-implementation of fml mailing list driver system with reflecting our 10 years experience on mailing list driver developement. Roughly speaking, the relation between fml4 and fml8 is similar to one between sendmail and Postfix. fml8 re-implements almost all features of fml4 functions. We re-design fml and clean up the function and variable naming convenstion. Also, We reinforce guide line to the coding style for clean source codes. For example, when you use fml4, you'll find that fml assumes the list of members is a text file on the host. fml4 inherits the assumption from version 1.0 through 4.0. It affetcts the core part of the design. Hence, it is difficult to extend fml IO for the use of RDBMS, redundency et.al. In fact, fml4 supports RDBMS but the code is ugly. We should need to fully rewrite fml core parts. Also, I want a lot of new features. fml8 should provide tiny bug tracking system maintatined automatically. It is better to co-relate fml with cvs log. These features help the support by mail and developer mailing list. I need it, of course. Firstly, we need to discuss what we should inherit from fml4 design and features, and discard what in fml4. • What we should inherit into fml8 from fml4 ? • easily customizable ? • what obsolete features we should remove ? Anyway, we should write codes for the further discussion! You can find it at the following URL. http://www.fml.org/software/fml8/ ftp://ftp.fml.org/pub/fml8/ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Relation Between fml4 And fml8 Development Branch. We implement new features at fml8 branch. fml4 imports it if needed. We only have to bug-fix at fml4 branch. (further translation omited). fml-devel -----------------------------> 8.0 A | | | (interaction) | V 1.2 -> 4.0 ------------------------------> 4.0-current | | 4.0.1 4.0.2 .... (release / 4.0-stable release) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Mailing List fml-users@ffs.fml.org is prepared. Use it for English discussion. To subscribe it, send the mail with "subscribe YOUR NAME" in the body to fml-users-ctl@ffs.fml.org. You will receive the reply for confirmation. Please reply the confirmation and send back it to fml-users-ctl@ffs.fml.org again. For example, a subscribe mail is as follows: From: your-account@your-domain To: fml-users-ctl@ffs.fml.org subscribe Kinomoto Sakura ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Please Let Me Know Your Opinion ... Please send me the idea on fml8 to the mail address: fml-request@fml.org or myself fukachan@fml.org directly. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ On This Tutorial For the fml4 user, the order of chapters and sections are almost same as the book "fml bible" publishded by O'reilly Japan (rewritten in Japanese). ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Technical terms in this tutorial See Glossary (function and variable names convention) also. % user prompt on the shell # root user prompt on the shell ~ user's home directory CUI command line tool such as makefml or fml. fml fml software in general use. fml (command) fml command included in fml8 software. fml is same as makefml command except for the argument order. user fml a user called as fml. a user account for fml8 software. fml4 fml4 series. fml8 fml8 series. GUI CGI interface. makefml (command) configuration helper tool included in fml4 and fml8. You can use them when you login the mailing list server. I. Fml Fundamental Usage This part describes a brief guide for beginners. See http://www.fml.org/software/fml/ and other sites for more details on mechanism of the mailing list. Table of Contents 1. What Is Mailing List ? 2. fml8 Overview ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Chapter 1. What Is Mailing List ? Email Email is an electirc version of mail. One email has the following structure which consists of two parts. The former is header, the latter is body. The separator between them is one null line (empty line). [Example] From: rudo@nuinui.net To: kenken@nuinui.net Subject: asobo. Hi, Kenken. I am Rudo. // rudo See RFC822 and RFC2822 for more details of definitions. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Mailing List (Ml) Mailing list (ML) is forwarding mechanism of email. The program for it is called as ML driver. ML driver receives the email injected via MTA over the network, copy and redistributes it to members subscribed to the ML. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Model Of An ML. [ml] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Chapter 2. fml8 Overview See Chapter 8 on the detail of difference between fml4 and fml8. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ fml8 Features • fml8 configuration file format is changed to new Postfix style format configuration files (.cf files). • usage of CUI is almost same as fml4 (it is same as could as possible). You can use CUI (makefml and fml command) to create/remove an ML, to add/remove/change an addresse of ML members, to add/remove/change an address of remote administrators, to see log and member list, et.al. Makefml and fml are same programs except for argument order. See the Section called Difference Between fml4 And fml8: CUI in Chapter 8 on the CUI usage difference between fml4 and fml8. • GUI (CGI) interface. The functions are a subset of CUI ones. to create/remove an ML, to add/remove/change an address of ML members, to add/remove/change an address of remote administrators, to see log and member list, et.al. The configuration file editing is incomplete yet. • article delivery, header rewriting and several filters ( corresponding with fml4's envelope filter and content filter ). • command mail for users. to add/remove/change the address, get article summary, get old articles, et.al. • command mail (admin command mail) for remote administratoin by mail. to add/remove/change an addresse of ML members, to add/remove/change an address of remote administrators, to see log and member list, et.al. • automatic analyzer of error messages. • IPv6 ready. • tiny thread track system. • built-in module for HTML converter of articles. support automatic conversion by default. fmlhtmlify and makefml supports html conversion functions. • main programs (fml/libexec): distribute command error • utilities: fmladdr fmlailas fmlconf fmldoc makefml fml • fml4 emulation: if you replace fml.pl of fml4 and fml.pl of fml8, fml8 runs as fml4. • After 2004 summer, the queueing system is implemanted. Currently the delivery system is queuing based. So, fml8 is a MTA in fact. • Abstracted IO layer to get member list in unified way from a file, /etc/ group, NIS, SQL. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Installation Overview Important: Run GNU autoconf firstly, and "make install". It is defact standard in the world of open sources. This procedure is different from fml4 installation steps. It may confuse you if you are customered with fml4 But fml8 is more friendly for package systems of free unix like systems. The main differece between fml4 and fml8 in installation is "run programs as root", "use of configure", and editing of configuration files. Suppose we create a new ML named elena ML (elena@fml.org). The brief flow of installation is as follows: 1. Download fml8 source and extract it on the disk. 2. Install it by user root. Firstly, change user to "root" and create the user "fml" and the group "fml". Secondly, run configure and "make install". % su root # groupadd fml # useradd -m -g fml fml # ./configure # make install By default, 4.4 BSD style sub-directories are created. The path is configurable at configure options. For example, main programs called from MTA such as distribute, command, et.al. are installed into under /usr/local/libexec/fml/. Instead, utility programs are installed to /usr/local/bin. These are wrappers to call real programs at /usr/local/libexec/fml/. Perl modules are installed into /usr/local/lib/fml/$fml_version/ and message templates et.al. are installed into /usr/local/share/fml/ $fml_version/. 3. Change user to "fml" and create elena ML for test. % su fml % makefml newml elena You can use "fml" instead of makefml. Both are same except for the argument order. % su fml % fml elena newml 4. Set up MTA which runs fml8 programs. 5. Test. 6. Customize your ML. ┌─────────────────────────────────────────────────────────────────────────────┐ │ Warning │ ├─────────────────────────────────────────────────────────────────────────────┤ │Please install by user root. It is different from fml4. │ └─────────────────────────────────────────────────────────────────────────────┘ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Create An ML Create an ML by CUI (makefml). To create elena@fml.org ML (fml.org is the default domain), run % su fml % makefml newml elena . See the section Chapter 5 for more details. In the virtual domain case, specify the whole address as an argument. For example, to create an ML elena@nuinui.net, run the following command: (At the first time) % su root % makefml newdomain nuinui.net /some/where/nuinui.net % su fml % makefml newml elena@nuinui.net (After the 2nd time) % su fml % makefml newml elena@nuinui.net ┌─────────────────────────────────────────────────────────────────────────────┐ │ Warning │ ├─────────────────────────────────────────────────────────────────────────────┤ │See Chapter 43 for the virtual domain case detail. │ └─────────────────────────────────────────────────────────────────────────────┘ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Add A New User To ML In the case of the default domain (fml.org) % su fml % makefml subscribe elena rudo@nuinui.net in the case of virtual domain (nuinui.net), specify the whole adress of ML name. % su fml % makefml subscribe elena@nuinui.net fukachan@sapporo.iij.ad.jp ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Remove The User In the case of the default domain (fml.org), % su fml % makefml unsubscribe elena rudo@nuinui.net in the case of virtual domain (nuinui.net), specify the whole adress of ML name. % su fml % makefml unsubscribe elena@nuinui.net fukachan@sapporo.iij.ad.jp ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Customize ┌─────────────────────────────────────────────────────────────────────────────┐ │ Warning │ ├─────────────────────────────────────────────────────────────────────────────┤ │"makefml config" is a CUI to customize ML by menu form. BUT YET INCOMPLETE. │ │ │ │Edit configuration files anyway now. │ └─────────────────────────────────────────────────────────────────────────────┘ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Common Configurations On This Host /usr/local/etc/fml/site_default_config.cf affects all ML on this host irrespective of the default domain or virtual domains. [1] The format of site_default_config.cf is same as config.cf described below. See list of all variables for the configurable variation. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ elena ML's Configuration To customize elena ML, edit /var/spool/ml/elena/config.cf file. The format is a little modified postfix style. It is different from both fml4's config.ph and cf. Add hooks after =cut line if needed. Add or modify the least variables. If unspecified, the default value is used. The default value depends fml version and is defined at /usr/local/etc/fml/defaults/${fml_version}/default_config.cf The library path depends fml version. This technique ensures the easy upgrade/ downgrade procedure. This is a feature of fml8. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Recipes 1. Why fml8 is the next official release of fml4 series ? 2. What difference between fml4 and fml8 ? 3. Which of current, stable and release should we download ? 1. Why fml8 is the next official release of fml4 series ? 1 bit shift of version with greate internal change is traditional :-) fml8 is build from scratch by discarding fml4 source codes. fml8 is not a upgraded fml4 software. So we use 1 bit shifted version number for fml8. 2. What difference between fml4 and fml8 ? See Chapter 8 fore more details. 3. Which of current, stable and release should we download ? fml8 does not provide such release line today. Please download the latest one by comparing file name which has date in int. See Chapter 3 on download. II. How To Set Up ML Topics driven in this part. Table of Contents 3. Download fml8 Source Code. 4. fml8 Installation On Unix 5. Create ML On Unix 6. fml8 installation on Microsft 2000/NT 7. Convert fml4 Style ML To fml8 Style ML 8. Difference Between fml4 And fml8 9. Upgrade And Downgrade Of fml8 10. Configure CGI 11. Apache Configuration 12. Test ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Chapter 3. Download fml8 Source Code. Download Via FTP. You can find fml8 source at ftp://ftp.fml.org/pub/fml8/ . You can get it by ftp. We build snapshot as a tarball in some interval. The file name contains date such as YYYYMMDD form. Please get the latest one. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Access To GitHUB. https://github.com/fmlorg/ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Chapter 4. fml8 Installation On Unix Preparation Of Installation Create the user "fml" and the group "fml" before running configure. % su root # groupadd fml # useradd -g fml -m fml ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Run Configure Run configure (GNU autoconf) and make. % su root # groupadd fml # useradd -g fml -m fml # ./configure # make install where configure replaces variables in scripts and .cf files. After runnig configure, run "make install". The fml installer (perl scripts) reads ./etc/fml/install.cf configure created and install fml8 to e.g. /usr/ local/. You can specify the user name and fundamental directory names by configure arguments. Customizable variables are follows: configure --help shows them. variables default value example -------------------------------------------------------- prefix /usr/local /usr/local exec_prefix /usr/local bindir ${exec_prefix}/bin /usr/local/bin sbindir ${exec_prefix}/sbin /usr/local/sbin libexecdir ${exec_prefix}/libexec /usr/local/libexec/fml datadir ${prefix}/share /usr/local/share/fml sysconfdir ${prefix}/etc /usr/local/etc/fml sharedstatedir ${prefix}/com localstatedir ${prefix}/var libdir ${exec_prefix}/lib /usr/local/lib/fml includedir ${prefix}/include oldincludedir /usr/include infodir ${prefix}/info mandir ${prefix}/man You can overwrite the following variables by configure arguments. fmlconfdir $sysconfidr/fml /usr/local/etc/fml mlspooldir /var/spool/ml /var/spool/ml fml_owner fml fml fml_group fml fml default_domain (spaculated by configure) (spaculated by configure) These options are shown by runnig configure --help . --without-warning run perl as perl without -w --with-fmlconfdir=DIR use DIR instead of SYSCONFDIR/fml --with-mlspooldir=DIR use DIR instead of /var/spool/ml --with-fml-owner=USER use USER instead of fml --with-fml-group=GROUP use GROUP instead of fml --with-default-domain=DOMAIN use DOMAIN as the ML domain ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Example: Running Configure Example: On NetBSD, you should install 3rd party programs into /usr/pkg. % ./configure --prefix=/usr/pkg Example: On FreeBSD, use /usr/local. % ./configure If you use /etc/fml as configuration directory on e.g. Debian, # ./configure --with-fmlconfdir=/etc/fml loading cache ./config.cache checking for perl... (cached) perl checking for perl... (cached) /usr/local/bin/perl checking whether optional useful commands are available or not checking for cksum... (cached) /usr/bin/cksum checking for md5... (cached) /usr/bin/md5 checking for ls... (cached) /bin/ls checking for tar... (cached) /usr/bin/tar checking for gzip... (cached) /usr/bin/gzip checking for zcat... (cached) /usr/bin/zcat checking for gunzip... (cached) /usr/bin/gunzip checking for lha... (cached) /usr/pkg/bin/lha checking for ish... no checking for bzip2... (cached) /usr/bin/bzip2 checking for bunzip2... (cached) /usr/bin/bunzip2 checking for uuencode... (cached) /usr/bin/uuencode checking for compress... (cached) /usr/bin/compress checking for sendmail... (cached) /usr/sbin/sendmail checking for newaliases... (cached) /usr/bin/newaliases checking for postfix... (cached) /usr/sbin/postfix checking for postalias... (cached) /usr/sbin/postalias checking for postconf... (cached) /usr/sbin/postconf checking for postmap... (cached) /usr/sbin/postmap checking for nkf... (cached) /usr/pkg/bin/nkf checking for kakasi... no checking for namazu... no checking for pgp... (cached) /usr/pkg/bin/pgp checking for pgp5... no checking for pgpe... no checking for pgpk... no checking for pgps... no checking for pgpv... no checking for gpg... no checking for less... (cached) /usr/bin/less checking for more... (cached) /usr/bin/more checking for w3m... (cached) /usr/pkg/bin/w3m updating cache ./config.cache creating ./config.status creating config.sh creating fml/etc/main.cf creating fml/etc/default_config.cf.ja creating fml/etc/site_default_config.cf creating fml/libexec/loader creating fml/bin/fmlalias creating fml/bin/fmlconf creating fml/bin/fmldoc creating fml/bin/fmlhtmlify creating fml/bin/fmlsch creating fml/bin/fmlthread creating fml/bin/fmlspool creating fml/bin/makefml enabled perl -w fml has been configure with the following options: prefix: /usr/local exec_prefix: ${prefix} bindir: ${exec_prefix}/bin sbindir: ${exec_prefix}/sbin lib_dir: ${exec_prefix}/lib libexec_dir: ${exec_prefix}/libexec mandir: ${prefix}/man datadir: ${prefix}/share fml process owner: fml fml process group: fml fmlconfdir: /etc/fml mlspooldir: /var/spool/ml default domain: home.fml.org Now you must run "make install". ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Appendix: Directory Roles fml8 installs files under /usr/local by default. Table 4-1. directory structure ┌─────────┬───────────────────────────────────────────────────────────────────┐ │directory│ description │ ├─────────┼───────────────────────────────────────────────────────────────────┤ │/usr/ │Configuration files. It corresponds with fml4's /usr/local/fml/.fml│ │local/etc│and default_config.ph. /usr/local/etc/fml/main.cf has fml version │ │/fml │and library paths et.al. │ ├─────────┼───────────────────────────────────────────────────────────────────┤ │/usr/ │ │ │local/ │Executables (corresponding with fml4's /usr/local/fml ) │ │libexec/ │ │ │fml │ │ ├─────────┼───────────────────────────────────────────────────────────────────┤ │/usr/ │ │ │local/lib│Perl module location ( fml4's /usr/local/fml ) │ │/fml │ │ ├─────────┼───────────────────────────────────────────────────────────────────┤ │/usr/ │Message templates ( fml4's /usr/local/fml/messages/). Template │ │local/ │files are language dependendent. │ │share/fml│ │ ├─────────┼───────────────────────────────────────────────────────────────────┤ │ │The top directory for mailing lists of the default domain. same as │ │ │fml4. caution: the owner of /var/spool/ml can be specified by │ │/var/ │configure arguments. Prepare different directory for each domain. │ │spool/ml │For example, /var/spool/ml for fml.org (default domain), whereas / │ │ │var/spool/nuinui.net for nuinui.net domain (virtual domain). See │ │ │ml_home_prefix_maps for the relation between domain and directory. │ │ │Also see Chapter 43 for the virtual domain detail. │ └─────────┴───────────────────────────────────────────────────────────────────┘ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Fml Installation: make install change user to "root" and run "make install" after configure runs. % su root # make install ┌─────────────────────────────────────────────────────────────────────────────┐ │ Warning │ ├─────────────────────────────────────────────────────────────────────────────┤ │You need not to run configure by the user root. But, you need to run "make │ │install" by root. So, it may be better to run both by root. │ │ │ │% su root │ │# ./configure │ │# make install │ └─────────────────────────────────────────────────────────────────────────────┘ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Edit main.cf Please edit /usr/local/etc/fml/main.cf if needed, though already configure rewrites main.cf to fit your environment. The file main.cf contains the most fundamental configuration variables to control fml8 basic features: fml version control, library path, virtual domain et.al. Instead, the detail of each ML configuration depends on config.cf file of each ML such as /var/spool/ml/elena/config.cf for elena ML. "config.cf" can override all configuration variables: header customizations, filter rules, member file locations et.al. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Example: /usr/local/etc/fml/main.cf /usr/local/etc/fml/main.cf is not ML specific. This is meta file to define fundamental variables e.g. fml version, directory path et.al. fml8 loader reads them. The format of main.cf is same as other .cf files: [2] variable = value style. # # $FML: main.cf.sgml,v 1.1 2005/07/27 12:21:36 fukachan Exp $ # # fml version # This is important # Example: fml 8.0 # fml-current YYYYMMDD # fml-devel YYYYMMDD fml_version = current-20020701 fml_owner = fml fml_group = fml ### ### DIRECTORIES ### # Example: /usr/local prefix = /usr/local exec_prefix = ${prefix} # $config_dir holds the global main configuration and # several version-dependent default configurations # Example: /usr/local/etc/fml config_dir = /usr/local/etc/fml # Example: /usr/local/etc/fml/defaults/$fml_version default_config_dir = $config_dir/defaults/$fml_version # defined for convenience, for example, we need this variable # at include, include-ctl, which needs expansion of ../libexec/fml/fml.pl # Example: /usr/local/libexec/fml executable_prefix = ${exec_prefix}/libexec/fml # Example: /usr/local/libexec/fml/$fml_version libexec_dir = ${exec_prefix}/libexec/fml/$fml_version # Example: /usr/local/lib/fml/$fml_version lib_dir = ${exec_prefix}/lib/fml/$fml_version # Example: /usr/local/share/fml/$fml_version share_dir = ${prefix}/share/fml/$fml_version # site local library location # which is prepared but not used by fml itself local_lib_dir = ${exec_prefix}/lib/fml/site_local # ml's home directories # $ml_home_dir (e.g. /var/spool/ml/elena ) is taken from loader's @ARGV. # This is compatible with fml 4.0. # Example: /var/spool/ml default_ml_home_prefix = /var/spool/ml ### ### CONFIGURATION FILES AND DEFAULT PARAMETERS ### # default domain default_domain = fml.org # version dependent default_config.cf location # whic holds # Example: /usr/local/etc/fml/defaults/8.0/default_config.cf default_config_cf = $default_config_dir/default_config.cf # domain specific configurations # Example: /usr/local/etc/fml/domains/fml.org/default_config.cf domain_default_config = $config_dir/domains/$default_domain/config.cf # virtual format: domain directory # for example, # fml.org /var/spool/ml/fml.org # nuinui.net /var/spool/ml/nuinui.net virtual_maps = $config_dir/virtual ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Edit site_default_config.cf (optional) /usr/local/etc/fml/site_default_config.cf is the configuration file common over all mailing list on this host (site). [3] site_default_config.cf overrides default_config.cf file. Each ML configuration file (/var/spool/ml/elena/config.cf for elena ML) overrides site_default_config.cf. By default, some example configurations are added to this file. # # site default_config.cf EXAMPLE # # fml-devel loads .cf files in this order for elena ML. # 1. ${prefix}/etc/fml/defaults/$VERSION/default_config.cf # 2. ${prefix}/etc/fml/site_default_config.cf # 3. ${prefix}/etc/fml/domains/$DOMAIN/default_config.cf # 4. /tmp/dir/elena/config.cf # # This file overrides the default "default_config.cf" configurations # in the following way. # # We want to disable the subject tag in articles by default. article_header_rewrite_rules -= rewrite_article_subject_tag # mime based comonent filter use_mime_component_filter = yes # [site specific options] # Example: # key = value # key += value # key -= value =cut # # you can write hooks here after. # Example: # $distribute_run_start_hook = q{ ... }; ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Filter All filter are enabled by default. "mime component filter" is important. By default mime component filter is enabled, Only text/plain article can be passed through fml8. To disable mime component filter on all ML's, set use_mime_component_filter = no at site_default_config.cf. To customize mime component filter, set use_mime_component_filter = yes at site_default_config.cf, and edit rules in /usr/local/etc/fml/ mime_component_filter file. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Virtual Domain You do not need edit /usr/local/etc/fml/main.cf but you need to edit $ml_home_prefix_maps (/usr/local/etc/fml/ml_home_prefix file by default). You can use "makefml newdomain" command to control $ml_home_prefix_maps. See "ML creation" for newdomain command. Suppose that fml.org is the default domain. In this case, /var/spool/ml/$ml is used for $ml ML of fml.org. /var/spool/ml is used only for the domain fml.org. If you want to set up elena@nuinui.net, you need to specify other directory. Specify the relation between domain and directory, edit /usr/local/etc/fml/ ml_home_prefix and set the following: nuinui.net /var/spool/nuinui.net Please use "makefml newdomain" command to change /usr/local/etc/fml/ ml_home_prefix file. It is recommended that you do not edit this file directly. ┌─────────────────────────────────────────────────────────────────────────────┐ │ Warning │ ├─────────────────────────────────────────────────────────────────────────────┤ │site_default_config.cf is applied to all domains. │ └─────────────────────────────────────────────────────────────────────────────┘ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ MTA Configuration (postfix) Please set up postfix properly before "makefml newml" can set up a ml. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Default Domain (Example: fml.org) Set up /etc/postfix/main.cf like this: [/etc/postfix/main.cf] allow_mail_to_commands = alias,forward,include alias_maps = hash:/etc/mail/aliases hash:/var/spool/ml/etc/mail/aliases ┌─────────────────────────────────────────────────────────────────────────────┐ │ Warning │ ├─────────────────────────────────────────────────────────────────────────────┤ │Please check that $mydestination contains the default domain (may be │ │$mydomain). │ └─────────────────────────────────────────────────────────────────────────────┘ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Virtual Domain (Example: nuinui.net) You need to edit /etc/postfix/main.cf to set up $virtual_maps. [/etc/postfix/main.cf] allow_mail_to_commands = alias,forward,include alias_maps = hash:/etc/mail/aliases hash:/var/spool/ml/etc/mail/aliases hash:/var/spool/nuinui.net/etc/mail/aliases virtual_maps = hash:/var/spool/nuinui.net/etc/postfix/virtual [/usr/local/etc/fml/ml_home_prefix] nuinui.net /var/spool/nuinui.net Both alias files and /var/spool/nuinui.net/etc/postfix/virtual are updated by makefml automatically where we suppose ml_home_prefix_maps defines nuinui.net /var/spool/nuinui.net relation. ┌─────────────────────────────────────────────────────────────────────────────┐ │ Warning │ ├─────────────────────────────────────────────────────────────────────────────┤ │Postfix variable $mydestination should contain the default domain (may be │ │$mydomain) but not virtual domain. Pay attention that we assume we use │ │postfix style virtual domain. Please see postfix document for more details. │ │ │ │When you begin to use a new virtual domain, you need to update both │ │$alias_maps and $virtual_maps in /etc/postfix/main.cf. Also, you have to │ │update /usr/local/etc/fml/ml_home_prefix by running "makefml newdomain". │ │ │ │Recent postfix has $virtual_alias_maps and $virtual_maps variables. But │ │$virtual_alias_maps = $virtual_maps by default. You can use either. │ └─────────────────────────────────────────────────────────────────────────────┘ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ MTA configuration (qmail) ┌─────────────────────────────────────────────────────────────────────────────┐ │ Warning │ ├─────────────────────────────────────────────────────────────────────────────┤ │fml8 assumes that qmail configurations is always based on /var/qmail/control/│ │virtualdomains regardless of the default domain or not. │ └─────────────────────────────────────────────────────────────────────────────┘ The template of /var/qmail/control/virtualdomains is created at /var/spool/ml/ etc/qmail by makefml. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ The default domain (example: fml.org) It is good to prepare "ml.fml.org" domain for ml specific. At /var/qmail/control/virtualdomains specify the following rule ml.fml.org:fml-fml.org . "makefml newml" can set up ~/.qmail-* automatically. See the section on "makefml newml and qmail" on how "makefml newml" creates ~ /.qmail-* files. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ virtual domain (example: nuinui.net) For "nuinui.net" virtual domain, not the default one, specify nuinui.net:fml-nuinui.net at /var/qmail/control/virtualdomains. It is same as in default domain case. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ recipes 1. Can we use other user as fml process ? 2. When should we change use to fml in installation ? 3. Can we install fml8 without document. 4. Can we specify per path in installation ? 5. Can we use jperl ? 6. Can we overwrite elena ML ? 7. Can we edit alias files under /var/spool/ml/etc ? 8. Can we use fml8 on Windows 2000/NT4 but MTA on Unix server ? 9. Can we initialize ML ? 1. Can we use other user as fml process ? Run configure with --with-fml-owner option. configure --with-fml-owner=$USER Do not use your own account but use fml specific user for all fml processes. Please use procmail et.al. if fml processes are kicked off by .forward not aliases. See /var/spool/ml/etc/procmail/procmailrc for more details on procmail usage. 2. When should we change use to fml in installation ? In installation. You can download source code and run configure by not user root (e.g. user fml), but run "make install" by user root. It may be better to run by user too always. 3. Can we install fml8 without document. Yes by default. fml8 does not install document. If you need documentation, please install ./SOURCE/Documentation/ into /usr/local/share/doc/fml8/ $FML_VERSION/. 4. Can we specify per path in installation ? No directly. Run configure with proper environment variable PATH. % env PATH=/some/where/:$PATH sh configure 5. Can we use jperl ? Unknown. 6. Can we overwrite elena ML ? Run "makefml newml" with --force option. % makefml --force newml elena 7. Can we edit alias files under /var/spool/ml/etc ? Yes but please control them by yourself. These files are controlled by makefml/ fml scripts. These scripts edit them. If the ML is removed, the corresponding entries are removed and cannot be back. 8. Can we use fml8 on Windows 2000/NT4 but MTA on Unix server ? Caution: not tested. It can be. Run fetchfml on Windows 2000 or NT4 and run MTA on Unix. 9. Can we initialize ML ? It is easy to run rmml once and newml again. % makefml rmml elena % makefml newml elena ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Chapter 5. Create ML On Unix Run "makefml newml" To Create An ML (In The Case Of Default Domain) ┌─────────────────────────────────────────────────────────────────────────────┐ │ Caution │ ├─────────────────────────────────────────────────────────────────────────────┤ │The usage of fml8 makefml is same as fml4 in the case of default domain. But │ │differs in the virtual domain case. See the Section called Run "makefml │ │newml" To Create An ML (In The Case Of Virtual Domain) for the virtual domain│ │case. │ └─────────────────────────────────────────────────────────────────────────────┘ To create an ML, use "makefml" command (CUI) in the same way as fml4. % su fml % makefml newml elena ... snip ... In the case of non default domain (virtual domain), run "makefml newdomain" command before running "makefml newml". % su root # makefml newdomain fml.org /var/spool/virtual/fml.org # exit % su fml % makefml newml elena ... snip ... "makefml newml" processes the following steps. • Create files such as config.cf include include-ctl at /var/spool/ml/elena. The domain name et.al. in these files is replaced to proper value. • Add elena ML entry into /var/spool/ml/etc/mail/aliases. Run postalias to rebuild /var/spool/ml/etc/mail/aliases.db. • Create ~fml/.qmail-* files for qmail. • Update procmailrc as a sample. • Prepare the directory ~fml/public_html/fml/mlarchive/$domain/$ml/ for html archive. For example, for elena@fml.org ~fml/public_html/fml/mlarchive/fml.org/elena/ is creatd. HTML archive of ML articles is created by default. • Prepare CGI (GUI). Set up ~fml/public_html/cgi-bin/fml/$domain/admin/config.cgi for the master cgi, instead cgi to control one ML $ml@$domain is set up at ~fml/public_html/cgi-bin/fml/$domain/ml-admin/$ml/config.cgi ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Run "makefml newml" To Create An ML (In The Case Of Virtual Domain) ┌─────────────────────────────────────────────────────────────────────────────┐ │ Caution │ ├─────────────────────────────────────────────────────────────────────────────┤ │The usage of makefml differs from fml4. In the case of fml8 firstly use │ │"makefml newdomain" command, in the next run "makefml newml" command. Also │ │ml_name differs. For virtual domain, use ml_name@ml_domain form. │ └─────────────────────────────────────────────────────────────────────────────┘ In using "makefml newml", the usage is same as fml4 except for the ml_name. ml_name part is ml_name@ml_domain in the case of fml8 At the first time to use a virtual domain, run "makefml newdomain" before "makefml newml". % su root # makefml newdomain nuinui.net /var/spool/virtual/nuinui.net # exit % su fml % makefml newml elena@nuinui.net After the second time, just use "makefml newml". % su fml % makefml newml elena@nuinui.net In running "makefml newdomain", specify a pair of domain and directory in ml_home_prefix_maps. This command edits /usr/local/etc/fml/ml_home_prefix file to add the following line. nuinui.net /var/spool/virtual/nuinui.net To remove this line, use "makefml rmdomain". The usage of "makefml newml" command is same as in the case of default domain. "makefml newml" creates an example of virtual domain configurations for several MTA's such as /var/spool/ml/etc/sendmail/virtusertable /var/spool/ml/etc/postfix/virtual . No example for qmail (not needed). No example for procmail since .procmailrc contains domain. See the chapter of virtual domain for more details. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ MTA Configuration (postfix) Important: If $alias_maps of Postfix is properly set up, "makefml newml" automatically prepares fml and postfix configuration for the new ML. See the Section called MTA Configuration (postfix) in Chapter 4 for the detail of postfix configuration. "makefml" does not update system aliases (e.g. /etc/mail/aliases), but updates only alias file $ml_home_prefix/etc/mail/aliases file, which is used only for fml. "makefml" rebuilds $ml_home_prefix/etc/mail/aliases.db automatically, too. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ NOTE: Format Of /var/spool/ml/etc/mail/aliases $ml_home_prefix/etc/mail/aliases has the following entry for elena@home.fml.org ML. ### ### # address for post elena: :include:/var/spool/ml/elena/include owner-elena: fukachan # address for command elena-ctl: :include:/var/spool/ml/elena/include-ctl owner-elena-ctl: fukachan # maintainer elena-request: elena-admin elena-admin: fukachan, elena-error # error analyzer elena-error: :include:/var/spool/ml/elena/include-error owner-elena-error: fukachan ### ### In the case of virtual domain, $ml_home_prefix varies with $virtual_maps. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ MTA Configuration (qmail) "makefml newml" creates the following files for qmail: ~fml/.qmail-fml:org-elena ~fml/.qmail-fml:org-elena-admin ~fml/.qmail-fml:org-elena-ctl ~fml/.qmail-fml:org-elena-default ~fml/.qmail-fml:org-elena-request Hence, if /var/qmail/control/virtualdomains contains the following definition fml.org:fml-fml.org you have only to run "makefml newml" to create an ML in the case of qmail. ┌─────────────────────────────────────────────────────────────────────────────┐ │ Warning │ ├─────────────────────────────────────────────────────────────────────────────┤ │This configuration assumuss ML's uses the whole one domain only for mailing │ │list. │ └─────────────────────────────────────────────────────────────────────────────┘ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Virtual Domain The logic is same as above. So you need to edit /var/qmail/control/ virtualdomains to make an ML effective automatically when you runs "makefml newml". This edit needs root priviledge. Please contact the administrator on it. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Customize config.cf In running "makefml newml", makefml sets up configuration files such as config.cf, include files for sendmail and postfix and ~fml/.qmail-* files. % su fml % makefml newml elena ... snip ... % ls /var/spool/ml/elena config.cf include include-ctl include-error ... snip ... To customize one ML configuraiton, edit config.cf. ┌─────────────────────────────────────────────────────────────────────────────┐ │ Warning │ ├─────────────────────────────────────────────────────────────────────────────┤ │menu tool to edit config.cf is incomplete. │ └─────────────────────────────────────────────────────────────────────────────┘ config.cf contains little definition. For example, /var/spool/ml/elena/include file follows: "| /usr/local/libexec/fml/distribute elena@fml.org" /var/spool/ml/elena/include-ctl file follows: "| /usr/local/libexec/fml/commande elena@fml.org" /usr/local/libexec/fml/PROGMAR resolves ml_name and ml_domain from the arguments such as elena@fml.org. That is, elena@fml.org in this argument determines values of $ml_domain and $ml_name. It is enough that ml_name and ml_domain in config.cf is a comment. The content of include, include-ctl and aliases are same as fml4 except for the path. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Recipes 1. Specify administrator's mail address in alias file when "newml" command runs. 2. Not create a configuration file for a specific MTA not used. 1. Specify administrator's mail address in alias file when "newml" command runs. CUI (makefml/fml) creats an alias in "newml". ${ml_name}-admin: ADDRESS where ADDRESS is defined by $newml_command_ml_admin_default_address. By default, $newml_command_ml_admin_default_address == $fml_owner defined in /usr/ local/etc/fml/main.cf file. To change the value, specify $newml_command_ml_admin_default_address in site_default_config.cf. $newml_command_ml_admin_default_address = YOUR_ADDRESS You can use $ml_name here. $newml_command_ml_admin_default_address = $ml_name-owner@$ml_domain 2. Not create a configuration file for a specific MTA not used. $newml_command_mta_config_list defines list of MTA. "makefml newml" command creates examples of the specified MTA's. Remove the specific MTA from the list to disable example creation. For example, you do not need "qmail" configuration example newml_command_mta_config_list -= qmail fml8 does not generate ~/.qmail-* files. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Chapter 6. fml8 installation on Microsft 2000/NT ┌─────────────────────────────────────────────────────────────────────────────┐ │ Warning │ ├─────────────────────────────────────────────────────────────────────────────┤ │not yet implemented. │ └─────────────────────────────────────────────────────────────────────────────┘ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Chapter 7. Convert fml4 Style ML To fml8 Style ML 2004/03: We have implemented a converter which converts ML HOME DIRECTORY ($DIR) such as /var/spool/ml/elena ($ml_home_dir in fml8) from fml4 style to fml8 style. It is incomplete but is being developed. 2004/11: You can replace fml.pl of fml4 with fml.pl of fml8. now. It means that fml8 directly emulates fml4. It enables easy upgrade from fml4 to fml8. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Overview: fml4 To fml8 (1) It is a little wrong that fml8 works if fml8 overwrites fml4 programs. Currently fml8 can work but it needs automatic conversion in the background. Hence, fml8 modifies fml4 to emulate fml4. Firstly there is a problem. You want to upgrade all ML's at the same time from fml4 to fml8? It is better to upgrade from one to one ? When something fails, you want to downgrade your system if could. We want to support both types. So it is available that some ML's are fml8, other ML's are fml4 in one domain simultaneously. Downgrading if needed are supported. One example of upgrade operation follows: 1. install fml8 2. (in the case of Postfix) add fml8 aliases to postfix's alias_maps. Example: alias_maps = hash:/etc/mail/aliases hash:/var/spool/ml/etc/aliases (fml4) hash:/var/spool/ml/etc/mail/aliases (fml8) 3. convert fml4 ML to fml8 one. fml $ml mergeml fml4's$DIR for example, fml elena mergeml /var/spool/ml/elena Apply 3. for ML's which would be converted to fml8. You can use "makefml mergeml" command to convert aliases, include files, fml4 configuration files and member lists from fml4 to fml8. It is not easy to convert difficult fml4's config.ph file. Now we can convert simple config.ph to fml8 config.cf style file automatically. We suppose this simple config.ph is generated by fml4's "makefml config" command. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Overview: Convert fml4 To fml8 (2) 2004/11: you can replace fml4's fml.pl with fml8's fml.pl. Configure like this. [1. Install fml8] % su fml % sh configure % su root # make install [2. Emulate fml4] # mv /usr/local/fml/fml.pl /usr/local/fml/fml.pl.orig # ln -s /usr/local/libexec/fml/fml.pl /usr/local/fml/fml.pl # ln -s /usr/local/libexec/fml/msend.pl /usr/local/fml/msend.pl # ln -s /usr/local/libexec/fml/mead.pl /usr/local/fml/libexec/mead.pl Precisely fml8 can not read fml4 configuration file. If fml8's fml.pl cannot find config.cf, it tries to convert config.ph in ML's home directory to fml8 config.cf, read it and starts to run. The conversion is incomplete but fml8 can convert simple configurations manipulated by fml4 CUI or GUI. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Overview: Difference Between fml4 and fml8 There are several fml8 variables and functions not related with fml4 since fml8 is re-designed and re-coded from scratch. Also not one to one even if the relation found. Let's see a few examples below. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Anyone Can Post Users registered as members can post ML by default. This default behaviour is common between fml4 and fml8. To set "anyone can post", in the case of fml4, $PERMIT_POST_FROM = "anyone"; in the case of fml8, article_post_restrictions = reject_system_special_accounts permit_anyone reject . ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Subject Tag No subject tag defined by default. This is common between fml4 and fml8 To set the tag such as '[ML_NAME:00100]', in the case of fml4, $SUBJECT_TAG_TYPE = '[:]'; This corresponds to the following fml8 configuration: article_header_rewrite_rules = rewrite_article_subject_tag article_subject_tag = [$ml_name:%05d] fml8 configuration concepts are more orthogonal. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Disable Specific Command In Command Mail Commands such as "members" are prohibited in fml8 by default. fml4 needs the following configurations to disable dangerous commands: &DENY_PROCEDURE('member'); &DENY_PROCEDURE('active'); &DENY_PROCEDURE('members'); &DENY_PROCEDURE('actives'); &DENY_PROCEDURE('status'); &DENY_PROCEDURE('stat'); Old fml4 use no filter by default but fml8 uses filter by default. fml8 applies confirmation for subscribe, chaddr, unsubscribe commands by default. fml4 not. Currently fml8 always applies confirmation, which can not be disabled by configuration. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Discussion "makefml mergeml" command processes the following steps automatically. To clarify details more, explain conversion of aliases and include files below. Our purpose is to run fml8 anyway. If fml8 runs, converter of config.ph runs too. So, we need MTA runs fml4 and fml4 runs fml8. Explain more details. Consider ML driver internal section. For example, when you use Postfix, Postfix reads aliases and recognizes it needs to read include file. By reading include file, Postfix knows how to call fml8 process. Finally, postfix runs /usr/local/libexec/fml/distribute command. Executed distribute command reads config.cf and knows the location of member lists and processes et.al. That is, when fml8 process starts, the following two phases aliases (MTA configuration) include ends. It is mandatory that no duplication in aliases files. For example, if /etc/ postfix/main.cf contains the following configuration: alias_maps = hash:/etc/mail/aliases hash:/var/spool/ml/etc/aliases (fml4) hash:/var/spool/ml/etc/mail/aliases (fml8) aliases of fml4 and fml8 should not have duplication. In othe words, in the case of fml4 process, MTA -> fml4's aliases -> fml4's include -> fml4 (fml.pl) runs in the case of fml8 process, MTA -> fml8's aliases -> fml8's include -> fml8 runs So we need the following condition: remove the ml from fml4's aliases file. add the ml to fml8's aliases file. If no duplication in aliases, both fml4 and fml8 runs on the same host. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Chapter 8. Difference Between fml4 And fml8 In this chapter, we describe the difference beetween fml4 and fml8 Intuitively fml4 vs fml8 is equal to sendmail vs Postfix. It is good image. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Difference Between fml4 And fml8: License. Roughly speaking, fml8 license is composed of Artistic, BSD or GPL. A part of fml8 is either of them. In the case of fml4, almost all codes are written by fml project. The license of such codes is GPL. jcode.pl and some perl modules are exceptions. In the case of fml8, the source tree has sub tree which is divided according to the license. For example, the license of fml/ sub tree is Artictic, cpan/ is Artistic or GPL, gnu/ is GPL and img/ is BSD. See the license files under them on the detail. It is easy to remove some licensed files since the sub-tree is license based. fml8 installs all modules of the tree into the proper path, so installed modules are hybrid of licenses. You need to clarify the license before installation. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Difference Between fml4 And fml8: Command Mail And Error Messages. fml8 selects language of the return mail for command mail and error messages by Accept-Language of the incoming message and other information. See Chapter 33 for more details. In sending back files or messages, fml8 uses MIME/Multipart. tar.gz and zip formats are not supported.. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Difference Between fml4 And fml8: CUI There are two CUI: makefml and fml. The syntax of the two is different. makefml COMMAND ML OPTIONS fml ML COMMAND OPTIONS The only difference is the order of command argument. fml4 command shows processing information as could as possible. Instead fml8 command runs as could as silently since it is proper for automatic process. [4] This behaviour is UNIX style. Table 8-1. Difference between fml4 and fml8: CUI ┌──────────────┬──────────────────────────┬───────────────────────────────────┐ │ Content │ fml4 │ fml8 │ ├──────────────┼──────────────────────────┼───────────────────────────────────┤ │ │"makefml help ML". │ │ │ │"makefml info ML" is same │ │ │show help │as "makefml help ML". If │not implemented. │ │ │the environment variable │ │ │ │PAGER, use it as pager. │ │ ├──────────────┼──────────────────────────┼───────────────────────────────────┤ │ │run "make install" at the │run "configure" and "make install" │ │installation │source top directory. In │at the source top directory. In │ │of fml │fact "make install" │fact "make install" executes │ │ │executes "makefml │install.pl script. │ │ │install". │ │ ├──────────────┼──────────────────────────┼───────────────────────────────────┤ │ │interactive by default. │not interactive. You can use │ │Behaviour of │You can use interactive │configure for most important │ │install script│menu for most important │options. │ │ │options. │ │ ├──────────────┼──────────────────────────┼───────────────────────────────────┤ │create ML │"makefml newml ML" or │makefml newml ML │ │ │"makefml new ML" │ │ ├──────────────┼──────────────────────────┼───────────────────────────────────┤ │templates of │ │ │ │alias files │only for sendmail (also │all for postfix, sendmail, qmail, │ │"makefml │used as postfix for │procmail MTA's. │ │newml" │compatibility). │ │ │generates. │ │ │ ├──────────────┼──────────────────────────┼───────────────────────────────────┤ │alias file │ │ │ │path "makefml │/var/spool/ml/etc/aliases │/var/spool/ml/etc/mail/aliases │ │newml" │ │ │ │generates. │ │ │ ├──────────────┼──────────────────────────┼───────────────────────────────────┤ │how to │ │ │ │generate qmail│makefml qmail-setup ML │"makefml newml" generates it. │ │configuration │ │ │ │files. │ │ │ ├──────────────┼──────────────────────────┼───────────────────────────────────┤ │re-generate │makefml recollect-aliases │not implemented. │ │aliaes. │ML │ │ ├──────────────┼──────────────────────────┼───────────────────────────────────┤ │remove ML │makefml destructml ML │makefml rmml ML │ ├──────────────┼──────────────────────────┼───────────────────────────────────┤ │how to set up │run "makefml mead ML" and │ │ │error │set up aliases properly. │enabled by default. │ │analyzer. │ │ │ ├──────────────┼──────────────────────────┼───────────────────────────────────┤ │test of fml │makefml test ML │not implemented │ ├──────────────┼──────────────────────────┼───────────────────────────────────┤ │set up │makefml fmlserv ML │ │ │LISTSERV style│listserv majordomo is same│not implemented │ │server. │as. │ │ ├──────────────┼──────────────────────────┼───────────────────────────────────┤ │ │ │"makefml subscribe ML ADDRESS". │ │ │"makefml add ML ADDRESS". │Other 4 commands (add subscribe │ │subscribe (add│"makefml adduser ML │adduser useradd) are same as │ │addess to │ADDRESS" is same. the │subscribe. No message is shown │ │member and │changes is shown after the│unless error occurs. This operation│ │recipient │operation. This operation │is applied to │ │list) │is applied to both actives│$primary_recipient_map and │ │ │and members files. │$primary_member_map (recipients and│ │ │ │members files actually). │ ├──────────────┼──────────────────────────┼───────────────────────────────────┤ │ │ │"makefml unsubscribe ML ADDRESS". │ │ │"makefml bye ML ADDRESS". │Other 7 commands ( bye unsubscribe │ │remove address│byeuser is same. the │deluser remove resign signoff │ │from recipient│changes is shown after the│userdel ) are same as unsubscribe. │ │and member │operation. This operation │No message is shown unless error │ │list. │is applied to both actives│occurs. This operation is applied │ │ │and members files. │to $primary_recipient_map and │ │ │ │$primary_member_map (recipients and│ │ │ │members files actually). │ ├──────────────┼──────────────────────────┼───────────────────────────────────┤ │ │"makefml chaddr ML │"makefml chaddr ML OLD_ADDRESS │ │change address│OLD_ADDRESS NEW_ADDRESS". │NEW_ADDRESS". No message is shown │ │(in recipient │the changes is shown after│unless error occurs. This operation│ │and member │the operation. This │is applied to │ │list) │operation is applied to │$primary_recipient_map and │ │ │both actives and members │$primary_member_map (recipients and│ │ │files. │members files actually). │ ├──────────────┼──────────────────────────┼───────────────────────────────────┤ │ │"makefml addactives ML │ │ │ │ADDRESS". Commands │"makefml addactives ML ADDRESS ". │ │add address to│(addactive add2active │No message is shown unless error │ │only recipient│add2actives) are same. the│occurs. This operation is applied │ │list │changes is shown after the│to $primary_recipient_map │ │ │operation. This operation │(recipients file actually). │ │ │is applied to actives │ │ │ │file. │ │ ├──────────────┼──────────────────────────┼───────────────────────────────────┤ │ │"makefml addmembers ML │ │ │ │ADDRESS". Commands │"makefml addmembers ML ADDRESS". No│ │add address to│(addmember add2member │message is shown unless error │ │only member │add2members) are same. the│occurs. This operation is applied │ │list. │changes is shown after the│to $primary_member_map (members │ │ │operation. This operation │file actually). │ │ │is applied to members │ │ │ │file. │ │ ├──────────────┼──────────────────────────┼───────────────────────────────────┤ │ │"makefml off ML ADDRESS". │"makefml off ML ADDRESS". No │ │ │skip is same as off. the │message is shown unless error │ │disable real │changes is shown after the│occurs. This operation is applied │ │time delivery │operation. This operation │to $primary_recipient_map │ │ │is applied to actives │(recipients file actually). │ │ │file. │ │ ├──────────────┼──────────────────────────┼───────────────────────────────────┤ │ │"makefml on ML ADDRESS". │"makefml digestoff ML ADDRESS" or │ │ │the changes is shown after│"makefml digest ML ADDRESS off". No│ │enable real │the operation. This │message is shown unless error │ │time delivery.│operation is applied to │occurs. This operation is applied │ │ │actives file. │to $primary_recipient_map │ │ │ │(recipients file actually). │ ├──────────────┼──────────────────────────┼───────────────────────────────────┤ │ │"makefml matome ML │"makefml digeston ML ADDRESS" or │ │change real │ADDRESS". digest is same. │"makefml digest ML ADDRESS on". No │ │time to digest│the changes is shown after│message is shown unless error │ │delivery. │the operation. This │occurs. This operation is applied │ │ │operation is applied to │to $primary_recipient_map │ │ │actives file. │(recipients file actually). │ ├──────────────┼──────────────────────────┼───────────────────────────────────┤ │ │"makefml addadmin ML │"makefml addadmin ML ADDRESS". No │ │add a remote │ADDRESS". the changes is │message is shown unless error │ │administrator │shown after the operation.│occurs. This operation is applied │ │address. │This operation is applied │to recipients-admin and │ │ │to members-admin file. │members-admin. │ ├──────────────┼──────────────────────────┼───────────────────────────────────┤ │remove a │"makefml byeadmin ML │"makefml byeadmin ML ADDRESS". No │ │remote │ADDRESS". the changes is │message is shown unless error │ │administrator │shown after the operation.│occurs. This operation is applied │ │address. │This operation is applied │to recipients-admin and │ │ │to members-admin file. │members-admin. │ ├──────────────┼──────────────────────────┼───────────────────────────────────┤ │set up │ │ │ │password of │"makefml passwd ML". │ │ │remote │interactive. │"makefml passwd ML" (incomplete ?) │ │administrator │ │ │ │(1). │ │ │ ├──────────────┼──────────────────────────┼───────────────────────────────────┤ │set up │ │ │ │password of │"makefml passwd ML │"makefml passwd ML ADDRESS". │ │remote │ADDRESS" interactive. │interactive. │ │administrator │ │ │ │(2). │ │ │ ├──────────────┼──────────────────────────┼───────────────────────────────────┤ │set up │"makefml passwd ML ADDRESS│"makefml passwd ML ADDRESS │ │password of │PASSWORD". the changes is │PASSWORD". No message is shown │ │remote │shown after the operation.│unless error occurs. This operation│ │administrator │This operation is applied │is applied to etc/passwd-admin │ │(3). │to etc/passwd file. │file. │ ├──────────────┼──────────────────────────┼───────────────────────────────────┤ │menu style │ │ │ │configuration │makefml config ML │incomplete. │ │tool. │ │ │ ├──────────────┼──────────────────────────┼───────────────────────────────────┤ │edit │"makefml edit ML". Ask the│"makefml edit ML". Not ask the │ │configuration │editor to use before │editor to use before running. use │ │file. │running. "vi" by default. │environment variable EDITOR if │ │ │ │specified. "vi" by default. │ ├──────────────┼──────────────────────────┼───────────────────────────────────┤ │fml4 specific │"makefml update-config │ │ │configuration │ML". Commands (update │ │ │file │config-update │no corresponding idea (one │ │conversion │update-config.ph) are │configuration file). │ │(generate cf │same. the operations is │ │ │to config.ph) │shown. │ │ ├──────────────┼──────────────────────────┼───────────────────────────────────┤ │edit cf │ │ │ │template by │makefml config-template ML│not implemented │ │menu. │ │ │ ├──────────────┼──────────────────────────┼───────────────────────────────────┤ │edit template │makefml edit-template FILE│ │ │files "makefml│list up available file │not implemented │ │newml" uses │list unless FILE │ │ │ │specified. │ │ ├──────────────┼──────────────────────────┼───────────────────────────────────┤ │re-generate │ │ │ │files e.g. │makefml │ │ │help at the ml│create-doc-template ML │no corresponding idea. │ │home │ │ │ │directory. │ │ │ ├──────────────┼──────────────────────────┼───────────────────────────────────┤ │convert SRC │ │ │ │file to DST │ │ │ │file with │makefml conv ML SRC DST │not implemented │ │variable │ │ │ │conversion. │ │ │ ├──────────────┼──────────────────────────┼───────────────────────────────────┤ │see log (the │"makefml log ML [OPTION]".│"makefml log ML". options are not │ │last 100 lines│"makefml tail ML" is same.│implemented. │ │shown). │ │ │ ├──────────────┼──────────────────────────┼───────────────────────────────────┤ │set up │ │ │ │admin.cgi │ │ │ │(scripts and │"makefml admin.cgi ML". │incomplete. │ │apache │interactive. │ │ │configuration │ │ │ │helper). │ │ │ ├──────────────┼──────────────────────────┼───────────────────────────────────┤ │set up │ │ │ │ml-admin.cgi │"makefml ml-admin.cgi ML".│ │ │(scripts and │"makefml mladmin.cgi ML" │incomplete. │ │apache │is same. interactive. │ │ │configuration │ │ │ │helper). │ │ │ ├──────────────┼──────────────────────────┼───────────────────────────────────┤ │set up │makefml │ │ │.htpasswd for │html_cgiadmin_passwd ML │not implemented │ │admin.cgi. │ │ │ ├──────────────┼──────────────────────────┼───────────────────────────────────┤ │html_config │ │ │ │(makefml │makefml html_config ML │not implemented │ │internal use │html_config_set is same. │ │ │command) │ │ │ ├──────────────┼──────────────────────────┼───────────────────────────────────┤ │set up │ │ │ │.htpasswd for │ │ │ │ml-admin.cgi │ │ │ │and the │makefml html_passwd ML │not implemented │ │password of │ │ │ │admin command │ │ │ │mail. │ │ │ ├──────────────┼──────────────────────────┼───────────────────────────────────┤ │set up │ │ │ │.htpasswd for │makefml htpasswd ML │not implemented │ │ml-admin.cgi. │ │ │ ├──────────────┼──────────────────────────┼───────────────────────────────────┤ │pgp command │makefml pgp ML │fmlpgp │ │wrapper │ │ │ ├──────────────┼──────────────────────────┼───────────────────────────────────┤ │pgp2 command │makefml pgp2 ML │fmppgp2 │ │wrapper │ │ │ ├──────────────┼──────────────────────────┼───────────────────────────────────┤ │pgpe command │makefml pgpe ML │fmlpgpe │ │wrapper │ │ │ ├──────────────┼──────────────────────────┼───────────────────────────────────┤ │pgpk command │makefml pgpk ML │fmlpgk │ │wrapper │ │ │ ├──────────────┼──────────────────────────┼───────────────────────────────────┤ │pgps command │makefml pgps ML │fmlpgps │ │wrapper │ │ │ ├──────────────┼──────────────────────────┼───────────────────────────────────┤ │pgpv command │makefml pgpv ML │fmlpgpv │ │wrapper │ │ │ ├──────────────┼──────────────────────────┼───────────────────────────────────┤ │gpg command │makefml gpg ML │fmlgpg │ │wrapper │ │ │ ├──────────────┼──────────────────────────┼───────────────────────────────────┤ │admin-auth │ │ │ │(PGP, GPG KEY │makefml admin-auth ML │fmlpgp* command │ │RING │ │--admin-command-mail-auth │ │operation) │ │ │ ├──────────────┼──────────────────────────┼───────────────────────────────────┤ │admin-encrypt │ │ │ │(PGP, GPG KEY │makefml admin-encrypt ML │not implemented │ │RING │ │ │ │operation) │ │ │ ├──────────────┼──────────────────────────┼───────────────────────────────────┤ │dist-auth │ │ │ │(PGP, GPG KEY │makefml dist-auth ML │fmlpgp* command --article-post-auth│ │RING │ │ │ │operation) │ │ │ ├──────────────┼──────────────────────────┼───────────────────────────────────┤ │dist-encrypt │ │ │ │(PGP, GPG KEY │makefml dist-encrypt ML │fmlpgp* command │ │RING │ │--article-post-encrypt │ │operation) │ │ │ ├──────────────┼──────────────────────────┼───────────────────────────────────┤ │set up popfml │ │ │ │(emulate MTA │makefml popfml │fetchfml │ │and ML via │ │ │ │POP). │ │ │ ├──────────────┼──────────────────────────┼───────────────────────────────────┤ │set up │ │write password in configuration │ │password for │makefml pop_passwd │file config.cf. │ │POP. │ │ │ ├──────────────┼──────────────────────────┼───────────────────────────────────┤ │lock ML. │makefml lock ML │not implemented (no corresponding │ │ │ │idea, no giant lock). │ ├──────────────┼──────────────────────────┼───────────────────────────────────┤ │create a │makefml │ │ │template of │bug-report-template ML │not implemented │ │bug report. │send-pr is same. │ │ ├──────────────┼──────────────────────────┼───────────────────────────────────┤ │execute │makefml command ML │not implemented │ │command. │ │ │ ├──────────────┼──────────────────────────┼───────────────────────────────────┤ │set up │makefml delivery_mode ML │not implemented │ │delivery mode.│ │ │ ├──────────────┼──────────────────────────┼───────────────────────────────────┤ │change │ │ │ │configuration │ │ │ │variable in │makefml setq ML │-o options. │ │running │ │ │ │makefml. │ │ │ ├──────────────┼──────────────────────────┼───────────────────────────────────┤ │show │ │ │ │environment │makefml showconfig ML │not implemented / no plan │ │summary where │showconf is same. │ │ │fml runs. │ │ │ ├──────────────┼──────────────────────────┼───────────────────────────────────┤ │show OS │ │ │ │information by│"makefml show". │not implemented / no plan │ │"show COMMAND"│ │ │ │style command.│ │ │ ├──────────────┼──────────────────────────┼───────────────────────────────────┤ │send a file. │makefml resend ML │not implemented / no plan │ ├──────────────┼──────────────────────────┼───────────────────────────────────┤ │upgrade │ │ │ │command: │ │ │ │convert fml │makefml upgrade ML │not needed │ │2.0 to fml │ │ │ │3.0. │ │ │ └──────────────┴──────────────────────────┴───────────────────────────────────┘ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Difference Between fml4 And fml8: GUI (CGI) In the case of fml4, you need to set up .cgi scripts and apache configurations after installation. In the case of fml8, "makefml newml" generates GUI scripts except for the apache configurations. Interface differs a lot. The interface of fml4 GUI is classical. That of fml8 is table based by default. It is a TODO to select GUI skin dynamically. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ File Naming Convention See Chapter 16 for the file naming convention. You need not to know the detail, since the conversion tools convert files from fml4 style to fml8 one. But it is useful to know it to see files. The policy to handle member list and recipient list separately is same. But the file name differs. The file name is "filename-role" style. The role is abbreviated if the role is default. "actives" is renamed to "recipients". The meaning is clear. Instead "members" is "members". "members-admin" is same. "recipients-admin" exists virtually but is is not used. "etc/passwd" is renamed to "etc/passwd-admin". The format differs a little. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Chapter 9. Upgrade And Downgrade Of fml8 ┌─────────────────────────────────────────────────────────────────────────────┐ │ Warning │ ├─────────────────────────────────────────────────────────────────────────────┤ │This chapter describes upgrade and downgrade of fml8. │ │ │ │See Chapter 7 on the upgrade from fml4 to fml8. │ └─────────────────────────────────────────────────────────────────────────────┘ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Upgrade Install again. After fml8 installation, rewrite fml_version line in /usr/local/etc/fml/main.cf to switch fml to the version installed now. Just when the file is saved, fml is changed to the new version. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ downgrade. No need to install. Edit /usr/local/etc/fml/main.cf to back the fml_version to the previous one. Just when the file is saved, fml is changed to the new version. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Chapter 10. Configure CGI ┌─────────────────────────────────────────────────────────────────────────────┐ │ Warning │ ├─────────────────────────────────────────────────────────────────────────────┤ │See the section the Section called Method in Chapter 38 for CGI Internal │ │details. │ │ │ │We assumes you use suexec under apache. │ │ │ │Now fml8 provides both the master cgi to control all ML's in one domain and a│ │cgi for each ML. You can add and remove a user, or view member list et.al. by│ │this interface. Editing of configuration on this cgi is incomplete. │ │ │ │If you use postfix and qmail, you do not need to modify MTA configuration for│ │cgi specific reason. │ └─────────────────────────────────────────────────────────────────────────────┘ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ "makefml newml" Creates CGI Script Always "makefml newml" sets up CGI scripts such as config.cgi under ~fml/public_html /... directory. There are two types of cgi scripts. One is for the whole domain, one for each ML. In creating elena@fml.org ML, makefml creates the following cgi http://lists.fml.org/~fml/cgi-bin/fml/$domain/admin/config.cgi [Example] http://lists.fml.org/~fml/cgi-bin/fml/fml.org/admin/config.cgi for all ML's of fml.org. To control only elena ML, please use http://lists.fml.org/~fml/cgi-bin/fml/$domain/ml-admin/${ml_name}/config.cgi [Example] http://lists.fml.org/~fml/cgi-bin/fml/fml.org/ml-admin/elena/config.cgi [cgi] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Edit .htaccess .htaccess is created but it is configured to deny all. http://lists.fml.org/~fml/cgi-bin/fml/$domain/.htaccess [Example] http://lists.fml.org/~fml/cgi-bin/fml/fml.org/.htaccess The default .htaccess is a dummy like this: AuthName ByPassword AuthType Basic require valid-user Please edit .htaccess properly. Apache does not support ~user style access by default. Please set up apache to enable it. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Example: Master Cgi The role of this cgi is same as limited makefml (CUI). Though this cgi permits ML creation and destruction, all functions makefml has are not supported. The function is limited. Eample: TOP MENU @home.fml.org CGI for configuration fml admin menu fml CGI interface for @home.fml.org ML's mailing list: [elena] command: .. help message ... [subscribe ] [submit][reset] subscribe unsubscribe addadmin byeadmin options Language: list [Japanese] [change] log newml rmml [cgi] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CGI Example: Create ML Select newml and push "submit". No need to select ML name in this stage. You find another menu at the center. Specify the ML name you create and push "submit" at the center. [cgi] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CGI Example: subscribe Specify the ML name and select "subscribe", push "submit". You find another menu at the center. Specify the address to subscribe and push "submit" at the center. [cgi] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CGI Skin Selection config.cgi is TABLE and SELECT based. If you use old style menu, use menu.cgi. for a whole domain ~fml/public_html/fml/DOMAIN/admin/menu.cgi for a ml ~fml/public_html/fml/DOMAIN/ml-admin/menu.cgi ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Chapter 11. Apache Configuration ┌─────────────────────────────────────────────────────────────────────────────┐ │ Warning │ ├─────────────────────────────────────────────────────────────────────────────┤ │See the Section called Method in Chapter 38 for the fml8 CGI internals. │ └─────────────────────────────────────────────────────────────────────────────┘ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Use Suexec Of Apache Build apache enabled with suexec. Run configure by (apache 1.x) configure --enable-suexec --suexec-caller=www In this case, the user "www" can call suexec. Please prepare a user specific for suexec-ed environment. After apache installation, change httpd.conf to allow ~user/cgi-bin/ form. Example: AllowOverride FileInfo AuthConfig Limit Options MultiViews Indexes SymLinksIfOwnerMatch IncludesNoExec ExecCGI Order allow,deny Allow from SPECIFIC_HOST ... snip ... AddHandler cgi-script .cgi ... snip ... ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Chapter 12. Test Before Test ┌─────────────────────────────────────────────────────────────────────────────┐ │ Warning │ ├─────────────────────────────────────────────────────────────────────────────┤ │Set up MTA properly before test of fml. │ └─────────────────────────────────────────────────────────────────────────────┘ In this chapter, fml8 and MTA works on ahodori.fml.org, which is called as the mail server. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Test Of MTA Firstly, check MTA without fml on ahodori.fml.org. Prepare one personal user address such as rudo@fml.org. Usually, just create a user named as "rudo". # useradd rudo Check you can send a mail to rudo@fml.org on ahodori.fml.org and rudo receives the mail. % echo test |Mail rudo@fml.org If it not works, check MTA configuration. See /var/log/maillog et.al to track errors. Secondary, verify mail delivery over network. Send a mail to rudo@fml.org from other host (not ahodori.fml.org). If rudo receives the mail, MTA is o.k. If both work well, MTA configuration must be ok. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Send A Mail To ML Create elena ML (elena@fml.org) and subscribe rudo@fml.org to elena ML. % su fml % makefml newml elena % makefml add elena rudo@fml.org Send a test mail to elena@fml.org from on the host and from other host (not ahodori.fml.org). Verify the header of this test mail should be "From: rudo@fml.org" since fml8 checks the From: header field. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Checkpoints If something not work well, check the following points: check the mail server log (e.g. /var/log/maillog) check the fml log (e.g. /var/spool/m/elena/log) fml can pass the message to MTA ? (e.g. /var/spool/m/elena/log) MTA succeeds to deliver it? (e.g. /var/log/maillog) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Test Of fml8 Itself. *** not yet implemented ***. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Reset After Test. It is easy to re-create this mailing list (e.g. test ML). % su fml % makefml rmml test % makefml newml test The removed ML home is left as /var/spool/ml/@test.$DATE.$SEQUENCE. Please remove it since this is a test to avoid the duplication in the future. % rm -fr /var/spool/ml/@test.$DATE.* III. How To Customise Topics driven in this part. Table of Contents 13. What A User Can 14. What Can You Do On The Mailing List Server 15. Modify Configuration Files 16. [Caution] File Names 17. Case Studies Of Customization 18. Header Rewriting 19. Extend Command 20. Filtering 21. Extend Message 22. Be ML Articles public via WWW ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Chapter 13. What A User Can Get ML Guide Send the mail with guide to elena-ctl@fml.org address. fml8 sends back the guide message to the sender. If a file named "guide" is found at $ml_home_dir, it is used as a message template. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Subscribe Suppose elena@fml.org ML. Firstly, send the mail with subscribe YOUR-NAME to elena-ctl@fml.org address. fml8 sends back the confirmation to both addresses. Please send back the reply for the confirmation to elena-ctl@fml.org again. When your reply to the confirmation is confirmed to be valid, fml8 add the address as a new ML member. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Posting Article Send a mail to elena@fml.org. MTA running on the mailing list server host (on e.g. ahodori.fml.org) receives the mail and finally kicks off /usr/local/ libexec/fml/distribute command. "distribute" command recieves the message from STDIN, rewrites the header, save it in the spool directory and pass it back to MTA for delivery. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Distribution Process 1) fml8 adds a tag to the subject, update the article sequence number. Example: Subject: [elena:00100] teddy bear is cute. (no tag by default). 2) save article (as a text file). 3) create a HTML version of the article under ~fml/public_html/ directory. 4) update database (udb) on thread. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Variables ┌─────────────────────────────────────────────────────────────────────────────┐ │ Warning │ ├─────────────────────────────────────────────────────────────────────────────┤ │*** sorry, not yet written *** │ └─────────────────────────────────────────────────────────────────────────────┘ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Example: Boot Sequence Of Distribute Process fml boot loader boots off in the following way. /usr/local/libexec/fml/distribute command is symlink-ed to /usr/local/libexec/ fml/loader. These files are same. /usr/local/libexec/fml/loader reads /usr/local/etc/fml/main.cf firstly. $fml_vesrion such as "current-20010501" is defined in the main.cf. fml8 resolves $fml_version from it and determines the library path as /usr/local/lib /fml/current-20010501/. fml8 loads perl modules under it. fml8 sets up @INC properly. fml loader loads FML::Process::Switch module and check $0 (process name). fml knows the process role from $0. In this case of distribute, fml loads FML::Process::Distribute module (defined as /usr/local/ etc/fml/$fml_version/modules), switch itself to it and processes distribution. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Help: When You Want To know The Usage Send the mail with help to elena-ctl@fml.org address. It sends back the help message to the sender. If a file named "help" is found at $ml_home_dir, it is used as a message template. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Get Past Articles Send the mail with get NUMBER to elena-ctl@fml.org address where NUMBER is the article number. fml8 sends back articles by mime/multipart form to the sender. You can use MH style arguments as NUMBER. [Example] get 100 get 1-100 get first:3 get last:3 get 1-100,first:3,last:3 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Unsubscribe In the case of elena@fml.org ML, send the mail with unsubscribe YOUR-NAME to elena-ctl@fml.org (control address). fml8 sends back the confirmation to the sender. Please send back the reply for the confirmation to elena-ctl@fml.org again. When your reply to the confirmation is confirmed to be valid, fml8 removes the address. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Command Mail (Control fml By Sending Mail) fml8 accepts control commands which is sent as a mail. It is called "command mail". Important: The use of CUI (makefml/fml) is basic in fml world. It is expected you should use CUI if you can login the mailing list server. The role of command mail is to delegate fml control priviledge to users who cannot login the mailing list server. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Flow Consider elena ML. Send the command mail to elena-ctl@fml.org which is the address for command mail. MTA receives the mail and finally kicks off /usr/ local/libexec/fml/command program. This program receives the mail (command mail) from STDIN , processes the requests and sends back the result to the sender. The mail to send back is passed to MTA for delivery via SMTP. ┌─────────────────────────────────────────────────────────────────────────────┐ │ Warning │ ├─────────────────────────────────────────────────────────────────────────────┤ │The result is aggreagated to one msssage as MIME/Multipart. This is different│ │from fml4 behaviour. │ └─────────────────────────────────────────────────────────────────────────────┘ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Perl Modules For Command Mail All modules which CUI, GUI and command mail uses are implented as FML::Command:: class. In fact, a sub set of FML::Command:: class is allowed as command mail. $user_command_mail_allowed_commands, $anonymous_command_mail_allowed_commands and $admin_command_mail_allowed_commands variables defines it. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Chapter 14. What Can You Do On The Mailing List Server On the host which serves ML driver, you can use CUI (makefml and fml) and edit all configuration files as you like. It implies you are the greatest administrator :) "makefml" command of fml8 is same as fml4 as could as possible to preserve compatibility. See the Section called Difference Between fml4 And fml8: CUI in Chapter 8 on the detail of the difference. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ On The Host You need no confirmation in using makefml. Person who can login the host of mailing list server has priviledge for all ML's on the host. So, He/She can edit all configuration files. But He/She may do wrong operations. To avoid careless wrong operations, in usual cases you should use CUI (makefml or fml) to configure fml. Of course you can edit files directly if you can understand fml structures. By default we recommend you should use CUI always on the host. "fml" command is same as "makefml" command except for the argument order. makefml COMMAND ML OPTIONS fml ML COMMAND OPTIONS Please either as you like. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Policy Of Command Creation fml8 provides a different command for each function. Its policy makes the number of commands infinite. So, except for some special cases, we should unify all functions into makefml/fml command since such commands can be shared among CUI, GUI and commmnd mail. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Operation May Modify The Specific ML (Read + Write) We should implement sub-command of makefml/fml when some operation may modify the specific ML. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Operation For Read Only Data Of The Specific ML (Read Only) We should implement it as a makefml/fml command since it is related to the specific ML. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Show The General Data (Read Only) If the data is not related to the specific ML, for example, see the module manual, aliases on the host, we implement specific commands other than makefml/ fml. This command name begins with "fml" prefix. fmladdr [-n] fmlalias [-n] fmldoc MODULE fmlconf [-n] ML ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ML Specific But A Command Wrapper PGP / GPG related command (e.g. fmlpgp) is very command speicific. So, it looks difficult to incorporate them into "makefml" and "fml" framework. So we implement it as another command such as fmlpgp, fmlgpg, ... ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Misc We implement specific commands other than makefml/fml. This command name begins with fml prefix. For example, "fmlhtmlify" is a conveter from text to html form. This command is used to convert both fml spool and MH folders. fmlhtmlify [-I DIR] $src_dir $dst_dir ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Common Command Line Options Programs under libexec/ and bin/ supports the following common command line options. --debug --help -c file -o key=value Use -c to specify non default main.cf path. -o overwrites configuration variables. Plural -o are acceptable. -o key1=value1 -o key2=value2 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Create A New ML % su fml % makefml newml ML If ML without @domain part is specified, the domain of the ML is treated as the default domain. Both ML and ML@DOMAIN form is o.k. for the default domain. Example: In the case of default domain: % makefml newml elena % makefml newml elena@fml.org In the case of virtual domain, you should specify the address with the domain such as user@domain form as ML string. See the section Chapter 5 for more details. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Remove An ML Example: % su fml % makefml rmml ML fml accepts ML string without @domain as the default domain. Both user and user@domain syntax is acceptable. Example: in the case of default domain: % makefml rmml elena % makefml rmml elena@fml.org Please use user@domain syntax for virtual domains. It reverts the action newml did. It removes ML home directory, alias entries and ~fml/.qmail-*. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Subscribe and Unsubscribe Use "useradd" commadn to subscribe the user, "userdel" to unsubscribe the user. Example: % su fml % makefml useradd ML ADDRESS % makefml userdel ML ADDRESS fml treats ML without @domain part as one of the default domain. Examle: % su fml % makefml useradd elena rudo@nuinui.net % makefml userdel elena rudo@nuinui.net % makefml useradd elena@fml.org rudo@nuinui.net % makefml userdel elena@fml.org rudo@nuinui.net For convenience, useradd is an acronym. The following commands, useradd adduser subscribe add , are same as useradd. In the same way, userdel deluser bye remove resign signoff unsubscribe are same as userdel. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Change the registered address Example: % su fml % makefml chaddr ML OLD-ADDRESS NEW-ADDRESS fml treats ML without @domain part as one of the default domain. For example, Example: in the case of a virtual domain % su fml % makefml chaddr elena rudo@nuinui.net teddy@nuinui.net % makefml chaddr elena@fml.org rudo@nuinui.net teddy@nuinui.net ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Stop Realtime Delivery % makefml off elena ADDRESS Delivery to ADDRESS is switched to digest. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Start Realtime Delivery % makefml on elena ADDRESS Delivery to ADDRESS is switched from digest to real time. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ See Log % makefml log elena % makefml log elena@fml.org ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ See The Member List % makefml list elena It shows recipients of this ML. Also, % makefml list elena recipient lists up only recipients of this ML. Instead % makefml list elena member shows the list who can post this ML. You can specify arbitrary MAP as an argument to show it. % makefml list elena MAP MAP can be an abbrebiation. For example, you can use "xxx" as MAP to imply "primary_xxx_map" or "xxx_maps". ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Modify Configuration Edit config.cf directly now. Configuration helper tool is incompletely implemented. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Add or Remove A Remote Administrator. ┌─────────────────────────────────────────────────────────────────────────────┐ │ Warning │ ├─────────────────────────────────────────────────────────────────────────────┤ │A remote administor is a person who cannot login to the mail server but │ │control an ML by sending a command mail (which is called "admin command"). │ │ │ │Please use CUI to control remote administrators. If you use CUI, you can have│ │priviledge to do since the use of CUI needs login to this host. │ └─────────────────────────────────────────────────────────────────────────────┘ [Example] % su fml % makefml addadmin ML ADDRESS % makefml deladmin ML ADDRESS fml treats ML without @domain part as one of the default domain. [Example: in the case of a virtual domain] % su fml % makefml addadmin elena rudo@nuinui.net % makefml deladmin elena rudo@nuinui.net % makefml addadmin elena@fml.org rudo@nuinui.net % makefml deladmin elena@fml.org rudo@nuinui.net For convenience, adminadd addpriv are same as addadmin. byeadmin byepriv are same as deladmin. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Add or Remove A Modrator [Example] % su fml % makefml addmoderator ML ADDRESS % makefml delmoderator ML ADDRESS fml treats ML without @domain part as one of the default domain. [Example: in the case of a virtual domain] % su fml % makefml addmoderator elena rudo@nuinui.net % makefml delmoderator elena rudo@nuinui.net % makefml addmoderator elena@fml.org rudo@nuinui.net % makefml delmoderator elena@fml.org rudo@nuinui.net ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ "fml" And "makefml" Command "fml" (/usr/local/bin/fml) and "makefml" (/usr/local/bin/makefml) is same except for argument order. Please use it as you like. % fml ML COMMNAD [OPTIONS] % makefml COMMAND ML [OPTIONS] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Show Addresses (Users + Aliases) "fmladdr" (/usr/local/bin/fmladdr) lists up all users on this host. It shows users defined in /etc/passwd and aliases defined in Postfix. % fmladdr ┌─────────────────────────────────────────────────────────────────────────────┐ │ Warning │ ├─────────────────────────────────────────────────────────────────────────────┤ │The difference between "fmladdr" and "fmlalias" is whether it contains users │ │defined at /etc/passwd or not. "fmladdr" contains it but "fmlalias" not. │ │"fmlalias" lists up all users defined at aliases. │ └─────────────────────────────────────────────────────────────────────────────┘ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Show Alias fmlalias (/usr/local/bin/fmlalias) shows all aliases. Precisely speaking, it shows all aliases defined as valid aliases of Postfix. % fmlalias ┌─────────────────────────────────────────────────────────────────────────────┐ │ Warning │ ├─────────────────────────────────────────────────────────────────────────────┤ │The difference between "fmladdr" and "fmlalias" is whether it contains users │ │defined at /etc/passwd or not. "fmladdr" contains it but "fmlalias" not. │ │"fmlalias" lists up all users defined at aliases. │ └─────────────────────────────────────────────────────────────────────────────┘ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Show Configuration "fmlconf" (/usr/local/bin/fmlconf) takes ML name as an argument. It shows all variables of the specified ML. If "-n" option specified, it shows variables different from default ones. To list up all variable list, % fmlconf elena To list up variables different from the default one, % fmlconf -n elena ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Show Perl Module Document The usage of fmldoc is same as perldoc. This is a wrapper for perldoc. To see FML::Process::Kernel perl module document, % fmldoc FML::Process::Kernel ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Convert Articles To HTML Form By default, fml converts the article to HTML form. "fmlhtmlify" command is a tool to convert all articles to initialize the html archive. [Usage] % fmlhtmlify SPOOL_DIRECTORY HTML_ARCHIVE_DIRECTORY [Example] % fmlhtmlify /var/spool/ml/elena/spool /some/where/mlarchive/elena ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Recipes 1. I've removed ML accidentally. Can I revive it ? (CUI,CGI,admin command) 2. Add an address who can post (CUI,CGI,admin command) 3. Add an address who receive articles but not post. 4. Change registered address. 1. I've removed ML accidentally. Can I revive it ? (CUI,CGI,admin command) If you have removed ML by running "makefml rmml", please use % makefml reviveml ML Same as CGI. When you use admin command (remote administration), you cannot use this operation. If you have removed ML by running "rm -fr /var/spool/ml/elena", you cannot revive it. Please revive ML from back-up. 2. Add an address who can post (CUI,CGI,admin command) Usually run % makefml add ML ADDRESS If you post from both office and home but want to receive article at office, it is better to add an address who can post but not receive. It implies we should add the address to only member_maps. On the mailing list server host, use makefml. % makefml addmember ML ADDRESS The following 4 commands are same function: add2member add2members addmember addmembers When you use "admin command", as in same way. To: elena-ctl@fml.org Subject: admin pass PASSWORD admin addmember ML ADDRESS CGI does not provide this function now. 3. Add an address who receive articles but not post. The usage of address, who cannot post but can receive articles, is for such as mail magazine case. n the mailing list server host, use makefml. % makefml addrecipient ML ADDRESS This ADDRESS is added to only recipient_maps. The following 4 commands are same function: add2recipient add2recipients addrecipient addrecipients The usage is same in "admin command". To: elena-ctl@fml.org Subject: admin pass PASSWORD admin addrecipient ML ADDRESS CGI does not provide this function. 4. Change registered address. On the mailing list server host, use makefml. % makefml chaddr ML OLD-ADDRESS NEW-ADDRESS The usage is same in "admin command". To: elena-ctl@fml.org Subject: admin pass PASSWORD admin chaddr ML OLD-ADDRESS NEW-ADDRESS "chaddr" command is available in using CGI. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Chapter 15. Modify Configuration Files Change Default For All ML's On Thie Host Edit /usr/local/etc/fml/site_default_config.cf file. The format is same as config.cf. This file corresponds to site_force.ph of fml4. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Chapter 16. [Caution] File Names References: fml-devel 205 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Filename Structure The fundamental syntax is FILENAME-ROLE . For example, fml uses the following syntax for address lists. recipients-ROLE members-ROLE Other than address lists, fml uses similar manner for other type of files. For example, passwd-admin passwd-moderator passwd-cgiadmin for several password files. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Case Study: Address List primary_recipient_maps = recipients # add actives for backward compatibility recipient_maps = recipients actives ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Case Study: List Of Remote Administrators recipients-admin members-admin ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Case Study: List Of Moderators recipients-moderator members-moderator ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Case Study: Remote Administrator Password Files etc/passwd-admin ┌─────────────────────────────────────────────────────────────────────────────┐ │ Warning │ ├─────────────────────────────────────────────────────────────────────────────┤ │etc/passwd, lack of role name, was used in the case of fml4. │ └─────────────────────────────────────────────────────────────────────────────┘ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Chapter 17. Case Studies Of Customization Case Study: Auto File Responder Modify delivery process ( libexec/distribute ) to send back /some/where/help file. For example, when a user can send anything to help@fml.org, fml sends back the help file to the sender. In this case, set the following at config.cf article_post_restrictions = permit_anyone and define the following hook after =cut line. $distribute_run_start_hook = q{ $curproc->reply_message( { type => "text/plain; charset=iso-2022-jp", path => "/some/where/help", filename => "help", disposition => "help example", }); $curproc->stop_this_process(); }; The last $curproc->stop_this_process(); method of fml8 corresponds to the statement $DO_NOTHING = 1; of fml4. After this statement, the normal processing stops. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Case Study: Anyonen Can Use Command Mail. $command_mail_restrictions defines who can use command mail. By default user registerd as a poster can use command mail. To enable that anyone can use command mail, set command_mail_restrictions = permit_anyone ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Recipes 1. Anyone can use command mail. 2. Anyone except system accounts can use command mail. 3. nobody use command mail. 1. Anyone can use command mail. command_mail_restrictions = permit_anyone 2. Anyone except system accounts can use command mail. command_mail_restrictions = reject_system_accounts permit_anyone 3. nobody use command mail. command_mail_restrictions = reject There are other methods to disable command mail. See the Section called Case Study: Disable Command Mail for more details. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Case Study: Disable Command Mail It is most safe to remove command mail entries from aliases. Another 2nd best solution follows: use_command_mail_function = no In this case, /usr/local/libexec/fml/command runs once but does not work and ends as soon as possible. The following solution may be possible. use_command_mail_function = yes command_mail_restrictions = reject When fml receives the incoming command mail, it inform the rejection to the sender in all cases. This configuration works but it evalutates each line. It is useless. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Case Study: Mail Magazine (1) ┌─────────────────────────────────────────────────────────────────────────────┐ │ Warning │ ├─────────────────────────────────────────────────────────────────────────────┤ │Please use PGP auth if could, though we describe header based auth here. Also│ │please set up MTA properly e.g. to disable smtp interfaces as could as │ │possible. │ │ │ │It is a problem that PGP auth requires user's skill at some level. │ └─────────────────────────────────────────────────────────────────────────────┘ In the case of header based auth, you can create a mail magazine by using the asymmetirc member list. Consider asymmetric case of member list (list of persons who can post) and recipient list below. Firstly, remove $primary_member_map from $member_maps. Instead, define $ml_home_dir/members-mailmag who can post to $member_maps. member_maps = $ml_home_dir/members-mailmag The use of "subscribe" command is same as default one since "subscribe" command changes $primary_member_map not $member_maps. It is a little tricky but crafty use of $primary_XXX_map and $XX_maps enhances fml8 configuration. In this case, when a new user is subscribed, the user address is added to both $ml_home_dir/members ($primary_member_map) and $ml_home_dir/recipinets ($primary_recipient_map). But $member_maps is defined as $ml_home_dir/ members-mailmag. $ml_home_dir/members is not used. Hence, only the list of recipients is updated but the list of posters is NOT changed. ┌─────────────────────────────────────────────────────────────────────────────┐ │ Warning │ ├─────────────────────────────────────────────────────────────────────────────┤ │Strictly speaking, this configuration is not enough safe. If somebody fakes │ │From: address, he/she can post since fml checks only From: address. │ │ │ │So, pgp auth is recommended. │ └─────────────────────────────────────────────────────────────────────────────┘ Another solution. primary_member_map = $tmp_dir/members-dummy and use $member_maps (member_maps = $ml_home_dir/members) for normal use. It has only poster's addresses. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Case Study: Mail Magazine (2) After 2004/06, fml8 supports the queuing system. So the outgoing mail fails once, after the confirmation of content, you flush again to deliver if the content is ok. The queuing system support enables "queue once, dequeue after content confirmation". It avoids delivery of wrong content. The configuration is as follows. Specify irrelevant port at config.cf. smtp_servers = IRRELEVANT_PORT [Example] smtp_servers = 127.0.0.1:2025 This makes the delivery fail. The message is queued. Check the content. If the content is correct and delivery is ready, runs the following command by specifying the correct transport. % fml -o smtp_servers=TRANSPORT ML_NAME flushq [Example] % fml -o smtp_servers=127.0.0.1:25 ML_NAME flushq "flush" and "flushq" command are same. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Case Study: Anyone Can Post. article_post_restrictions = permit_anyone $article_post_restrictions parameter controls who can post to this ML. To set this as "permit_anyone", anybody (including system special account e.g. root, postmaster) can post. By default, $article_post_restrictions is defined as follows for fml4 compatibility, article_post_restrictions = reject_system_special_accounts permit_member_maps reject "reject_system_special_accounts" denies post if From: looks like system accounts e.g. root, postmaster. This configuration means that system special accounts cannot post and only user contained in $member_maps can post article. Attention that reject_XXX and permit_XXX statement is first match. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ recipes 1. Any persons in a domain can post always. 1. Any persons in a domain can post always. It is not easy to handle global variables in the case of fml4 . By using the following restriction, you can ermit only sender of example.co.jp domain and reject other domain. [/var/spool/ml/elena/config.cf] article_post_restrictions = reject_system_special_accounts permit_member_maps reject member_maps = pcre:$ml_home_dir/sender.pcre [$ml_home_dir/domains] \S+\@example.co.jp ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Case Study: Article Posting Allowd If It Is A Reply To The Former One. From time to time we can find that a posted article is denied due to posting from not a member. One reason is that the member who replied some article forgot to notify changes of his/her mail address to the mailing list administrator. Another reason that his/her mail address is changed from @DOMAIN to @SUB.DOMAIN vice versa. Yet another reason is that he/she replied it from other location which recieved the article via mail forwarding at some other host. After 2004/10/28 fml8 current, fml8 supports "allow article post irrespective of the From: address if some condition satisfied" at article_post_restrictions. The current implementation suppors the condition that "if the reply refers a known message-id within some time limit". Precisely speaking, "known message-id" implies the id is found at the message-id database which holds In-Reply-To: and References: of old articles within some time limit (e.g. one week). ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Recipes 1. Article Posting Allowd If It Is A Reply To The Former One. 1. Article Posting Allowd If It Is A Reply To The Former One. "check_article_thread" is the keyword to enable this check. article_post_restrictions = reject_system_special_accounts check_article_thread permit_member_maps reject Not used by default. To use it, specify it at article_post_restrictions. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Discussion Hmm, this is similar to a cookie. There are some problems. 1) What is proper time scale ? $article_post_article_thread_lifetime controlls it. One day by default. article_post_article_thread_lifetime = 86400 Also, boundary of the time scale ? When starts the allowd window ? It starts from the first article of the specific thread ? Or from the last article ? 2) More restricted condition support required ? If so, we should check the corelation between subject: and the thread? ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Recipes 1. Only A Few Persons Can Starts Article Thread. 1. Only A Few Persons Can Starts Article Thread. member_maps = $tmp_dir/members-thread-init article_post_restrictions = reject_system_special_accounts check_article_thread permit_member_maps reject Only persons registered at members-thread-init file can post article always. Other persons can post the article if the article is a reply to some other article. Hmm, it looks a variation of moderator system ? Better that they use PGP auth if could. member_maps = $tmp_dir/members-thread-init article_post_restrictions = reject_system_special_accounts check_article_thread check_pgp_signature reject ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Case Study: PGP/PGP Based Authentication In Posting ┌─────────────────────────────────────────────────────────────────────────────┐ │ Caution │ ├─────────────────────────────────────────────────────────────────────────────┤ │Please install Crypt::OpenPGP perl module firstly. It is better to use OS │ │dependent pacakge system since Crypt::OpenPGP depends a lot of other │ │packages. │ └─────────────────────────────────────────────────────────────────────────────┘ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Recipes 1. PGP/PGP Based Authentication In Posting 1. PGP/PGP Based Authentication In Posting check_pgp_signature options enables PGP/GPG based auth. If the degital signature is confirmed, the user can post articles. article_post_restrictions = reject_system_special_accounts check_pgp_signature reject This function is disabled by default. Change article_post_restrictions if use. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Key Operations PGP KEY RING directories are separeted for each purpose. For example, the keyring dir for article pgp auth is $ml_home_dir/etc/pgp-article-post-auth/ directory, the keyring dir for remote administration by command mail is $ml_home_dir/etc/pgp-admin-command-mail-auth/ directory. Use pgp2, pgp5 and gpg commands to edit keys under them It is useful to use the following fmlpgp wrapper command. The wrapper sets up proper environment variables. [Example] operations for elena ML fmlpgp elena --article-post-auth -kg the command line options available: --article-post-auth (auth for post article) --command-mail-auth (auth for command mail) --admin-command-mail-auth (auth for admin command mail) --article-post-encrypt (article encryption) Available wrappers follow: pgp2: fmlpgp pgp5: fmlpgp5 fmlpgpe fmlpgpk fmlpgps fmlpgpv gpg: fmlgpg fmlgpgv ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Case Study: Authenticate command mail by PGP/GPG 1. Authenticate user mode command mail by PGP/GPG. 2. Authenticate admin command mail by PGP/GPG. 1. Authenticate user mode command mail by PGP/GPG. command_mail_restrictions = check_pgp_signature reject Use CLI ( fmlgpg fmlgpgv fmlpgp fmlpgp5 fmlpgpe fmlpgpk fmlpgps fmlpgpv ) to manipulate PGP/GPG keys. Example: generate key for mailing list "ML_NAME". % fmlpgp --command-mail-auth ML_NAME -kg See the Section called Case Study: PGP/PGP Based Authentication In Posting for more details. 2. Authenticate admin command mail by PGP/GPG. admin_command_mail_restrictions = check_pgp_signature reject Use CLI ( fmlgpg fmlgpgv fmlpgp fmlpgp5 fmlpgpe fmlpgpk fmlpgps fmlpgpv ) to manipulate PGP/GPG keys. Example: generate key for mailing list "ML_NAME". % fmlpgp --admin-command-mail-auth ML_NAME -kg See the Section called Case Study: PGP/PGP Based Authentication In Posting for more details. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ case study: hierarchical ML Consider usual ML's which allows post from registered members. For example, sales 1, 2 and 3 division. Create sales-1, sales-2 and sales-3 ML. Each division manages each member list. Also, create sales ML other than that to inform the whole sales members. If you send a mail to sales ML, the mail is sent to all members of sales-1, sales-2 and sales-3 ML. Define the following $recipient_maps in the config.cf of sales ML. recipient_maps += $ml_home_dir/../sales-1/recipients recipient_maps += $ml_home_dir/../sales-2/recipients recipient_maps += $ml_home_dir/../sales-3/recipients Define $member_maps in the same way to allow post from all sales members: member_maps += $ml_home_dir/../sales-1/members member_maps += $ml_home_dir/../sales-2/members member_maps += $ml_home_dir/../sales-3/members Instead of $member_maps change, it is simple that you allow post from anybody. If so set article_post_restrictions = permit_anyone This example is simplest. It is easy to use this style. If you need to use SQL e.g. MySQL, it is modern. It needs a lot of preparions and operation know-how. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ I Want To Use ML By My Account. When you set up an ML within your account, for example when you are using virtual domain service of ISP, you need to use a mail processor such as procmail. To catch up messages to ML's, you need to filter messages according to To: or Cc: in the mail header. fml8 expects the user uses a filter tool such as procmail in such a situation. fml8 distribution itself does not provide such a tool. When running "makefml newml", "makefml" creates/updates ~/.procmailrc sample at /var/spool/ml/etc/procmail/procmailrc. Please use it as a sample. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ~/.procmailrc Example PATH=$HOME/bin:/usr/bin:/usr/ucb:/bin:/usr/local/bin:/usr/pkg/bin MAILDIR=$HOME/Mail # You'd better make sure it exists DEFAULT=$HOME/Mail/mbox LOGFILE=$MAILDIR/procmail.log LOCKFILE=$HOME/.lockmail VERBOSE=on :0 * To.*elena@fml.org | /usr/local/libexec/fml/fml.pl /var/spool/ml/elena :0 * To.*elena-ctl@fml.org | /usr/local/libexec/fml/fml.pl /var/spool/ml/elena --ctladdr # last resort, mail for me et. al. :0 inbox/. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Virtual Domain Case The procmail rules above contains ml_name and ml_domain within it. So it does not need special handling for virtual domain. It is same for both default domain and virtual domain. MTA configuration is another issue. Please contact administrator on it. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Case Study: Office (1) Edit /usr/local/etc/fml/site_default_config.cf to apply the effect to all ML's. No tag of subject. [5] article_header_rewrite_rules -= rewrite_article_subject_tag This means header rewrite rules minus "adding subject tag" operation. Prepend office# at X-ML-Name:. That is, mlname is changed to office#mlname. # office#$mlname outgoing_mail_header_x_ml_name = office#$ml_name Anybody can post to this ML since customers send mails to this address. article_post_restrictions = permit_anyone In this case, anybody including system special accounts e.g. root, postmaster can post. Disable almost all filters since a lot of customer messages looks something wrong. use_article_filter = no Change spool type as subdir since the number of articles may become over million. spool_type = subdir Disable command mail. use_command_mail_function = no If someboby want to use command mail (e.g. by CGI), we use this variable. It is recommended to remove proper alias entries if could to ensure the command mail is prohibited. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Case Study: Office (2) Edit /usr/local/etc/fml/site_default_config.cf to apply the effect to all ML's. Add uppercase-ed ML name to the article subject tag. article_subject_tag = (\U$ml_name\E %05d) For example, an article of support@example.co.jp has the tag Subject: (SUPPORT 10000) . Allow the use of command mail, which comes only from the specific domain (my domain e.g. example.co.jp). This hook enables it. $command_verify_request_end_hook = q{ my $cred = $curproc->credential(); my $from = $cred->sender(); unless ($from =~ /\@example\.co\.jp/i) { $curproc->stop_this_process(); $curproc->logerror("deny command request from $from"); } }; ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Chapter 18. Header Rewriting Header information is stored at FML::Header class object. FML::Header class inherits Mail::Header. See Mail::Header for method details. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Recipe's 1. Uppercase the tag in article Subject: 2. Lowercase the tag in article Subject: 1. Uppercase the tag in article Subject: article_subject_tag = [\U$ml_name\E:%05d] (available after 2002/10/29 snapshot) 2. Lowercase the tag in article Subject: article_subject_tag = [\L$ml_name\E:%05d] (available after 2002/10/29 snapshot) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Chapter 19. Extend Command Case Study: Create Your Own Help Command. To extend help command of elena ML, create help.pm perl module at /var/spool/ml/elena/local/lib/FML/Command/User/help.pm In loading module, libraries under local/ path is preferred. So, this help command is loaded for help command (FML::Command::User::help). ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Recipes 1. initialize ML by admin command. 2. add or remove a log of user by admin command. 3. send welcome message when "admin add" runs. 4. restrict subscribers. 5. I forget how to use admin command ? 1. initialize ML by admin command. now allowd. Please use CUI on the mail server host. 2. add or remove a log of user by admin command. Specific command not yet supported. Use ordinary admin commands. admin add .. admin add .. admin add .. 3. send welcome message when "admin add" runs. not implemented. 4. restrict subscribers. not implemented. 5. I forget how to use admin command ? See fml8 document ;-) http://www.fml.org/software/fml8/ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Chapter 20. Filtering 1. Where the mail is sent back to when filter system rejects ? 2. Reject SPAM messages by using spamassassin. 3. Add X-Spam-Status: Yes header field if spamassassin determines the message as a spam. 4. How to write a hook to reject a message with danger attachment(s). 1. Where the mail is sent back to when filter system rejects ? By default, It is defined as use_article_filter_reject_notice = yes article_filter_reject_notice_recipient = maintainer sender When the filter system rejects the request, fml sends back it to both the ML maintainer and the sender. To change the recipient to the sender (From: address) only, set article_filter_reject_notice_recipient = sender To notify the rejection to both ML maintainer and the sender, set article_filter_reject_notice_recipient = maintainer sender To disable notification of rejection, set use_article_filter_reject_notice = no 2. Reject SPAM messages by using spamassassin. Case 1: use internal filter. use_article_spam_filter = yes article_spam_filter_drivers = spamassassin Case 2: In this case, fml8 use not spamassassin internal filter but use a hook. $distribute_verify_request_end_hook = q{ my $spamassassin = '/usr/pkg/bin/spamc -c'; use FileHandle; my $wh = new FileHandle "| $spamassassin"; if (defined $wh) { $wh->autoflush(1); my $msg = $curproc->incoming_message(); $msg->print($wh); $wh->close(); if ($?) { $curproc->log("spam: (code = $?)"); $curproc->stop_this_process(); } } }; 3. Add X-Spam-Status: Yes header field if spamassassin determines the message as a spam. $distribute_verify_request_end_hook = q{ my $spamassassin = '/usr/pkg/bin/spamc -c'; use FileHandle; my $wh = new FileHandle "| $spamassassin"; if (defined $wh) { $wh->autoflush(1); my $msg = $curproc->incoming_message(); $msg->print($wh); $wh->close(); if ($?) { $curproc->log("spam: (code = $?)"); my $hdr = $curproc->incoming_message_header(); $hdr->add('X-Spam-Status', 'Yes'); } } }; This is a little tricky but it works well. 4. How to write a hook to reject a message with danger attachment(s). fml8 analyzed the incoming message firstly and creates a chain of Mail::Message objects on memory. It is easy for fml8 to analyze the chain to check the message content. The following examples uses hooks. In all cases, if matched, call stop_this_process() to stop further processing. Pay attension that these examples do not try to return error messsages. If you need to return error messages, use reply_message(). It is better not to return it since this message must be a virus or a spam. Here is an example to check attachment keywords e.g. .exe in mesages. Before fml8 2004/12/08 current, it follows: $distribute_verify_request_start_hook = q{ my $msg = $curproc->incoming_message() || undef; for (my $m = $msg; $m ; $m = $m->{ next } ) { my $hs = $m->message_fields() || ''; if ($hs =~ /filename=.*\.(com|vbs|vbe|wsh|wse|js|exe|doc|rtf)/o) { $curproc->log("attachment \.$1 found"); $curproc->stop_this_process(); } } }; After fml8 2004/12/08 current, it follows: $distribute_verify_request_start_hook = q{ my $msg = $curproc->incoming_message() || undef; my $list = $msg->message_chain_as_array_ref(); for my $m (@$list) { my $hs = $m->message_fields() || ''; if ($hs =~ /filename=.*\.(com|vbs|vbe|wsh|wse|js|exe|doc|rtf)/o) { $curproc->log("[new] attachment \.$1 found"); $curproc->stop_this_process(); } } }; Another solution is to trap Content-Disposition: attachment; to detect the existence of attachments. Before fml8 2004/12/08 current, it follows: $distribute_verify_request_start_hook = q{ my $msg = $curproc->incoming_message() || undef; for (my $m = $msg; $m ; $m = $m->{ next } ) { my $hs = $m->message_fields() || ''; if ($hs =~ /Content-Disposition:.*attachment;/o) { $curproc->log("attachment \.$1 found"); $curproc->stop_this_process(); } } }; After fml8 2004/12/08 current, it follows: $distribute_verify_request_start_hook = q{ my $msg = $curproc->incoming_message() || undef; my $list = $msg->message_chain_as_array_ref(); for my $m (@$list) { my $hs = $m->message_fields() || ''; if ($hs =~ /Content-Disposition:.*attachment;/o) { $curproc->log("[new] attachment \.$1 found"); $curproc->stop_this_process(); } } }; ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Chapter 21. Extend Message Case Study: Customize Message Create file at /var/spool/ml/elena/local/share/message/$language/class See /usr/local/share/fml/$version/message/$language/class as samples. Copy, cut and paste one of them :) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Chapter 22. Be ML Articles public via WWW Recipes 1. convert articles to html form after ML runs without html conversion. 2. convert articles to html form for resetting. 3. How to create html archive on a different machine? 1. convert articles to html form after ML runs without html conversion. use fmlhtmlify command. Example % fmlhtmlify /var/spool/ml/elena/spool ~fml/public/fml/mlarchive/DOMAIN/ML 2. convert articles to html form for resetting. use fmlhtmlify command. Example % fmlhtmlify /var/spool/ml/elena/spool ~fml/public/fml/mlarchive/DOMAIN/ML 3. How to create html archive on a different machine? 1. syncrhnize archive by e.g. rsync. 2. set up html converter such as mhonarch on the machine. 3. NFS but pay attension network structure in using NFS seen from Internet. IV. Operations This part describes operations. Table of Contents 23. Logging 24. Back Up Of Configurations ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Chapter 23. Logging See Log % makefml log ML_NAME % fml ML_NAME log shows the latest 30 lines of log. GUI uses log command. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Show Computer Oriented Log When not fml program or CGI calls fml8 CUI and such program wants to analyze the output, you can use use the following option. % makefml --log-computer-output COMMAND ML_NAME % fml --log-computer-output ML_NAME COMMAND It shows the computer oriented log into STDERR channel. For example % fml --log-computer-output elena@fml.org list rudo@nuinui.net 1070109341 info lock channel=recipient_map_modify 1070109342 info unlock channel=recipient_map_modify This example shows "TIME LOG_LEVEL MESSAGE" style log. It is suitable for computer proceessing. The command line option --log-computer-output is same effect as use_log_computer_output = yes in config.cf file. When "use_log_computer_output = yes" specified in config.cf, all programs are affected. All programs shows the computer oriented log to STDERR. So use of command line option is recommended. We should use perl module which holds a set of functions. In this case, the print out engine is the class called as FML::Log::Print::Simple. The output style is contolled by $log_computer_output_engine in config.cf file. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Recipes 1. show fml error log of yesterday. 2. See old logs. 3. Centralize log messages. 4. extract specific log messages in monitoring. 5. extrace the specific log messages with coping it. 6. Expire old log files. 1. show fml error log of yesterday. daily.pl of fml4 is not implemented yet. Currently use grep to parse the log file. 2. See old logs. fml8 appends log messages continuously into the log file at $ml_home_directory by default. All log messages exist in it. On the other hand, Unix log expires. So you cannot trace too lod messages. Please tune parameters of expiration tools e.g. newsyslog which program differs from unix variants to variants to save log messages in at least 3 months. 3. Centralize log messages. Unix uses syslog mechanism. To redirect all messages to /var/log/messages, set the following: [/etc/syslog.conf] *.* /var/log/messages Also, fml8 can use syslog mechanism. [/var/spool/ml/elena/config.cf] log_type = syslog To use these configuration, all messages are centralized to /var/log/messages file. 4. extract specific log messages in monitoring. % tail -F /var/spool/ml/elena/log | grep 'PATTERN' 5. extrace the specific log messages with coping it. % tail -F /var/spool/ml/elena/log | grep 'PATTERN' | tee FILE 6. Expire old log files. Newsyslog mechanism provided by fml4 is not implemented. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Chapter 24. Back Up Of Configurations To preserve fml8 configurations, back up the following two directories: /usr/local/etc/fml/ $ml_home_prefix (e.g. /var/spool/ml/, domain specific) Attention: These directories holds all articles, log files and others et.al. It is better to back up MTA configurations, too. For example, /etc/postfix in the case of Postfix. In summary, the following three (generally speaking 2 + number of domains fml8 operatates) are targets. /etc/postfix/ /usr/local/etc/fml/ $ml_home_prefix (e.g. /var/spool/ml/) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Back Up fml8 Configurations To back up fml8 configurations, it is enough to back up the following two directories. But it is too large since they contains articles, log files and all contents. /usr/local/etc/fml/ $ml_home_prefix (e.g. /var/spool/ml/, domain specific) The hard disk is cheap. So it is safe to preserve all contents as could as possible. If you preserve only configuratoins, it is enough to back up the following files. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Configuration Files To Back Up It is useful to make a list of targets based on the file naming convension. In the case of fml8, a file with .cf extension is a configuration file. The format of .cf file is key = value style. This style configuration files follow /usr/local/etc/fml/main.cf /usr/local/etc/fml/site_default_config.cf /EACH_ML_HOME_DIRECTORY/config.cf et.al. Configuration files with other syntax are /usr/local/etc/fml/mime_component_filter /usr/local/etc/fml/ml_home_prefix This type of files are space separeted. /usr/local/etc/fml/ contains only configuration files. So back up all under them. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Address List To Back Up Lists of mail addresses are /ML_HOME_DIRECTORY/members* /ML_HOME_DIRECTORY/recipients* Article delivery uses both recipients and members. For other roles, fml8 uses members-$role and recipients-$role. So, back up all members* and recipients* files. Remote administration by command mail (admin command mail) uses the following password files /ML_HOME_DIRECTORY/etc/passwd-$role . Back up /ML_HOME_DIRECTORY/etc/ too. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Back Up All Files Except For Some Large Directories. It is easy to back up all files except for the following large directories. They contains large data or temporary files. spool articles tmp temporary files var useful data If you use rsync, rsync --exclude is useful. V. Troubleshoot This part describes how to shoot troubles. Table of Contents 25. Troubleshoot ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Chapter 25. Troubleshoot 1. I want to know fml version. 2. Check Postfix version. 3. Check Sendmail version. 4. List up pre-defined addresses on this host. 5. List up defined aliases on this host 6. List up all ML addresses containing the specific member address. 1. I want to know fml version. [Example: in the case of "test" ML] % fmlconf test fml_version fml_version = fml-devel current-20021029 2. Check Postfix version. % postconf mail_version 3. Check Sendmail version. % echo '$v' | sendmail -bt 4. List up pre-defined addresses on this host. "fmladdr" command lists up users defined at both /etc/passwd and aliases. % fmladdr ┌─────────────────────────────────────────────────────────────────────────────┐ │ Warning │ ├─────────────────────────────────────────────────────────────────────────────┤ │The difference between "fmladdr" and "fmlalias" is whether it contains users │ │defined at /etc/passwd or not. "fmladdr" contains it but fmlalias not. │ │"fmlalias" lists up only users defined at aliases. │ └─────────────────────────────────────────────────────────────────────────────┘ 5. List up defined aliases on this host Run "fmlalias". It shows all addresses defined in aliases files. % fmlalias ┌─────────────────────────────────────────────────────────────────────────────┐ │ Warning │ ├─────────────────────────────────────────────────────────────────────────────┤ │The difference between "fmladdr" and "fmlalias" is whether it contains users │ │defined at /etc/passwd or not. "fmladdr" contains it but fmlalias not. │ │"fmlalias" lists up only users defined at aliases. │ └─────────────────────────────────────────────────────────────────────────────┘ 6. List up all ML addresses containing the specific member address. For each ML, run the following command: % fml ML list |grep ADDRESS ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ When The File System Error Ocuurs When the file system error occurs, fml8 exit abnormally to make MTA re-deliver the message again to fml8 or fml8 re-delivers it by itself without saving the article on the file system. So fml8 do not lost received messages whereas both log or summary file lack something. Describe below what happans when the file system error occurs in the delivery process. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ When Passed From MTA MTA To fml8 fml8 reads a message and writes it into the disk once. If succeeded, it processes more. If failed, fml8 exits abnormally as exit(EX_TEMPFAIL) for MTA to re-deliver it. See the Section called Incoming Queuing in Chapter 31 for more details. In this case, incoming message queue may have a incomplete message. fml8 tries to remove it in abnormal exit. Even if failed, the queue management system removes it later. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ If Updating Of The Article Sequence Number Failed In normal case, fml8 updates the article sequence number and re-reads it and compares it again. If the check fails, fml8 exit(EX_TEMPFAIL) for MTA to re-deliver it. ┌─────────────────────────────────────────────────────────────────────────────┐ │ Caution │ ├─────────────────────────────────────────────────────────────────────────────┤ │The article sequence number updated. After that, fml8 does not do exit │ │(EX_TEMPFAIL) to deliver the message on memory as could as possible. │ └─────────────────────────────────────────────────────────────────────────────┘ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ When Saving Of Article Failed ┌─────────────────────────────────────────────────────────────────────────────┐ │ Caution │ ├─────────────────────────────────────────────────────────────────────────────┤ │In this stage, the article sequence has been updated. │ └─────────────────────────────────────────────────────────────────────────────┘ In this case, fml8 does not create a new article file but the original message is already on the disk. The header of the article differs from the original one but the body content is same. So fml8 tries to link(2) the original mail in the incoming queue to the article file to save the content. [6] fml8 tries to deliver the message on memory. If the delivery process exits abnormally, distribution of article ends incompletely since fml8 can not use outgoing queue due to file system error. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Delivery Process fml8 saves the message into the outgoing queue, after succeeded, the delivery process runs. When fml8 fails to write the outgoing queue, fml8 exits incompletely. See the Section called fml Sends Back A Mail Message in Chapter 31 for more details. VI. fml8 Design This part describes the design policy of fml. Table of Contents 26. [LOG] Original Idea Of fml8 Project 27. Programming Style ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Chapter 26. [LOG] Original Idea Of fml8 Project The Original Idea Of fml8 (fml-devel) Project fml8 project called as fml-devel also is refactoring of fml4 mailing list driver. See http://www.fml.org/software/fml8/ for more details on the furure plan, design and implementation of fml-current. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Details Of Idea • simple implementation of configuration files and menu. • perl module (> perl 5.00504 ) • support more integrated CUI (makefml) and GUI. • Separation □ easy upgrade □ use CPAN modules as could as possible. □ 3rd party directory • abstracted IO layer □ file (implemented) □ /etc/group (implemented) □ NIS (implemented) □ SQL (MySQL implemetned) □ LDAP • IPv4/IPv6 ready (implemented) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Refactoring Table 26-1. refactoring TODO ┌─────────┬──────────────────────────────────────┬────────────────────────────┐ │ status │ entry │ detail │ ├─────────┼──────────────────────────────────────┼────────────────────────────┤ │done. │license │perl conformance │ ├─────────┼──────────────────────────────────────┼────────────────────────────┤ │ │ │fml4 to fml8 is similar to │ │underway.│image │sendmail to postfix. support│ │ │ │configuration converter. │ ├─────────┼──────────────────────────────────────┼────────────────────────────┤ │done. │wrapper (separation layer). │separation layer for upgrade│ │ │ │/downgrade, debug. │ ├─────────┼──────────────────────────────────────┼────────────────────────────┤ │ │ │use CPAN modules as could as│ │ │adapter │possible. prepare adapter │ │ │ │layer in using CPAM module. │ ├─────────┼──────────────────────────────────────┼────────────────────────────┤ │ │new single configuration file format. │ │ ├─────────┼──────────────────────────────────────┼────────────────────────────┤ │ │rule of variable naming convension │use_XXX, XXX_TYPet ... │ │ │ │prohibit NOT_USE style. │ ├─────────┼──────────────────────────────────────┼────────────────────────────┤ │ │function name convension use X11 style│use Perl Cookbook style ? │ │ │for main:: space. use method style for│e.g. "MemberP() -> IsMember │ │ │method. not use Lisp like style (-p). │()" │ ├─────────┼──────────────────────────────────────┼────────────────────────────┤ │done. │queue manager │re-delivery by itself │ ├─────────┼──────────────────────────────────────┼────────────────────────────┤ │ │tools │not use BSD make. │ └─────────┴──────────────────────────────────────┴────────────────────────────┘ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Architecture image [architectu] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ release engineering Not be an architect nor developer. Not too abstractive and not too object oriented. Be between them. Feedback in one month to manage project and code review. Table 26-2. release interval ┌────────────────────┬────────────────────────────────────────────────────────┐ │ days in one month │ content │ ├────────────────────┼────────────────────────────────────────────────────────┤ │the first 4 - 5 days│manage project. apply at least 20 % of the project to │ │ │this stage. │ ├────────────────────┼────────────────────────────────────────────────────────┤ │2 - 3 weeks │coding. │ ├────────────────────┼────────────────────────────────────────────────────────┤ │the last week │code review, document review │ ├────────────────────┼────────────────────────────────────────────────────────┤ │at the last of the │release a snapshot. alpha-0, alpha-1, alpha-2, ... │ │month │ │ └────────────────────┴────────────────────────────────────────────────────────┘ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Chapter 27. Programming Style This chapter describes a few topics on programming technique. See FNF on FML.ORG programming style. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Variable Naming Convension It is ambiguous where "default" word in the variable name is proper. The left side of the naming string is expected to show large scale such as CLASS. Let us consider article related variables. We expect $article_* variables for them. It seems better to use CLASS_default_XXX syntax not default_XXX. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Structure Of Variable Naming It seems proper to use systematic naming convension. For it, we define base class or inheritence of naming syntax. Consider class names. For example, "mail" implies messsage/rfc822 format text. The input into fml system is a mail, outgoing one is a mail. The variable are sub class of "mail" object, so the name is unified as PREFIX_mail_ATTRIBUTE style. mail_XXX mail_default_XXX use_incoming_mail_XXX incoming_mail_XXX use_outgoing_mail_XXX outgoing_mail_XXX use_report_mail_XXX report_mail_XXX Other example (header): header_XXX header_default_XXX article_header_XXX use_article_header_XXX command_mail_header_XXX use_command_mail_header_XXX We can describe structure of class as follows: command { SOMETHING_command admin_command } directory { XXX_directory } file { template_file } mail { incoming_mail outgoing_mail report_mail } message { reply_message } article { article_digest (not use digest to show digest of article) article_spool (not use spool to show spool of article) } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Example: Standard Pattern (e.g. log.cf lock.cf) use_VARIABLE = yes or no # append _dir for directory. VARIABLE_dir = STRING # append _file for file. VARIABLE_file = STRING VARIABLE_type = STRING VARIABLE_format = STRING VARIABLE_format_type = STRING VARIABLE_limit = STRING (NUMBER but STRING) VARIABLE_upper_limit = STRING (NUMBER but STRING) VARIABLE_lower_limit = STRING (NUMBER but STRING) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Example 2: (e.g. acl.cf) VARIABLE_restrictions = reject_ATTRIBUTE1 check_ATTRIBUTE2 permit_XXX ATTRIBUTE1 = PATTERN1 PATTERN2 ... ATTRIBUTE2 = var1 var2 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Example 3: (program name prefix) PROGRAM_VARIABLE_ATTRIBUTE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ A Few Topics On Design And Coding Style ┌─────────────────────────────────────────────────────────────────────────────┐ │ Warning │ ├─────────────────────────────────────────────────────────────────────────────┤ │See also FNF on style. │ └─────────────────────────────────────────────────────────────────────────────┘ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ A Few Cautions Apply quotemeta() for search key. Use access method for object not handle directly within objects. Example: To access to main.cf object, not use $curproc->{ ... }->{ main_cf } instead use $curproc->main_cf(); style. It is better not to use @EXPORT and @EXPORT_OK. How depth of classes is allowed ? two such as String::is_japanese_string() ? At least 3, I think. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Programming Style Original Idea ┌─────────────────────────────────────────────────────────────────────────────┐ │ Warning │ ├─────────────────────────────────────────────────────────────────────────────┤ │Here is the original idea log. │ └─────────────────────────────────────────────────────────────────────────────┘ • We can use polymorphism in perl. Use it and object composition instaed of multiple inheritence. • Perl 5's OOP is not OOP. Do not depent on it. It just provides simple use of variable since variable itself knows the home (object / package). • Interface for re-use and abstraction should be OOP style. • We want to use OOP style in using Perl 5 but take care for OOP-ism. Balance is important. • not use deep inheritence. Programs in libexec/ describes the basic flow of processes. They may be allowd to be structured not object oriented programming Polymorphism and re-use is important especially in sub-classes. VII. fml8 Internals This part describles the fml internals for developers. Table of Contents 28. fml8 Boot Loader To Resolve Version Dependence Dynamically 29. Configuration File: config.cf 30. Create A New Program 31. fml8 Mail Delivery System 32. Digest Delivery 33. Language Preference In Processing 34. Manipulate Message (Mail Message) 35. Filter 36. Subscribe / Unsubscribe 37. Command (Command Mail, CUI And GUI) 38. Internal Of CGI Process 39. Directory 40. Restrict Input Data 41. User Authentication 42. Hook 43. Virtual Domain 44. Errormail Analyzer (libexec/error) 45. IO Interface And Operations 46. Lock 47. Database Related Modules 48. Database Management System 49. Convert Another ML System To fml8 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Chapter 28. fml8 Boot Loader To Resolve Version Dependence Dynamically fml8 provides a boot loader to resolve version dependence dynamically. For example, the loader boot straps fml8 as follows: fml (libexec/distribute) boots like this ... functions class ---------------------------------------- main::Bootstrap() libexec/loader | V main::Bootstrap2() FML::Process::Switch | V ProcessSwitch() FML::Process::Switch | | | switch to ($obj = FML::Process:Distribute) | V ProcessStart($obj,$args) FML::Process::Flow ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Case: Distribution fml8 loader boot straps like this in the case of distribution. /usr/local/libexec/fml/distributre (is same as /usr/local/libexec/fml/loader in fact) reads /usr/local/etc/fml/main.cf and resolvers the version it should use from $fml_version variable. Let $fml_version current-20010501. The loader uses library perl modules under /usr/local/lib/fml/current-20010501/. The loader resets @INC (perl include path). It loads FML::Process::Switch and checks $0 (program name in process table). The loader resolves from the name that the role is distribution. It loads FML::Process::Distribute and switches to the class. The relation between program name and class (perl module) is defined at /usr/ local/etc/fml/defaults/$fml_version/modules file. FML::Process::Flow::ProcessStart() function drives these sequential steps. ProcessStart() takes FML::Process::Distribute object as an argument and drives the object. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ FML::Process:: Class Structure FML::Process::Distribute >-| FML::Process::Command >-|-- FML::Process::Kernel FML::Process::Mead >-| | |-use-a FML::Parse |-use-a FML::Config |-use-a FML::Log |-use-a ... SOMETHING ... ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Modules In Process Execution • libexec/loader (wrapper): executes Bootstrap() runction. libexec/distribute et.al. is a symlink(2) to this loader. See under /usr/local/libexec/fml/ path. • □ reads /usr/local/etc/fml/main.cf and resolves $fml_version. reset @INC by main.cf value. Since default_config.cf is version dependent, the loader should evaluate the file before it reads ML specific configuration files. □ Evaluate @ARGV and resolves which ML specific configuration files we need to load. □ load FML::Process::Switch class which is also version dependent. ☆ The loader executes Bootstrap2() and ProcessSwitch() to switch the context to each one such as distribution, command mail et.al. In this time, the loader knows the role from $0 process name. ☆ Exapmle of Polymorphyism: dynamic binding of module and creation of process object in starting the process. FML::Process::Flow describes the flow of process like this: $process = new FML::Process::SOMETHING; $process->prepare($args); $process->verify_request($args); $process->run($args); $process->finish($args); Each process should probide proper methods under FML::Process:: class. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Discussion: Where Function Should Resolve $ml_name And $ml_domain. Currently fml8 resolves them in prepare() under FML::Process:: classes. Here is a part of background idea. main::Bootstrap() resoles $fml_version based on main.cf information. pass hints to some processes e.g. CGI. CGI only it should ignore invalid input. $ml_name $and ml_domain is hard-coded in cgi scripts. main::Bootstrap2() ProcessSwitch() resolves the module, configuration files, library path and @INC. pass hints to some processes e.g. CGI. CGI only ProcessStart($obj, $args) main process starts new prepare resoles $ml_name and $ml_domain. parse input from CGI using hints. determine ml specific configuration files. parse incoming message. parse command line arguments. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Chapter 29. Configuration File: config.cf ML Specific Configuration File: config.cf You can customize each ML differently. fml4 and fml8 are same in this point. In the case of fml4, there is a config.ph in ML home directory, $DIR (e.g. /var /spool/ml). This "config.ph" file is a perl script. There is one configuration file (config.cf) in fml8, too. But the format is different. The format is like this: variable = value . It is similar to postfix or .ini files. It is similar to a perl module. You can write perl codes after =cut line. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Problems in fml4 The configuration file of fml4, config.ph, is a perl script. Perl script is good for human editing but it is not suitable for configuration tools. It implies it is difficult to prepare configuration tools for config.ph. So, in fml4 two files, cf and config.ph are used. [7] The use of cf is suitable for configuration tools but introduces another difficulty such as inconsistency between cf and config.ph since human may edit config.ph but forgets editing cf. So, fml8 introduces only one configuration file. It is a new format which is similar to Postfix main.cf. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ config.cf Format The format of "config.cf" is "variable = value syntax". If plural values are required, space or "\n\s" is a separator. variable = value valiable = value1 value2 value3 variable = value1 value2 value3 The syntax of files with the suffix .cf e.g. /etc/fml/main.cf , default_config.cf, is same. $variable at the right hand is expanded. For example, a = value1 b = $a/value2 is expanded to a = value1 b = value1/value2 . The variable expansion is done at the last. So, the following definitions a = value1 b = $a/value2/$c c = value3 a = value4 are expaned to b = valu4/value2/value3 since the last $a overwrites the previous one. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Extension To Postfix Style variable += value variable -= value is used for adding or removing the specific value. x = a b c d x -= b becoms x = a c d . Another case, x = a b c d x += e becomes x = a b c d e . ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Overload Variables In config.cf Overloading of .cf files is possible. It overwrites variables. It enables separation of configuration files e.g. the default file, the host specific file, the domain specific file, and ML specific file. fml8 reads these files sequentially. At the last, fml8 expands variables when variable reading is requested. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Modifying/Adding Variables After All Configuration Files Have Been Loaded. The variable expansion is always done. If some value with $ is added to some variable, the next reading operation [8] causes variable expansion. For example, set $config->{ key } = '$ml_home_dir/value'; here. The next read operation e.g. $config->{ another_key } (where the key is any) evaluates the variable expansion. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Internal Of Variable Expansion %_fml_config hash holds pairs of key and value. The format is $dir/$file in this hash, it is not expanded. get() returns the value of %_fml_config_result. The value in this hash is after the variable expansion. The variable is expanded in calling get() method. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Variable List (Alphabetical Order) Table 29-1. table description ┌─────────────────────────────────────────────────┬───────────────────────┬─────────────────────────────────────┐ │ variable name │ descrition │ default value(s) │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │domain matching level │ │ │address_compare_function_domain_matching_level │in comparing mail │3 │ │ │addresses │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │case insensitive │ │ │address_compare_function_type │comparison of user part│user_part_case_insensitive │ │ │of mail address. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │base directory which │ │ │admin_cgi_base_dir │locates .cgi for this │$cgi_base_dir/admin │ │ │domain. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │gpg configurations for │ │ │admin_command_mail_auth_gpg_config_dir │admin commnad mail │$etc_dir/gpg-admin-command-mail-auth │ │ │authentication. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │admin_command_mail_auth_gpg_config_dir_alias │conventional naming │$etc_dir/gpg-admin │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │pgp configurations for │ │ │admin_command_mail_auth_pgp_config_dir │admin commnad mail │$etc_dir/pgp-admin-command-mail-auth │ │ │authentication. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │admin_command_mail_auth_pgp_config_dir_alias │conventional naming │$etc_dir/pgp-admin │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │admin_command_mail_restrictions │restrictions for admin │reject_system_special_accounts │ │ │command mail │check_admin_member_password reject │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │admin_member_maps │all remote │$primary_admin_member_map │ │ │administrator lists │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │admin_member_password_maps │all password files. │$primary_admin_member_password_map │ │ │ │file:$etc_dir/passwd │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │admin_recipient_maps │dummy │$primary_admin_recipient_map │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │anonymous_cgi_base_dir │top level directory for│$fml_owner_home_dir/public_html/ │ │ │anonymous cgi scripts. │cgi-bin/anonymous │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │expire limit of │ │ │anonymous_cgi_expire_limit │anonymous CGI session │15m │ │ │ID. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │article_delivery_transport │specify transport for │smtp │ │ │article delivery. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │article_expire_limit │how old article to be │90d │ │ │removed │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │article_filter_reject_notice_data_type │how fml refer the │string │ │ │rejeced message. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │article_filter_reject_notice_recipients │recipients to inform │maintainer sender │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │article_header_filter_rules │header filter rules. │check_message_id check_date permit │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │article_header_list_help │list-help of article │$mail_header_default_list_help │ │ │header. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │article_header_list_id │list-id of article │$mail_header_default_list_id │ │ │header. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │article_header_list_owner │list-owner of article │$mail_header_default_list_owner │ │ │header. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │article_header_list_post │list-post of article │$mail_header_default_list_post │ │ │header. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │article_header_list_software │default list-software │$mail_header_default_list_software │ │ │header field. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │article_header_list_subscribe │list-subscribe of │$mail_header_default_list_subscribe │ │ │article header. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │article_header_list_unsubscribe │list-unsubscribe of │$mail_header_default_list_unsubscribe│ │ │article header. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │ │delete_unsafe_header_fields │ │ │ │rewrite_article_subject_tag │ │ │ │rewrite_reply_to rewrite_errors_to │ │ │ │rewrite_stardate rewrite_precedence │ │article_header_rewrite_rules │header rewriting rules │rewrite_message_id add_software_info │ │ │ │add_fml_ml_name │ │ │ │add_fml_traditional_article_id │ │ │ │add_fml_article_id add_x_sequence │ │ │ │add_rfc2369 │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │article_message_id_cache_dir │article Message-ID │$db_dir/article_message_id │ │ │cache directory │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │article_mime_component_filter_rules │file of filter rules │$fml_config_dir/mime_component_filter│ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │article_non_mime_filter_rules │dummy │permit │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │permit post from anyone│ │ │article_post_article_thread_lifetime │if the posted message │86400 │ │ │follows │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │article_post_auth_gpg_config_dir │gpg configurations for │$etc_dir/gpg-article-post-auth │ │ │article authentication.│ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │article_post_auth_pgp_config_dir │pgp configurations for │$etc_dir/pgp-article-post-auth │ │ │article authentication.│ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │article_post_encrypt_gpg_config_dir │gpg configurations for │$etc_dir/gpg-article-post-encrypt │ │ │article encryption. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │article_post_encrypt_pgp_config_dir │pgp configurations for │$etc_dir/pgp-article-post-encrypt │ │ │article encryption. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │article_post_restrictions │restrictions for post │isolate_system_special_accounts │ │ │ │permit_member_maps isolate │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │article_post_restrictions_reject_notice_data_type│how to inform the │string │ │ │rejected message │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │article_sequence_file │file to store sequence │$sequence_file │ │ │number │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │article_size_filter_rules │size based filter │check_header_size check_body_size │ │ │rules. │permit │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │article_spam_filter_bogofilter_options │"-e" implies embedded │-e │ │ │mode. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │article_spam_filter_drivers │external spam checker. │bogofilter │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │article_spam_filter_functions │list up driver names │bogofilter │ │ │used as spam checker. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │article_spam_filter_rules │action if the message │header_rewrite │ │ │looks a spam. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │exit non-zero status │ │ │article_spam_filter_spamassassin_options │code when spam caught │-e │ │ │if "-e" specified. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │article_spam_filter_spamc_options │spamc optoins. "-c" │-c │ │ │means check only. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │article_subject_tag │Subject: tag. │[$ml_name:%05d] │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │article_summary_file │article summary file. │$ml_home_dir/summary │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │save the first N bytes │ │ │article_summary_file_format_address_length │of the address in │15 │ │ │summary. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │article_summary_file_format_style │format style. │fml4_compatible │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │ │reject_not_iso2022jp_japanese_string │ │ │ │reject_null_mail_body │ │ │filter rules of text/ │reject_one_line_message │ │article_text_plain_filter_rules │plain filter. │reject_old_fml_command_syntax │ │ │ │reject_invalid_fml_command_syntax │ │ │ │reject_japanese_command_syntax │ │ │ │reject_ms_guid permit │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │article_thread_outline_greeting_en │greeting prepended to │[outline of this thread] │ │ │thread outline │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │article_thread_outline_greeting_ja │ ɤγ Ϥޤ │[ ɤΤ 餹 ] │ │ │ˤĤ 밧 │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │article_thread_outline_rules │where should we add │add_outline_to_header │ │ │thread outline ? │append_outline_to_body │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │article_virus_filter_clamav_options │--mbox needed for mail │--quiet --mbox │ │ │files. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │article_virus_filter_drivers │external virus checker.│clamscan │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │article_virus_filter_functions │list up driver names │clamav │ │ │used as virus checker. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │article_virus_filter_rules │action if virus found. │reject │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │base directory which │$fml_owner_home_dir/public_html/ │ │cgi_base_dir │locates .cgi for this │cgi-bin/fml/$ml_domain │ │ │domain. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │cgi_charset_en │cgi charset in English │us-ascii │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │cgi_charset_ja │cgi charset in Japanese│euc-jp │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │cgi_default_charset │default charset │us-ascii │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │cgi_default_language │language mode of CGI (!│english │ │ │= charset) │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │cgi_language_select_list │available language mode│english japanese │ │ │in CGI │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │cgi_main_menu_color │default bgcolor │#FFFFFF │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │choise of address list │ │ │cgi_menu_address_map_select_list │types in CGI │member recipient admin_member │ │ │operations. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │default value of list │ │ │cgi_menu_default_address_map │types in CGI │recipient │ │ │operations. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │cgi_navigation_bar_color │default bgcolor in │#FFFFFF │ │ │navigation menu │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │chaddr_command_auth_type │use comnfirmation in │confirmation │ │ │chaddr command ? │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │operate action │ │ │chaddr_command_operation_mode │automatically or │automatic │ │ │manually by maintainer │ │ │ │? │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │gpg configurations for │ │ │command_mail_auth_gpg_config_dir │(user) commnad mail │$etc_dir/gpg-command-mail-auth │ │ │authentication. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │pgp configurations for │ │ │command_mail_auth_pgp_config_dir │(user) commnad mail │$etc_dir/pgp-command-mail-auth │ │ │authentication. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │command_mail_filter_reject_notice_data_type │how fml refer the │string │ │ │rejeced message. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │command_mail_filter_reject_notice_recipients │recipients to inform │maintainer sender │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │the numfer of │ │ │command_mail_invalid_command_limit │ineffective commands in│100 │ │ │one command mail. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │command_mail_line_length_limit │maximum length of one │128 │ │ │command line. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │command_mail_reply_prompt │command prompt in │>>> │ │ │message reply │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │restrictions for │isolate_system_special_accounts │ │command_mail_restrictions │command mail │permit_anonymous_command │ │ │ │permit_user_command isolate │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │size based filter │check_header_size check_body_size │ │command_mail_size_filter_rules │rules. │check_command_limit │ │ │ │check_line_length_limit permit │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │the numfer of effective│ │ │command_mail_valid_command_limit │commands in one command│100 │ │ │mail. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │confirm_command_expire_limit │how long confirmation │14d │ │ │is effective ? │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │confirm_command_prefix │special command name │confirm │ │ │used as confirmation │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │restrict "who can │ │ │createonpost_newml_maps │create a new ML". PCRE │pcre:$ml_home_dir/newml.allow.pcre │ │ │is available. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │ │reject_system_special_accounts │ │ │ │reject_errormail │ │createonpost_newml_restrictions │Who can create a new │reject_fml8_managed_address │ │ │CREATE-ON-POST ML ? │reject_createonpost_domain │ │ │ │permit_createonpost_maintainer_maps │ │ │ │permit_ml_domain │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │restrict "who can │ │ │createonpost_sender_maps │post". PCRE is │pcre:$ml_home_dir/sender.allow.pcre │ │ │available. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │ │reject_system_special_accounts │ │ │ │reject_errormail │ │createonpost_sender_restrictions │who can post for │reject_list_header_field │ │ │CREATE-ON-POST ML ? │reject_fml8_managed_address │ │ │ │reject_createonpost_domain │ │ │ │permit_anyone │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │restrict "who can │pcre:$ml_home_dir/ │ │createonpost_subscribe_maps │subscribe". PCRE is │subscribe.allow.pcre │ │ │available. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │ │reject_system_special_accounts │ │ │ │reject_errormail │ │createonpost_subscribe_restrictions │who can subscribe ? │reject_fml8_managed_address │ │ │ │reject_createonpost_domain │ │ │ │permit_anyone │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │db_dir │directoy to hold │$var_dir/db │ │ │several data files │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │default_mail_body_size_limit │body size limit │10240000 │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │default_mail_header_size_limit │header size limit │102400 │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │deny_file │deny file │$ml_home_dir/deny │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │digest_header_rewrite_rules │digest article header │add_software_info add_rfc2369 │ │ │rewrite rules │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │digest_member_maps │dummy │$primary_member_maps │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │digest_recipient_maps │all maps of digest │$primary_digest_recipient_map │ │ │recipients. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │digest_sequence_file │file to store the last │$ml_home_dir/seq-digest │ │ │sequence to deliver │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │directory_default_mode │default mode in │0755 │ │ │creating directory. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │domain_config_base_dir │system data directory │$ml_home_prefix/etc │ │ │provided by fml │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │domain_exim_config_dir │directory to hold exim │$domain_config_base_dir/exim │ │ │specific config files. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │domain_local_dir │domian local directory.│$ml_home_prefix │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │domain_local_log_file │domin local log file. │$domain_local_dir/@log@ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │domain_local_tmp_dir │domian local temporary │$ml_home_prefix/@tmp@ │ │ │directory. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │domain_mail_config_dir │directory to hold │$domain_config_base_dir/mail │ │ │config files for MTA │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │directory to hold │ │ │domain_postfix_config_dir │postfix specific config│$domain_config_base_dir/postfix │ │ │files. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │directory to hold │ │ │domain_procmail_config_dir │procmail specific │$domain_config_base_dir/procmail │ │ │config files. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │domain_qmail_config_dir │directory to hold qmail│$domain_config_base_dir/qmail │ │ │specific config files. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │directory to hold │ │ │domain_sendmail_config_dir │sendmail specific │$domain_config_base_dir/sendmail │ │ │config files. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │error_mail_analyzer_cache_dir │directory to cache │$db_dir/error │ │ │error messages. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │error_mail_analyzer_cache_mode │mode of cache │temporal │ │ │expiration │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │error_mail_analyzer_cache_size │cache size. │14 │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │error_mail_analyzer_cache_type │module as cache engine │File::CacheDir │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │function in │ │ │error_mail_analyzer_function │FML::Error::Analyze to │histgram │ │ │analyze. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │error_mail_analyzer_function_select_list │functions defined in │simple_count histgram │ │ │FML::Error::Analyze │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │error limit in using │ │ │error_mail_analyzer_simple_count_limit │simple_count as anlyzer│5 │ │ │function. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │etc_dir │etc directory │$ml_home_dir/etc │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │event_queue_dir │event queue directory │$var_dir/event/queue │ │ │for scheduler │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │password to fetch │ │ │fetchfml_article_post_password │article messages for │******** │ │ │$ml_name ML │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │username to fetch │ │ │fetchfml_article_post_user │article messages for │$ml_name │ │ │$ml_name ML │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │password to fetch │ │ │fetchfml_command_mail_password │command messages for │******** │ │ │$ml_name ML │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │username to fetch │ │ │fetchfml_command_mail_user │command messages for │$ml_name-ctl │ │ │$ml_name ML │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │password to fetch error│ │ │fetchfml_error_mail_analyzer_password │messages for $ml_name │******** │ │ │ML │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │username to fetch error│ │ │fetchfml_error_mail_analyzer_user │messages for $ml_name │$ml_name-admin │ │ │ML │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │fetchfml_fetch_protocol │protocol to fetch │pop3 │ │ │messages. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │fetchfml_imap_servers │imap servers fetchfml │localhost │ │ │process uses. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │fetchfml_pop_servers │pop servers fetchfml │localhost │ │ │process uses. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │queue_dir fetchfml uses│ │ │fetchfml_queue_dir │as temporary incoming │$var_dir/mail/queue-fetchfml │ │ │queue │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │file_default_mode │default mode in │0600 │ │ │creating file │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │maximu number of │ │ │get_command_request_limit │request in get command │100 │ │ │(s) in one mail. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │guide_file │guide file │$ml_home_dir/guide │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │help_file │help file │$ml_home_dir/help │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │html_archive_dir │html archive directory │$fml_owner_home_dir/public_html/fml/ │ │ │of the specific ML. │mlarchive/$ml_domain/$ml_name │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │html_tmp_base_url │temporary url base for │/~$fml_owner/fml/tmp │ │ │CGI │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │html_tmp_dir │temporary directory for│$fml_owner_home_dir/public_html/fml/ │ │ │CGI │tmp │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │maximum size limit of │ │ │incoming_article_body_size_limit │article body passed │$default_mail_body_size_limit │ │ │from MTA. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │maximum size limit of │ │ │incoming_article_header_size_limit │article header passed │$default_mail_header_size_limit │ │ │from MTA. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │maximum size limit of │ │ │incoming_command_mail_body_size_limit │article body passed │$default_mail_body_size_limit │ │ │from MTA. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │maximum size limit of │ │ │incoming_command_mail_header_size_limit │article header passed │$default_mail_header_size_limit │ │ │from MTA. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │incoming_mail_body_checksum_cache_dir │Message-ID cache │$db_dir/body_checksum │ │ │directory │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │incoming_mail_body_loop_check_rules │body loop check rules │check_body_checksum │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │incoming_mail_cache_dir │incoming mail queue │$var_dir/mail/incoming │ │ │directory │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │incoming_mail_cache_size │the maximum number of │128 │ │ │cached incoming mails │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │incoming_mail_envelope_loop_check_rules │envelope based loop │check_envelope_sender │ │ │check rules │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │incoming_mail_header_loop_check_rules │loop check rules │check_message_id check_x_ml_info │ │ │ │check_list_post │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │isolated_queue_dir │top level directory to │$var_dir/mail/queue-isolated │ │ │hold isolated messages │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │isolated_queue_expire_limit │expire messages in the │14d │ │ │queue after this limit.│ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ldap_base_dn │base DN to contact in │dc=$ml_name, dc=fml, dc=org │ │ │modify, search et.al. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ldap_bind_dn │DN to bind. │dc=fml, dc=org │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ldap_query_add_as_ldif │attributes to add into │fmlrecipient:&address fmlmember:& │ │ │$ldap_base_dn entry. │address │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │attributes to remove │fmlrecipient:&address fmlmember:& │ │ldap_query_delete_as_ldif │from $ldap_base_dn │address │ │ │entry. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ldap_user │dummy │fml │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │list_addresses │addresses fml uses: │$maintainer $article_post_address │ │ │e.g. elena, elena-ctl │$command_mail_address │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │list_command_default_maps │default map to show by │$recipient_maps │ │ │list command. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │listinfo_base_dir │base directory for ML │$fml_owner_home_dir/public_html/fml/ │ │ │information │listinfo │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │listinfo_dir │directory for ML │$listinfo_base_dir/$ml_domain/ │ │ │information │$ml_name │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │listinfo_template_base_dir │listinfo template │$fml_share_dir/listinfo │ │ │template dir │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │listinfo_template_dir │listinfo template │$fml_share_dir/listinfo/ │ │ │ │$template_file_charset │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │lock_dir │directory where lock │$var_dir/lock │ │ │files are created. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │lock_file │giant lock file name │$lock_dir/giantlock │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │lock_type │lock algorithm type │flock │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │show the last N lines │ │ │log_command_tail_starting_location │of log file where N == │100 │ │ │100. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │log_computer_output_engine │specify perl module for│FML::Log::Print::Simple │ │ │output engine. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │log_dir │log dir │$var_dir/log │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │log_file │log file. │$ml_home_dir/log │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │log_format_type │log message format │process[pid] │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │number of archive files│ │ │log_rotate_archive_file_total │to be kept besides the │7 │ │ │log │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │The interval field │ │ │log_rotate_interval │specifies the time │86400 │ │ │separation │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │log_rotate_policy │log rotation policy. │size │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │log_rotate_size_limit │rotate log if the size │300000 │ │ │is over this size. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │log_syslog_facility │see syslog(3) │mail │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │log_syslog_ident │string prepended to │fml/$program_name │ │ │every message. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │log_syslog_options │see syslog(3) │pid │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │log_syslog_priority │see syslog(3) │info │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │log_type │logging type │file │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │mail_aliases_file │aliases │$domain_mail_config_dir/aliases │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │mail_header_default_errors_to │default Errors-To: │$maintainer │ │ │field. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │mail_header_default_list_help │default list-help │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │mail_header_default_list_id │default list-id header │$ml_name ML <$ml_name.$ml_domain> │ │ │field. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │mail_header_default_list_owner │default list-owner │ │ │ │header field. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │mail_header_default_list_post │default list-post │ │ │ │header field. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │mail_header_default_list_software │default list-software │$fml_version │ │ │header field. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │mail_header_default_list_subscribe │default list-subscribe │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │default │ │ │ │field. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │mail_header_default_precedence │default Precedence: │bulk │ │ │field. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │mail_header_default_x_ml_name │default X-ML-Name: │$ml_name │ │ │field. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │mail_queue_dir │mail queue directory │$var_dir/mail/queue │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │member_maps │all maps used to check │$primary_member_map │ │ │member list. │$admin_member_maps │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │member_total_limit │upper limit of posters.│3000 │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │message_id_cache_dir │Message-ID cache │$db_dir/message_id │ │ │directory │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │message_template_dir │directory to hold │$fml_share_dir/message │ │ │message template files │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │base directory which │ │ │ml_admin_cgi_base_dir │locates .cgi for this │$cgi_base_dir/ml-admin/$ml_name │ │ │ML. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ml_anonymous_cgi_allowed_commands │ │subscribe unsubscribe │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │ml specific directory │$anonymous_cgi_base_dir/$ml_domain/ │ │ml_anonymous_cgi_base_dir │for anonymous cgi │$ml_name │ │ │scripts. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │ml specific url base │/~$fml_owner/cgi-bin/anonymous/ │ │ml_anonymous_cgi_base_url │for anonymous cgi │$ml_domain/$ml_name │ │ │scripts. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ml_local_dir │ML local directory │$ml_home_dir/local │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ml_local_lib_dir │ML local library path │$ml_local_dir/lib │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │directory to hold ml │ │ │ml_local_message_template_dir │specific message │$ml_local_share_dir/message │ │ │template files │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ml_local_share_dir │ML local share/ │$ml_local_dir/share │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │queue_dir moderate uses│ │ │moderate_queue_dir │as temporary incoming │$var_dir/mail/queue-moderate │ │ │queue │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │expire submitted queue │ │ │moderate_queue_expire_limit │after │14d │ │ │$moderate_expire_limit.│ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │moderator_member_maps │all list of moderator │$primary_moderator_member_map │ │ │lists. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │moderator_recipient_maps │dummy │$primary_moderator_recipient_map │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │newml_command_ml_admin_default_address │fml_owner value used by│$fml_owner │ │ │newml command. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │newml_command_postfix_template_files │templates of include │include include-ctl include-error │ │ │files │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │templates files of ~fml│dot-qmail dot-qmail-ctl │ │newml_command_qmail_template_files │/.qmail-* │dot-qmail-admin dot-qmail-request │ │ │ │dot-qmail-default │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │newml_command_template_files │template files used in │config.cf │ │ │running "makefml newml"│ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │objective_file │objective file │$ml_home_dir/objective │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │outgoing_article_body_size_limit │maximum size limit of │$default_mail_body_size_limit │ │ │deliverd article body. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │maximum size limit of │ │ │outgoing_article_header_size_limit │deliverd article │$default_mail_header_size_limit │ │ │header. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │outgoing_command_mail_body_size_limit │maximum size limit of │$default_mail_body_size_limit │ │ │deliverd article body. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │maximum size limit of │ │ │outgoing_command_mail_header_size_limit │deliverd article │$default_mail_header_size_limit │ │ │header. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │outgoing_mail_cache_dir │outgoing mail cache │$var_dir/mail/outgoing │ │ │directory │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │outgoing_mail_cache_size │the maximum number of │128 │ │ │cached outgoing mails │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │outgoing_mail_header_errors_to │Errors-To: field │${mail_header_default_errors_to} │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │outgoing_mail_header_precedence │Precedence: field │${mail_header_default_precedence} │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │ml name in both │ │ │outgoing_mail_header_x_ml_name │X-ML-Name: and │${mail_header_default_x_ml_name} │ │ │X-Sequence header │ │ │ │fields. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │postfix_verp_delimiters │verps delimieters used │+= │ │ │in postfix │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │postfix_virtual_map_file │virtual map file │$domain_postfix_config_dir/virtual │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │list of remote │ │ │primary_admin_member_map │administrators who has │file:$ml_home_dir/members-admin │ │ │priviledge │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │primary password file │ │ │primary_admin_member_password_map │to authenticate remote │file:$etc_dir/passwd-admin │ │ │administrator │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │primary_admin_recipient_map │dummy │file:$ml_home_dir/recipients-admin │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │primary_digest_member_map │dummy │$primary_member_map │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │primary_digest_recipient_map │primary list of digest │file:$ml_home_dir/recipients-digest │ │ │recipients. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │member list == primary │ │ │primary_member_map │address list who can │file:$ml_home_dir/members │ │ │post. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │primary_moderator_member_map │primary list of │file:$ml_home_dir/members-moderator │ │ │moderators. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │primary_moderator_recipient_map │dummy │file:$ml_home_dir/ │ │ │ │recipients-moderator │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │primary_recipient_map │primary recipients │file:$ml_home_dir/recipients │ │ │list. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │primary_user_db_gecos_map │primary { address => │$user_db_dir/gecos │ │ │gecos_field } map. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │primary { address => │ │ │primary_user_db_subscribe_date_map │unix time when │$user_db_dir/subscribe_date │ │ │subscribed } map. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │special command name │ │ │privileged_command_prefix │used as admin command │admin │ │ │mail │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │procmail_aliases_file │sample of ~fml │$domain_procmail_config_dir/ │ │ │/.procmailrc │procmailrc │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │qmail_verp_delimiters │verps delimieters used │-= │ │ │in qmail │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │qmail_virtual_map_file │template of /var/qmail/│$domain_qmail_config_dir/ │ │ │control/virtualdomains │virtualdomains │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │virtual domain │ │ │qmail_virtualdomains_file │configurations for │/var/qmail/control/virtualdomains │ │ │qmail │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │recipient_maps │all maps used as │$primary_recipient_map │ │ │recipient list. │file:$ml_home_dir/actives │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │recipient_total_limit │upper limit of │3000 │ │ │recipients. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │sendmail_virtual_map_file │sample of /etc/mail/ │$domain_sendmail_config_dir/ │ │ │virtusertable │virtusertable │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │sequence_file │file to store article │$ml_home_dir/seq │ │ │sequence. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │shared_db_dir │database directory │$ml_home_prefix/@db@ │ │ │shared among ML's │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │smtp_recipient_limit │recipient limits over │1000 │ │ │one smtp transaction. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │smtp_sender │MAIL FROM: │$maintainer │ │ │<$smtp_sender> in SMTP │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │smtp_servers │smtp servers. │[::1]:25 127.0.0.1:25 │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │spammer_maps │list of spammers or │$primary_spammer_map │ │ │addresses to reject. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │spool_dir │spool directory │$ml_home_dir/spool │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │spool_type │use subdir in spool │plane │ │ │directory ? │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │subscribe_command_auth_type │use comnfirmation in │confirmation │ │ │subscribe command ? │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │operate action │ │ │subscribe_command_operation_mode │automatically or │automatic │ │ │manually by maintainer │ │ │ │? │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │system_has_alarm │has alarm(2) ? │yes │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │system_has_fork │has fork(2) ? │yes │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │system_has_getpwgid │has getpwgid(2) ? │yes │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │system_has_getpwuid │has getpwuid(2) ? │yes │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │system_has_select │has select(2) ? │yes │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │ │root postmaster MAILER-DAEMON msgs │ │system_special_accounts │list of system │nobody news majordomo listserv │ │ │accounts. │listproc \S+\-help \S+\-subscribe \S+│ │ │ │\-unsubscribe │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │thread_cgi_base_url │CGI relative path │/cgi-bin/fmlthread.cgi │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │thread_cgi_bgcolor │CGI color │#E6E6FA │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │thread_cgi_title │CGI title │thread tracking system interface │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │thread_db_dir │directory to hold │$shared_db_dir/thread │ │ │ticket data │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │thread_id_syntax │ticket number │$ml_name/%d │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │thread_sequence_file │file to store ticket │$ml_home_dir/thread.seq │ │ │sequence │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │thread_subject_tag │syntax added to │[$thread_id_syntax] │ │ │Subject: │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │thread_subject_tag_location │location of insertion │appended │ │ │of tag │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │thread_subject_tag_name │ml name assigned to │$ml_name │ │ │ticket │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │tmp_dir │directory to hold │$ml_home_dir/tmp │ │ │temporary files │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │udb_base_dir │database directory │$ml_home_prefix/@udb@ │ │ │shared among ML's. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │unsafe_header_fields │remove unsafe header │Return-Receipt-To │ │ │fields │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │unsubscribe_command_auth_type │use comnfirmation in │confirmation │ │ │unsubscribe command ? │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │operate action │ │ │unsubscribe_command_operation_mode │automatically or │automatic │ │ │manually by maintainer │ │ │ │? │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │use_address_compare_function │FML::Credential checks │yes │ │ │address comparison │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │use_admin_command_mail_function │use admin command mail │no │ │ │? │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │allow a request e.g. │ │ │use_anonymous_cgi_function │subscribe and │yes │ │ │unsubscribe from www. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │use_article_delivery │user article delivery │yes │ │ │function ? │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │use_article_expire │expire too old article │no │ │ │or not ? │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │use_article_filter_reject_notice │infor the filter │yes │ │ │rejection ? │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │use_article_header_filter │use header based filter│yes │ │ │? │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │use_article_header_rewrite │use article header │yes │ │ │rewrite function ? │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │use_article_mime_component_filter │MIME structure based │yes │ │ │filter │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │use_article_non_mime_filter │dummy │yes │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │use_article_post_function │use function of article│${use_distribute_program:-yes} │ │ │delivery │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │use_article_size_filter │use size based filter. │yes │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │use_article_spam_filter │use external spam │no │ │ │checker. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │use_article_spool │store article into │${ues_spool:-yes} │ │ │spool directory ? │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │remove content │ │ │use_article_summary_file_expire │correspoding with │no │ │ │article expiration. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │use text/plain filter, │ │ │use_article_text_plain_filter │which is a simple │yes │ │ │syntax checker. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │use_article_thread_outline │add thread outline │no │ │ │automatically ? │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │use_article_virus_filter │external virus checker.│no │ │ │disabled by default. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │use_command_mail_filter_reject_notice │inform filter rejection│yes │ │ │? │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │use_command_mail_function │use commnd mail ? │${use_command_mail_program:-yes} │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │add self introduction │ │ │use_command_mail_reply_preamble │into the preamble of │yes │ │ │command mail reply. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │add processing summary │ │ │use_command_mail_reply_trailor │into the trailor of │yes │ │ │command mail reply. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │use_command_mail_size_filter │use size based filter │yes │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │use_createonpost_function │use CREATE-ON-POST or │yes │ │ │not ? │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │use_debug │debug on or off (off by│no │ │ │default). │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │use digest article │ │ │use_digest_header_rewrite │header rewrite function│yes │ │ │? │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │use_error_mail_analyzer_function │use error message │${use_error_analyzer_program:-yes} │ │ │analyzer ? │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │use fetchfml │ │ │use_fetchfml_article_post_function │article_post function │yes │ │ │or not. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │use fetchfml │ │ │use_fetchfml_command_mail_function │command_mail function │yes │ │ │or not. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │use fetchfml │ │ │use_fetchfml_error_mail_analyzer_function │error_mail_analyzer │yes │ │ │function or not. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │use_fetchfml_function │use fetchfml function │no │ │ │or not. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │use_html_archive │use html converter │yes │ │ │function ? │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │use_incoming_mail_body_loop_check │use loop check based on│yes │ │ │body information │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │use_incoming_mail_cache │cache incoing mail ? │yes │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │use_incoming_mail_envelope_loop_check │enable envelope based │yes │ │ │loop check or not ? │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │use_incoming_mail_header_loop_check │use loop check based on│yes │ │ │header information ? │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │use_lock │use lock system ? │yes │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │use_log │user logging function │yes │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │if yes, makefml/fml │ │ │use_log_computer_output │outputs machine │no │ │ │friendly log. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │use_log_rotate │rotate log files or │no │ │ │not. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │upper limit of posters.│ │ │use_member_total_limit │no limitation by │no │ │ │default. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │use_moderate_function │use moderate function │yes │ │ │or not. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │use_outgoing_mail_cache │cache outgoing mail │yes │ │ │cache ? │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │upper limit of │ │ │use_recipient_total_limit │recipients. no │no │ │ │limitation by default. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │use_smtp_log │log smtp transaction ? │yes │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │use_spool │store article into │yes │ │ │spool directory ? │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │use_thread_subject_tag │use special subject tag│no │ │ │? │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │use_thread_track │user thread tracking │yes │ │ │system ? │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │ │effective command in │help get mget get mget send subscribe│ │user_command_mail_allowed_commands │normal commnd mail (for│add unsubscribe bye on off digest │ │ │usual users) │remove resign signoff chaddr confirm │ │ │ │guide info admin objective summary │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │user_db_dir │user database │$db_dir/user_info │ │ │directory. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │user_db_gecos_maps │{ address => │$primary_user_db_gecos_map │ │ │gecos_field } maps. │ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │user_db_subscribe_date_maps │{ address => unix time │$primary_user_db_subscribe_date_map │ │ │when subscribed } maps.│ │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │var_dir │directory hoding │$ml_home_dir/var │ ├─────────────────────────────────────────────────┼───────────────────────┼─────────────────────────────────────┤ │welcome_file │welcome file │$ml_home_dir/welcome │ └─────────────────────────────────────────────────┴───────────────────────┴─────────────────────────────────────┘ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Variable List (Class Based) __exceptional__ { ? $timezone } address { address_compare { ? $address_compare_function_domain_matching_level $address_compare_function_type $use_address_compare_function } } admin { admin_command { } admin_command_mail { ? $admin_command_mail_allowed_commands $admin_command_mail_auth_gpg_config_dir ? $admin_command_mail_auth_gpg_config_dir_alias $admin_command_mail_auth_pgp_config_dir ? $admin_command_mail_auth_pgp_config_dir_alias $admin_command_mail_restrictions $use_admin_command_mail_function } admin_member { $admin_member_maps $primary_admin_member_map } admin_member_password { $admin_member_password_maps $primary_admin_member_password_map } admin_recipient { $admin_recipient_maps $primary_admin_recipient_map } admin_* { ? $admin_cgi_allowed_commands $admin_cgi_base_dir } } anonymous { anonymous_cgi { $anonymous_cgi_base_dir $anonymous_cgi_expire_limit ? $ml_anonymous_cgi_allowed_commands $ml_anonymous_cgi_base_dir ? $ml_anonymous_cgi_base_url $use_anonymous_cgi_function } anonymous_command { ? $anonymous_command_mail_allowed_commands } } article { article_delivery { ? $article_delivery_transport $use_article_delivery } article_digest { $use_article_digest_function } article_expire { $article_expire_limit $use_article_expire } article_filter { $article_filter_functions $use_article_filter } article_filter_reject_notice { $article_filter_reject_notice_data_type ? $article_filter_reject_notice_recipients $use_article_filter_reject_notice } article_header_filter { $article_header_filter_rules $use_article_header_filter } article_header_rewrite { $article_header_rewrite_rules $use_article_header_rewrite } article_mime_component_filter { $article_mime_component_filter_rules $use_article_mime_component_filter } article_non_mime_filter { $article_non_mime_filter_rules $use_article_non_mime_filter } article_post { ? $article_post_address ? $article_post_article_thread_lifetime $article_post_auth_gpg_config_dir $article_post_auth_pgp_config_dir $article_post_encrypt_gpg_config_dir $article_post_encrypt_pgp_config_dir $article_post_restrictions $article_post_restrictions_reject_notice_data_type $use_article_post_function } article_size_filter { $article_size_filter_rules $use_article_size_filter } article_spam_filter { ? $article_spam_filter_bogofilter_options ? $article_spam_filter_drivers $article_spam_filter_functions $article_spam_filter_rules ? $article_spam_filter_spamassassin_options ? $article_spam_filter_spamc_options $use_article_spam_filter } article_spool { $use_article_spool } article_summary_file_expire { $use_article_summary_file_expire } article_text_plain_filter { $article_text_plain_filter_rules $use_article_text_plain_filter } article_thread_outline { ? $article_thread_outline_greeting_en ? $article_thread_outline_greeting_ja $article_thread_outline_rules $use_article_thread_outline } article_virus_filter { ? $article_virus_filter_clamav_options ? $article_virus_filter_drivers $article_virus_filter_functions $article_virus_filter_rules $use_article_virus_filter } article_* { ? $article_header_list_help ? $article_header_list_id ? $article_header_list_owner ? $article_header_list_post ? $article_header_list_software ? $article_header_list_subscribe ? $article_header_list_unsubscribe $article_message_id_cache_dir $article_sequence_file ? $article_subject_tag $article_summary_file ? $article_summary_file_format_address_length ? $article_summary_file_format_style } } cgi { cgi_* { $cgi_base_dir ? $cgi_charset_en ? $cgi_charset_ja ? $cgi_default_charset ? $cgi_default_language ? $cgi_language_select_list ? $cgi_main_menu_color ? $cgi_menu_address_map_select_list $cgi_menu_default_address_map ? $cgi_navigation_bar_color } } command { command_mail { ? $command_mail_address $command_mail_auth_gpg_config_dir $command_mail_auth_pgp_config_dir $command_mail_line_length_limit ? $command_mail_reply_prompt $command_mail_restrictions $use_command_mail_function } command_mail_filter { $command_mail_filter_functions $use_command_mail_filter } command_mail_filter_reject_notice { $command_mail_filter_reject_notice_data_type ? $command_mail_filter_reject_notice_recipients $use_command_mail_filter_reject_notice } command_mail_invalid_command { $command_mail_invalid_command_limit } command_mail_reply_preamble { $use_command_mail_reply_preamble } command_mail_reply_trailor { $use_command_mail_reply_trailor } command_mail_size_filter { $command_mail_size_filter_rules $use_command_mail_size_filter } command_mail_valid_command { $command_mail_valid_command_limit } } admin_command { admin_command { } admin_command_mail { } } anonymous_command { anonymous_command { } } chaddr_command { chaddr_command { $chaddr_command_auth_type ? $chaddr_command_operation_mode } } confirm_command { confirm_command { $confirm_command_expire_limit ? $confirm_command_prefix } } get_command { get_command { $get_command_request_limit } } list_command { list_command { } list_command_default { $list_command_default_maps } } log_command { log_command { ? $log_command_tail_starting_location } } newml_command { newml_command { ? $newml_command_init_private_directories ? $newml_command_init_public_directories ? $newml_command_ml_admin_default_address ? $newml_command_mta_config_list $newml_command_postfix_template_files $newml_command_qmail_template_files $newml_command_template_files } } privileged_command { privileged_command { ? $privileged_command_prefix } } rmml_command { rmml_command { ? $rmml_command_mta_config_list } } subscribe_command { subscribe_command { $subscribe_command_auth_type ? $subscribe_command_operation_mode } } unsubscribe_command { unsubscribe_command { $unsubscribe_command_auth_type ? $unsubscribe_command_operation_mode } } user_command { user_command { ? $user_command_mail_allowed_commands } } createonpost { createonpost { $use_createonpost_function } createonpost_newml { $createonpost_newml_maps $createonpost_newml_restrictions } createonpost_sender { $createonpost_sender_maps $createonpost_sender_restrictions } createonpost_subscribe { $createonpost_subscribe_maps $createonpost_subscribe_restrictions } } debug { debug { $use_debug } } default { default_* { $default_mail_body_size_limit $default_mail_header_size_limit } } digest { digest_header_rewrite { $digest_header_rewrite_rules $use_digest_header_rewrite } digest_member { $digest_member_maps $primary_digest_member_map } digest_recipient { $digest_recipient_maps $primary_digest_recipient_map } digest_* { $digest_sequence_file } } directory { directory_* { ? $directory_default_mode ? $directory_private_mode ? $directory_public_mode } } domain { domain_* { $domain_config_base_dir $domain_exim_config_dir $domain_local_dir $domain_local_tmp_dir $domain_mail_config_dir $domain_postfix_config_dir $domain_procmail_config_dir $domain_qmail_config_dir $domain_sendmail_config_dir } } error { error_mail_analyzer { $error_mail_analyzer_cache_dir ? $error_mail_analyzer_cache_mode ? $error_mail_analyzer_cache_size $error_mail_analyzer_cache_type ? $error_mail_analyzer_function ? $error_mail_analyzer_function_select_list $error_mail_analyzer_simple_count_limit $use_error_mail_analyzer_function } } fetchfml { fetchfml { ? $fetchfml_fetch_protocol ? $fetchfml_imap_servers ? $fetchfml_pop_servers $fetchfml_queue_dir $use_fetchfml_function } fetchfml_article_post { ? $fetchfml_article_post_password ? $fetchfml_article_post_user $use_fetchfml_article_post_function } fetchfml_command_mail { ? $fetchfml_command_mail_password ? $fetchfml_command_mail_user $use_fetchfml_command_mail_function } fetchfml_error_mail_analyzer { ? $fetchfml_error_mail_analyzer_password ? $fetchfml_error_mail_analyzer_user $use_fetchfml_error_mail_analyzer_function } } html { html_archive { ? $html_archive_charset_en ? $html_archive_charset_ja ? $html_archive_default_charset $html_archive_dir $html_archive_index_order_type $use_html_archive } html_archive_address_mask { $html_archive_address_mask_type $use_html_archive_address_mask } html_* { ? $html_tmp_base_url $html_tmp_dir } } incoming { incoming_article { $incoming_article_body_size_limit $incoming_article_header_size_limit } incoming_command_mail { $incoming_command_mail_body_size_limit $incoming_command_mail_header_size_limit } incoming_mail_body_loop_check { $incoming_mail_body_loop_check_rules $use_incoming_mail_body_loop_check } incoming_mail_cache { $incoming_mail_cache_dir ? $incoming_mail_cache_size $use_incoming_mail_cache } incoming_mail_envelope_loop_check { $incoming_mail_envelope_loop_check_rules $use_incoming_mail_envelope_loop_check } incoming_mail_header_loop_check { $incoming_mail_header_loop_check_rules $use_incoming_mail_header_loop_check } incoming_* { $incoming_mail_body_checksum_cache_dir } } ldap { ldap_* { ? $ldap_base_dn ? $ldap_bind_dn ? $ldap_password ? $ldap_query_add_as_ldif ? $ldap_query_delete_as_ldif ? $ldap_query_find_result_attribute ? $ldap_query_find_search_filter ? $ldap_query_get_next_key_result_attribute ? $ldap_query_get_next_key_search_filter ? $ldap_query_getline_result_attribute ? $ldap_query_getline_search_filter ? $ldap_servers ? $ldap_user } } list { list_command { } list_command_default { } list_* { ? $list_addresses } } lock { lock { $lock_dir $lock_file $lock_type $use_lock } } log { log { $domain_local_log_file $log_dir $log_file ? $log_file_charset_en ? $log_file_charset_ja ? $log_file_default_charset $log_format_type ? $log_syslog_facility ? $log_syslog_ident ? $log_syslog_options ? $log_syslog_priority ? $log_syslog_servers $log_type $use_log } log_command { } log_computer_output { ? $log_computer_output_engine $use_log_computer_output } log_rotate { ? $log_rotate_archive_file_total ? $log_rotate_interval ? $log_rotate_policy $log_rotate_size_limit $use_log_rotate } } mail { mail_* { $mail_aliases_file ? $mail_header_default_errors_to ? $mail_header_default_list_help ? $mail_header_default_list_id ? $mail_header_default_list_owner ? $mail_header_default_list_post ? $mail_header_default_list_software ? $mail_header_default_list_subscribe ? $mail_header_default_list_unsubscribe ? $mail_header_default_precedence ? $mail_header_default_x_ml_name $mail_queue_dir } } maintainer { maintainer_recipient { $maintainer_recipient_maps } maintainer_* { ? $maintainer ? $maintainer_signature } } member { member { $member_maps $primary_member_map } member_total_limit { $member_total_limit $use_member_total_limit } } message { message_* { ? $message_default_subject $message_id_cache_dir $message_template_dir } } ml_local { ml_local_* { $ml_local_dir $ml_local_lib_dir $ml_local_message_template_dir $ml_local_share_dir } } moderate { moderate { $moderate_queue_dir $moderate_queue_expire_limit $use_moderate_function } } moderator { moderator_member { $moderator_member_maps $primary_moderator_member_map } moderator_recipient { $moderator_recipient_maps $primary_moderator_recipient_map } } outgoing { outgoing_article { $outgoing_article_body_size_limit $outgoing_article_header_size_limit } outgoing_command_mail { $outgoing_command_mail_body_size_limit $outgoing_command_mail_header_size_limit } outgoing_mail_cache { $outgoing_mail_cache_dir ? $outgoing_mail_cache_size $use_outgoing_mail_cache } outgoing_* { ? $outgoing_mail_header_errors_to ? $outgoing_mail_header_precedence ? $outgoing_mail_header_x_ml_name } } path { path_* { $path_bogofilter $path_bunzip2 $path_bzip2 $path_cksum $path_clamscan $path_compress $path_emacs $path_gpg $path_gpgsplit $path_gpgv $path_gunzip $path_gzcat $path_gzip $path_ish $path_kakasi $path_less $path_lha $path_ls $path_makemap $path_md5 $path_more $path_mule $path_namazu $path_newaliases $path_ng $path_nkf $path_perl $path_pgp $path_pgp5 $path_pgpe $path_pgpk $path_pgps $path_pgpv $path_postalias $path_postconf $path_postfix $path_postmap $path_sendmail $path_spamassassin $path_spamc $path_spamd $path_sum $path_tar $path_uuencode $path_vi $path_w3m $path_xemacs $path_zcat } } post { } postfix { postfix_* { ? $postfix_verp_delimiters $postfix_virtual_map_file } } procmail { procmail_* { $procmail_aliases_file } } qmail { qmail_* { ? $qmail_verp_delimiters $qmail_virtual_map_file $qmail_virtualdomains_file } } recipient { recipient { $primary_recipient_map $recipient_maps $smtp_recipient_limit } recipient_total_limit { $recipient_total_limit $use_recipient_total_limit } } reply_message { } report_mail { report_mail_* { ? $report_mail_charset_en ? $report_mail_charset_ja ? $report_mail_default_charset ? $report_mail_subject } } sendmail { sendmail_* { $sendmail_virtual_map_file } } smtp { smtp_log { $use_smtp_log } smtp_* { ? $smtp_sender ? $smtp_servers } } spammer { spammer { $primary_spammer_map $spammer_maps } } spool { spool { $spool_dir ? $spool_subdir_unit $spool_type $use_spool } } sql { sql_* { ? $sql_database ? $sql_password ? $sql_query_add ? $sql_query_delete ? $sql_query_find ? $sql_query_get_next_key ? $sql_query_getline ? $sql_servers ? $sql_table ? $sql_user } } system { system_* { ? $system_default_umask ? $system_has_alarm ? $system_has_fork ? $system_has_getpwgid ? $system_has_getpwuid ? $system_has_select ? $system_special_accounts ? $system_timezone } } template_file { template_file_* { ? $template_file_charset_en ? $template_file_charset_ja ? $template_file_charset_select_list ? $template_file_default_charset } } thread { thread_subject_tag { ? $thread_subject_tag ? $thread_subject_tag_location ? $thread_subject_tag_name $use_thread_subject_tag } thread_track { $use_thread_track } thread_* { ? $thread_cgi_base_url ? $thread_cgi_bgcolor ? $thread_cgi_title $thread_db_dir ? $thread_id_syntax $thread_sequence_file } } user { user_command { } user_db_gecos { $primary_user_db_gecos_map $user_db_gecos_maps } user_db_subscribe_date { $primary_user_db_subscribe_date_map $user_db_subscribe_date_maps } user_* { $user_db_dir } } x { } _file$ { $compat_old_fml_default_config_ph_file $deny_file $guide_file $help_file $objective_file $sequence_file $welcome_file } _dir$ { $compat_config_base_dir $compat_old_fml_config_dir $db_dir $etc_dir $event_queue_dir $isolated_queue_dir $listinfo_base_dir $listinfo_dir $listinfo_template_base_dir $listinfo_template_dir $ml_admin_cgi_base_dir $shared_db_dir $tmp_dir $udb_base_dir $var_dir } *** unclassified *** ? $file_default_mode $isolated_queue_expire_limit ? $language_preference_order ? $ml_admin_cgi_allowed_commands ? $unsafe_header_fields ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Recipes 1. What functions are proper used in config.cf file ? 1. What functions are proper used in config.cf file ? Use methods of $curproc (in hooks). ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Chapter 30. Create A New Program Create A Program (CUI) Firstly, prepare a new module in FML::Process class. See FML::Process::Calendar as the least functional model and see FML::Process::Distribute for the most complicated class. See FML::Process::Flow::ProcessStart() for mandatory methods to implement. FML::Process::Flow::ProcessStart() kicks off several methods sequentially. At 2002/07, these methods are mandatory. new() prepare() verify_request() run() finish() FML::Process::Kernel | uses-a FML::Process::{Flow,Utils} FML::Parse ... | A FML::Process::MODULE uses-a FML::Something uses-a CPAN module uses-a ... If you have prepared FML::Process::MODULE, define relation between the program name and the module at fml/etc/modules. Also, define available command line options at fml/etc/command_line_options if needed. After it is prepared, symlink the loader and the new program name. For example, % ls -l /usr/local/libexec/fml lrwxr-xr-x 1 root wheel 6 Apr 14 18:25 command@ -> loader drwxr-xr-x 2 root wheel 512 Apr 14 18:25 current-20030414/ lrwxr-xr-x 1 root wheel 6 Apr 14 18:25 digest@ -> loader lrwxr-xr-x 1 root wheel 6 Apr 14 18:25 distribute@ -> loader lrwxr-xr-x 1 root wheel 6 Apr 14 18:25 error@ -> loader lrwxr-xr-x 1 root wheel 6 Apr 14 18:25 fml@ -> loader lrwxr-xr-x 1 root wheel 6 Apr 14 18:25 fml.pl@ -> loader lrwxr-xr-x 1 root wheel 6 Apr 14 18:25 fmladdr@ -> loader lrwxr-xr-x 1 root wheel 6 Apr 14 18:25 fmlalias@ -> loader lrwxr-xr-x 1 root wheel 6 Apr 14 18:25 fmlconf@ -> loader lrwxr-xr-x 1 root wheel 6 Apr 14 18:25 fmldoc@ -> loader lrwxr-xr-x 1 root wheel 6 Apr 14 18:25 fmlhtmlify@ -> loader lrwxr-xr-x 1 root wheel 6 Apr 14 18:25 fmlsch@ -> loader lrwxr-xr-x 1 root wheel 6 Apr 14 18:25 fmlserv@ -> loader -rwxr-xr-x 1 root wheel 6863 Apr 14 18:24 loader* lrwxr-xr-x 1 root wheel 6 Apr 14 18:25 makefml@ -> loader lrwxr-xr-x 1 root wheel 6 Apr 14 18:25 mead@ -> loader As a test, you symlink it explicitly. For the canonical programs, fml installer symlinks them according to fml/etc/install.cf. You need to define the program as $bin_programs or $exec_programs in install.cf.in (configure generates install.cf). ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Create A Program (CGI) The main part of CGI program is implemented as an FML::CGI::XXX class. These modules have the following relation. FML::Process::Kernel | A FML::Process::CGI::Kernel uses-a CGI | A FML::Process::CGI | A FML::CGI::XXX How to write CGI programs is same as one of CUI. GUI modules locate under FML::CGI to clarify the difference between CUI and GUI. In the case of CGI, prepare the following methods for screen control in FML::CGI::MODULE. html_start() html_end() and run_cgi_main() run_cgi_title() run_cgi_navigator() run_cgi_menu() run_cgi_command_help() run_cgi_options() These methods are called from verify_request() and run() in FML::Process::CGI. CGI process is driven by FML::Process::CGI. run() method calls $curproc->html_start($args); call a set of run_cgi_xxx() methods $curproc->html_end($args); to control screen. At 2001/11, FML::Process::CGI::Kernel consists of the following methods: [9] new() prepare() verify_request() run() finish() You do not need edit these files. FML::CGI:: is called at run() method. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Chapter 31. fml8 Mail Delivery System The Difference Between fml4 And fml8 One of purposes of fml8 is unification and abstraction of member list operations. Mail distribution is based on the following module Mail::Delivery. Mail::Delivery class provides SMTP, ESMTP and LMTP delivery library interface. Mail::Delivery is an adapter layer for Mail::Delivery subclass ( SMTP ESMTP LMTP ). For example, use Mail::Delivery::SMTP; my $service = new Mail::Delivery::SMTP; if ($service->error) { Log($service->error); return;} $service->deliver( { mta => '127.0.0.1:25', smtp_sender => 'rudo@nuinui.net', recipient_maps => $recipient_maps, recipient_limit => 1000, mesage => $message }); where $message is a Mail::Message object. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Mail::Message Object This object provies message analyzer. It analyzes a message and build the following object chains on memory. header -> body header -> preamble -> part1 -> part2 -> trailor (multipart) Mail::Message class provides such data structure described above. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Incoming Queuing MTA kicks off a fml process. It reads a message from STDIN. The fml process reads a message once and write it onto the hard disk (write it into the incoming queue). After the queuing succeeded, the process starts to analyze a message. For this logic, the original mail is saved before main processing starts. If the queuing fails, fml calls exit(EX_TEMPFAIL). In almost cases, exit(75). If MTA receives this exit code, MTA tries to deliver again later. Mail::Delivery::Queue class processes the incoming queue. The queus is removed when the process ends. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ fml Sends Back A Mail Message Mail::Delivery::Queue class inserts a message to send back into the mail queue. Later FML::Process::QueueManager handles the real delivery process. Article delivery processing is a little diffferent but based on queueing by Mail::Delivery::Queue. If someting error occurs in delivery, another fml process tries to deliver it later. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Coding In fml8 Sources. Code is like this to send back a message: $curproc->reply_message( "you are not a ML member." ); If no recipient specified, the recipient is the sender of the message (From: address). To send a file, like this: $curproc->reply_message( { type => "text/plain; charset=iso-2022-jp", path => "/etc/fml/main.cf", filename => "main.cf", disposition => "main.cf example", }); $curproc->reply_message( { type => "image/gif", path => "/some/where/logo001.gif", filename => "logo.gif", disposition => "attachment", }); ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Mail Queue And Delivery System FML::Process::QueueManager picks up one queue from the queue directory. Mail::Message parses it. Mail::Delivery processes the real delivery via FML::Mailer. Mail::Delivery::Queue | | ---> queue directory V FML::Process::QueueManager | | <--- queue directory V FML::Mailer | V Mail::Delivery In manipulating queue, we should lock the target queue by flock(2). ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Mail Queue Directory The queue directory consists of the following plural directories: new/ active/ incoming/ deferred/ info/sender/ info/recipients/ info/transport/ info/ stores envelope information. incoming/ holds incoming queue, others hold outgoing information. In creating a new outgoing queue file, make a temporary file in new/ once. When the delivery preparation is ended, move the queue from new/ to active/. Hence files under active/ is delivery ready. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Lock The Queue When we need to handle the specific queue file, use lock()/unlock() method for each $queue_id object. The lock algorithm is based on flock(2) for the file. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Queue Management System Since 2004 summer, delivery system of fml8 is under queue management system like MTA. Now fml8 can deliver again messages by itself. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Discussion: FML::Mailer Is Apropriate ? Only FML::Process::QueueManager uses FML::Mailer. So, independent FML::Mailer class is needed ? In usual codes, reply_message() handles all message operations. FML::Mailer is always behind it. But modules other than reply_message() is created in the future ? Hmm, ... FML::Mailer should be merged into FML::Process::QueueManager class? ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Delivery TIPS 1. Wwitch forwarding address regarding the mail content. 1. Wwitch forwarding address regarding the mail content. It is simple if you can prepare different files as necessary. For example, prepare recipients.A recipients.B recipients.C for the corresponding conditions A B C. Set up the following hook: if (condition A matched) { $config->set('recipient_maps', "recipients.A"); } elsif (condition B matched) { $config->set('recipient_maps', "recipients.B"); } elsif (condition C matched) { $config->set('recipient_maps', "recipients.C"); } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Chapter 32. Digest Delivery Run /usr/local/libexec/fml/digest $ml_name periodically for digest delivery. It aggregates articles into one MIME/ multipart message and send it to members defined by $digest_recipient_maps. ┌─────────────────────────────────────────────────────────────────────────────┐ │ Warning │ ├─────────────────────────────────────────────────────────────────────────────┤ │Digest delivery program is a simple version yet now. │ └─────────────────────────────────────────────────────────────────────────────┘ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Files Used For Digest Delivery Control This program uses the following files under $ml_home_dir. seq-digest members-digest recipients-digest seq-digest holds the last sequence delivered as digest. members-digest is dummy. recipients-digest is a recipient list. $digest_recipient_maps is this recipients-digest file only by default. The argument of $digest_recipient_maps is IO::Adapter, so you can use mysql here. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Idea: Digest Related Commands Idea on digest commands (references: fml-devel:313). Hmm, how about the further extension? ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ makefml command makefml digest $ml $address on makefml digeston $ml $address makefml digest $ml $address off makefml digestoff $ml $address (These commands are implemented already). ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ admin command mail admin digest $address on admin digest $address off (These commands are implemented already). ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ user level command mail ? digest on digest off The confirmation is needed ? Yes, we should need it to unify the fml fundamental design. We should restrict address manipulation functions as could as possible. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CGI digeston digestoff ok? ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ recipes 1. When digest program should run ? 2. Can we change default compression style in digest delivery ? 3. Can we specify parameters in running "makefml add" ? 4. Can we log digest log mesages in the file other than the default log file ? 1. When digest program should run ? Anytime OK. Please edit crontab. 2. Can we change default compression style in digest delivery ? No since fml8 supports only MIME/Multipart now. 3. Can we specify parameters in running "makefml add" ? No since fml8 supports only MIME/Multipart now. 4. Can we log digest log mesages in the file other than the default log file ? Not configurable. But you can if you us HOOK. [Example] $article_digest_prepare_start_hook = q{ $config->{ log_file } = "/some/where/log.digest"; }; ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Chapter 33. Language Preference In Processing Problems Of Language Preference The simplest model is that we suppose we should return the japanese message when the ML is configured as for Japanese. This model needs that the language of a ML is fixed. This ML always returns the error message in Japanese. However, it is not proper to ignore Accept-Language: header field since some Japanese people cannot read Japanese on the screen. There may be invalid Accept-Language: field. There are several problems. For example, if "Accept-Language: ja" is given, we can recognize the language is "ja". However, how about the case Japanese send a mail with the body content "help" (English) ? In that case we cannot determine we should return the reply in us-ascii or iso-2022-jp. For example, how about the following example ? [Example] From: rudo@example.co.jp Subject: help mime-version: 1.0 content-type: text/plain; charset=us-ascii help We should return the English reply message based on charset information since this message contains English only, so charset is us-ascii. But in this case we should return Japanese message since the sender is a Japanese. So we should return the help message in both English and Japanese if the ML is configured as Japanese preferrable. If English is preferrable, the reply is English only. If Accept-Lanaguage: is specified, we prefer it. Even if the ML is English preferrable (config: language_preference_order = en) and the message with "Accept-Lanaguage: ja" is given, the ML returns the Japanese help message. fml8 behaves like it. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Japanese Preferred ML language_preference_order variable controls the behaviour. By default, an ML for Japanese is configured as language_preference_order = ja en fml8 uses this hint. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Accept-Language: ja, en fml8 returns the message only in Japanese. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Accept-Language: en fml8 returns the message only in English. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ no Accept-Language:, Content-Type: charset=iso-2022-jp fml8 returns the message only in Japanese. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ no Accept-Language:, Content-Type: charset=us-ascii We cannot determine the language. We should return the message in both English and Japanese. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ no Accept-Language:, no Content-Type: We cannot determine the language. We should return the message in both English and Japanese. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ English preferred ML By default, a ML for English people is configured as language_preference_order = en fml8 uses this hints. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Accept-Language: ja, en fml8 returns the message only in Japanese. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Accept-Language: en fml8 returns the message only in English. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ no Accept-Language:, Content-Type: charset=iso-2022-jp fml8 returns the message only in Japanese. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ no Accept-Language:, Content-Type: charset=us-ascii fml8 returns the message only in English. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ no Accept-Language:, no Content-Type: fml8 returns the message only in English. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Chapter 34. Manipulate Message (Mail Message) See Mail::Message class for the mail message object handling. Mail::Message class provides fundamental methods. Several message handling modules e.g. Mail::Bounce, Mail::Delivery depend on this class. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Mail::Message Class A mail consists of one header and one body. A multipart mail body consists of several parts. The mail delivery module needs not to know the detail of a message. But the filter system needs to know the structure of the message. These modules depend Mail::Message class to know the message structure. For example, Mail::Bounce, Mail::Delivery et.al. use this class. The usage is as follows: my $fh = new FileHandle $file; my $msg = Mail::Message->parse( { fd => $fh } ); use FML::Mailer; my $obj = new FML::Mailer; $obj->send( { sender => $sender, recipient => $rcpt, message => $msg, }); ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Mail::Message::Parse Class dummy. The real functions are within Mail::Message class. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Mail::Message::Compose Class dummy. This is an adapter for MIME::Lite class. All requests are forwarded to MIME::Lite class. See MIME::Lite class for the usage details. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Message Internationalization: The Usage Of reply_message_nl() For the message internationalization, use reply_message_nl() [10] like this: $curproc->reply_message_nl('error.already_member', 'already member', { _arg_address => $address }); This function uses the message template at /usr/local/share/fml/$fml_version/ message/$language/error/already_member . $_arg_VARNAME in the message template such as $_args_address is expanded by using the value specified as the argument of reply_mesage_nl(). Usual $VARIABLE is also expaned by replacing it with value of config name space. For example, $ml_name is expanded to ML name defined in config.cf. In fact $_arg_ prefix is used for lexical scope variables to avoid conflicts against variables in config.cf. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Discussion: How To Send Back Language Dependent Error Mesages fml needs to send back language dependent error messages. How we should implement it ? (Below, just a discussion not implemation in fact.) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ fml4 Case In the case of fml4, fml4 calls language dependent message converter like this: Mesg(*e, KEYWORD, DEFAULT MESSAGE, ARGUMENT); Mesg() searches the specified keyword in files under /usr/local/fml/messages/ Japanese/ directory. Each file contains messages with keywords to be substituted properly. For example, the keyword not_found matches not_found entry in /usr/local/fml/ messages/Japanese/kern file. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ What fml8 Should Do ? "One file has one keyword" and "one file for one category, so one file contains plural entries". Hmm, which is better? I don't determine it. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ X/Open Portability Guide Issue 4 Version 2 (``XPG4.2'') If you use XPG (X/Open standard), catgets(catd, set_id, msg_id, char *s); function converts the message specified by LOCALE_XXX. [11] For example, the usage is as follows: printf(catgets(catd, 30, 4, "%s: Internal match error.\n"), progname); This function uses set 30 and entry 4 in the local definition file such as /usr /pkg/share/nls/ja_JP.EUC/PROGNAME.cat. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ fml8: Design (Temporary ?) One problem is whether we should use locale or not ? In considering CUI e.g. makefml, it is better to use locale. For example, prepare /usr/local/lib/fml/$fml_version/messages/ja_JP.EUC/kern 1: %s not found 2: %s (error number = %d) . Instead, one file for one message may be useful. Especially it is easy we can customize only one message. To try the latter case, we can prepare a lot of classes such as FML::Message::ja::KEYWORD For example, there are 200 or 300 files such as FML::Message::ja::not_found . This methods has the following problems: • separete files but in contrast more customizable. • locale friendly? may be no. Consider an example. In the latter case, the message module will be like this? sub not_found { my .. = @_; return <<"_EOF_" $sender is ... something ... _EOF_ } Hmm, is it good ??? ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Chapter 35. Filter ┌─────────────────────────────────────────────────────────────────────────────┐ │ Caution │ ├─────────────────────────────────────────────────────────────────────────────┤ │Filter described here is filter system for articles posted to ML. This filter│ │is implemented as FML::Filter class. │ │ │ │Other than article filter, there may be command mail filter. FML::Filter does│ │not provide such function. Instead, FML::Command::Filter class provides │ │command mail specific filter e.g. line length limit of one line. │ └─────────────────────────────────────────────────────────────────────────────┘ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Overview Of Filter System There are three types of filter system for content check such as for header, body and mime structure based. Other than the tree cases, we should consider text/plain and non mime text (text/?) filter. So there may be four types of filter. header body non-mime permit / reject (!MIME of 4.0's content filter) mime component filter 4.0's content filter text/plain filter ja, en, ... (language dependent) language independent (e.g. M$ GUID scanner) check of the first text/plain part syntax check external filter (call external virus/spam checker) clamav spamassassin bogofilter Other than these filters, content_filter using SMTP/LMTP can be needed but not implemented. If you need content_filter, please use the function of Postfix. Traffic based filter is also needed but not implemented yet. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Configuration Variables Each sub filter system is enabled/disabled independently. use_SERVICE_filter = yes SERVICE_filter_functions = function_A function_B use_function_A = yes function_A_rules = rule_01 urle_02 # Descriptions: how to inform the rejected message # when the filter system rejects. # We prefer string not mime/multipart to avoid parsing by MUA. # History: string in 4.0. # Value: SELECT ( multipart string ) # Examples: string article_post_restrictions_reject_notice_data_type = string =head2 filter # Descriptions: # History: fml8 rearragena fml4 filter functions and integrates them # into one. # Roughly speaking, fml8 filter is composed of the following # $USE_DISTRIBUTE_FILTER # $INCOMING_MAIL_SIZE_LIMIT # ADD_CONTENT_HANDLER() # functions. # Value: YES_OR_NO # Examples: yes use_article_filter = yes # Descriptions: # History: # Value: MIX ( # article_size_filter # article_header_filter # article_non_mime_filter # article_mime_component_filter # article_text_plain_filter # article_spam_filter # article_virus_filter # ) # Examples: article_filter_functions = article_size_filter article_header_filter article_non_mime_filter article_mime_component_filter article_text_plain_filter article_spam_filter article_virus_filter =head2 size based filter # Descriptions: use size based filter. # History: no # Value: YES_OR_NO # Examples: use_article_size_filter = yes # Descriptions: size based filter rules. # first match. # permit post if no rule matched. # History: # Value: MIX ( check_header_size # check_body_size # permit # ) # Examples: article_size_filter_rules = check_header_size check_body_size permit =head2 header base filter # Descriptions: use header based filter ? # History: disabled by default. # "yes" always if $USE_DISTRIBUTE_FILTER is yes. # Value: YES_OR_NO # Examples: use_article_header_filter = yes # Descriptions: header filter rules. # first match. # permit post if no rule matched. # History: fml4 has no check_date rule. # Value: MIX ( # check_message_id # check_date # permit # ) # Examples: article_header_filter_rules = check_message_id check_date permit =head2 filter for non MIME structure # Descriptions: dummy # History: disabled by default. # !MIME of 4.0 content filter. # Value: YES_OR_NO # Examples: use_article_non_mime_filter = yes # Descriptions: dummy # History: # Value: MIX ( permit reject_empty_content_type ) # Examples: permit article_non_mime_filter_rules = permit # Descriptions: MIME structure based filter # History: 4.0 content filter. disabled by default. # Value: YES_OR_NO # Examples: use_article_mime_component_filter = yes # Descriptions: file of filter rules # History: @CONTENT_HANDLER # Value: FILE # Examples: article_mime_component_filter_rules = $fml_config_dir/mime_component_filter =head2 filter for text/plain # Descriptions: use text/plain filter, which is a simple syntax checker. # History: 4.0's EnvelopeFilter. # half of the following rules applied when # $USE_DISTRIBUTE_FILTER is enabled. # Value: YES_OR_NO # Examples: use_article_text_plain_filter = yes # Descriptions: filter rules of text/plain filter. # first match. # permit post if no rule matched. # History: See kern/libenvf.pl for more detail. # [DISABLED BY DEFAULT] # # reject_not_iso2022jp_japanese_string # <=> FILTER_ATTR_REJECT_INVALID_JAPANESE # reject_old_fml_command_syntax # <=> FILTER_ATTR_REJECT_COMMAND # reject_japanese_command_syntax # <=> FILTER_ATTR_REJECT_2BYTES_COMMAND # # [ENABLED BY DEFAULT] # # reject_null_mail_body # <=> FILTER_ATTR_REJECT_NULL_BODY # reject_invalid_fml_command_syntax # <=> FILTER_ATTR_REJECT_INVALID_COMMAND # reject_one_line_message # <=> FILTER_ATTR_REJECT_ONE_LINE_BODY # reject_ms_guid # <=> FILTER_ATTR_REJECT_MS_GUID # # Note: permit by default # Value: MIX ( # reject_not_iso2022jp_japanese_string # reject_null_mail_body # reject_one_line_message # reject_old_fml_command_syntax # reject_invalid_fml_command_syntax # reject_japanese_command_syntax # reject_ms_guid # permit # ) # Examples: article_text_plain_filter_rules = reject_not_iso2022jp_japanese_string reject_null_mail_body reject_one_line_message reject_old_fml_command_syntax reject_invalid_fml_command_syntax reject_japanese_command_syntax reject_ms_guid permit =head2 external SPAM filter # Descriptions: use external spam checker. # disabled by default. # add flag to header and go through if the message looks a spam. # History: none # Value: YES_OR_NO # Examples: no use_article_spam_filter = no # Descriptions: action if the message looks a spam. # History: none # Value: MIX ( reject ignore header_rewrite ) # Examples: header_rewrite article_spam_filter_rules = header_rewrite # Descriptions: external spam checker. # if plural drivers specified, try them sequentially. # History: none # Value: MIX ( spamassasin spamc bogofilter ) # Examples: bogofilter article_spam_filter_drivers = bogofilter # Descriptions: external virus checker. disabled by default. # History: none # Value: YES_OR_NO # Examples: no use_article_virus_filter = no # Descriptions: action if virus found. # History: none # Value: MIX ( reject ignore header_rewrite ) # Examples: reject article_virus_filter_rules = reject # Descriptions: external virus checker. # if plural drivers specified, try them sequentially. # History: none # Value: MIX ( clamscan ) # Examples: clamscan article_virus_filter_drivers = clamscan =head2 inform the filter rejection # Descriptions: infor the filter rejection ? # History: halfly hard-coded in fml 4.0. # notice is always sent to maintainer, # but not to sender by default. # $FILTER_NOTIFY_REJECTION controlls notice to sender. # Value: YES_OR_NO # Examples: yes use_article_filter_reject_notice = yes # Descriptions: recipients to inform # History: halfly hard-coded in fml 4.0. # notice is always sent to maintainer, # but not to sender by default. # $FILTER_NOTIFY_REJECTION controlls notice to sender. # Value: MIX ( maintainer sender ) # Examples: maintainer sender article_filter_reject_notice_recipients = maintainer sender # Descriptions: how fml refer the rejeced message. # We prefer string not multipart to avoid parsing of MUA. # History: string in fml 4.0. # Value: SELECT ( multipart string ) # Examples: string article_filter_reject_notice_data_type = string # Descriptions: # History: # Value: YES_OR_NO # Examples: use_article_spam_filter = no # Descriptions: list up driver names used as spam checker. # History: none # Value: MIX ( spamassassin spamc bogofilter ) # Examples: bogofilter article_spam_filter_functions = bogofilter # Descriptions: exit non-zero status code when spam caught if "-e" specified. # History: none # Value: COMMAND_LINE_OPTIONS # Examples: -e article_spam_filter_spamassassin_options = -e # Descriptions: spamc optoins. "-c" means check only. # History: none # Value: COMMAND_LINE_OPTIONS # Examples: -c article_spam_filter_spamc_options = -c # Descriptions: "-e" implies embedded mode. # History: none # Value: COMMAND_LINE_OPTIONS # Examples: -e article_spam_filter_bogofilter_options = -e # Descriptions: # History: # Value: YES_OR_NO # Examples: use_article_virus_filter = no # Descriptions: list up driver names used as virus checker. # History: none # Value: MIX ( virusassassin virusc bogofilter ) # Examples: bogofilter article_virus_filter_functions = clamav # Descriptions: --mbox needed for mail files. # History: none # Value: COMMAND_LINE_OPTIONS # Examples: --quiet --mbox article_virus_filter_clamav_options = --quiet --mbox =head2 filter # Descriptions: # History: # Value: YES_OR_NO # Examples: use_command_mail_filter = yes # Descriptions: # History: # Value: MIX ( command_mail_size_filter ) # Examples: command_mail_filter_functions = command_mail_size_filter =head2 size based filter # Descriptions: use size based filter # History: # Value: YES_OR_NO # Examples: use_command_mail_size_filter = yes # Descriptions: size based filter rules. # first match. # permit if no rule matched. # History: # Value: MIX ( # check_header_size # check_body_size # check_command_limit # check_line_length_limit # permit # ) # Examples: command_mail_size_filter_rules = check_header_size check_body_size check_command_limit check_line_length_limit permit =head2 inform filter rejection # Descriptions: inform filter rejection ? # History: hard-coded. # Value: YES_OR_NO # Examples: yes use_command_mail_filter_reject_notice = yes # Descriptions: recipients to inform # History: hard-coded. # Value: MIX ( maintainer sender ) # Examples: maintainer sender command_mail_filter_reject_notice_recipients = maintainer sender # Descriptions: how fml refer the rejeced message. # We prefer string not multipart to avoid parsing of MUA. # History: string in fml 4.0. # Value: SELECT ( multipart string ) # Examples: string command_mail_filter_reject_notice_data_type = string # Descriptions: # History: # Value: FILE # Examples: path_bogofilter = @BOGOFILTER@ # $article_digest_finish_end_hook = q{ 1;}; # $article_digest_finish_start_hook = q{ 1;}; # $article_digest_prepare_end_hook = q{ 1;}; # $article_digest_prepare_start_hook = q{ 1;}; # $article_digest_run_end_hook = q{ 1;}; # $article_digest_run_start_hook = q{ 1;}; # $article_digest_verify_request_end_hook = q{ 1;}; # $article_digest_verify_request_start_hook = q{ 1;}; # $article_filter_end_hook = q{ 1;}; # $article_filter_start_hook = q{ 1;}; # $article_header_rewrite_end_hook = q{ 1;}; # $article_header_rewrite_start_hook = q{ 1;}; # $article_post_finish_end_hook = q{ 1;}; # $article_post_finish_start_hook = q{ 1;}; # $article_post_prepare_end_hook = q{ 1;}; # $article_post_prepare_start_hook = q{ 1;}; # $article_post_run_end_hook = q{ 1;}; # $article_post_run_start_hook = q{ 1;}; # $article_post_verify_request_end_hook = q{ 1;}; # $article_post_verify_request_start_hook = q{ 1;}; # $command_mail_filter_end_hook = q{ 1;}; # $command_mail_filter_start_hook = q{ 1;}; # $command_mail_finish_end_hook = q{ 1;}; # $command_mail_finish_start_hook = q{ 1;}; # $command_mail_prepare_end_hook = q{ 1;}; # $command_mail_prepare_start_hook = q{ 1;}; # $command_mail_run_end_hook = q{ 1;}; # $command_mail_run_start_hook = q{ 1;}; # $command_mail_verify_request_end_hook = q{ 1;}; # $command_mail_verify_request_start_hook = q{ 1;}; # $createonpost_finish_end_hook = q{ 1;}; # $createonpost_finish_start_hook = q{ 1;}; # $createonpost_prepare_end_hook = q{ 1;}; # $createonpost_prepare_start_hook = q{ 1;}; # $createonpost_run_end_hook = q{ 1;}; # $createonpost_run_start_hook = q{ 1;}; # $createonpost_verify_request_end_hook = q{ 1;}; # $createonpost_verify_request_start_hook = q{ 1;}; # $distribute_finish_end_hook = q{ 1;}; # $distribute_finish_start_hook = q{ 1;}; # $distribute_prepare_end_hook = q{ 1;}; # $distribute_prepare_start_hook = q{ 1;}; # $distribute_run_end_hook = q{ 1;}; # $distribute_run_start_hook = q{ 1;}; # $distribute_verify_request_end_hook = q{ 1;}; # $distribute_verify_request_start_hook = q{ 1;}; # $error_mail_analyzer_finish_end_hook = q{ 1;}; # $error_mail_analyzer_finish_start_hook = q{ 1;}; # $error_mail_analyzer_prepare_end_hook = q{ 1;}; # $error_mail_analyzer_prepare_start_hook = q{ 1;}; # $error_mail_analyzer_run_end_hook = q{ 1;}; # $error_mail_analyzer_run_start_hook = q{ 1;}; # $error_mail_analyzer_verify_request_end_hook = q{ 1;}; # $error_mail_analyzer_verify_request_start_hook = q{ 1;}; # $faker_finish_end_hook = q{ 1;}; # $faker_finish_start_hook = q{ 1;}; # $faker_prepare_end_hook = q{ 1;}; # $faker_prepare_start_hook = q{ 1;}; # $faker_run_end_hook = q{ 1;}; # $faker_run_start_hook = q{ 1;}; # $faker_verify_request_end_hook = q{ 1;}; # $faker_verify_request_start_hook = q{ 1;}; # $fetchfml_finish_end_hook = q{ 1;}; # $fetchfml_finish_start_hook = q{ 1;}; # $fetchfml_prepare_end_hook = q{ 1;}; # $fetchfml_prepare_start_hook = q{ 1;}; # $fetchfml_run_end_hook = q{ 1;}; # $fetchfml_run_start_hook = q{ 1;}; # $fetchfml_verify_request_end_hook = q{ 1;}; # $fetchfml_verify_request_start_hook = q{ 1;}; # $fmladdr_finish_end_hook = q{ 1;}; # $fmladdr_finish_start_hook = q{ 1;}; # $fmladdr_prepare_end_hook = q{ 1;}; # $fmladdr_prepare_start_hook = q{ 1;}; # $fmladdr_run_end_hook = q{ 1;}; # $fmladdr_run_start_hook = q{ 1;}; # $fmladdr_verify_request_end_hook = q{ 1;}; # $fmladdr_verify_request_start_hook = q{ 1;}; # $fmlalias_finish_end_hook = q{ 1;}; # $fmlalias_finish_start_hook = q{ 1;}; # $fmlalias_prepare_end_hook = q{ 1;}; # $fmlalias_prepare_start_hook = q{ 1;}; # $fmlalias_run_end_hook = q{ 1;}; # $fmlalias_run_start_hook = q{ 1;}; # $fmlalias_verify_request_end_hook = q{ 1;}; # $fmlalias_verify_request_start_hook = q{ 1;}; # $fmlconf_finish_end_hook = q{ 1;}; # $fmlconf_finish_start_hook = q{ 1;}; # $fmlconf_prepare_end_hook = q{ 1;}; # $fmlconf_prepare_start_hook = q{ 1;}; # $fmlconf_run_end_hook = q{ 1;}; # $fmlconf_run_start_hook = q{ 1;}; # $fmlconf_verify_request_end_hook = q{ 1;}; # $fmlconf_verify_request_start_hook = q{ 1;}; # $fmldoc_finish_end_hook = q{ 1;}; # $fmldoc_finish_start_hook = q{ 1;}; # $fmldoc_prepare_end_hook = q{ 1;}; # $fmldoc_prepare_start_hook = q{ 1;}; # $fmldoc_run_end_hook = q{ 1;}; # $fmldoc_run_start_hook = q{ 1;}; # $fmldoc_verify_request_end_hook = q{ 1;}; # $fmldoc_verify_request_start_hook = q{ 1;}; # $fmlhtmlify_finish_end_hook = q{ 1;}; # $fmlhtmlify_finish_start_hook = q{ 1;}; # $fmlhtmlify_prepare_end_hook = q{ 1;}; # $fmlhtmlify_prepare_start_hook = q{ 1;}; # $fmlhtmlify_run_end_hook = q{ 1;}; # $fmlhtmlify_run_start_hook = q{ 1;}; # $fmlhtmlify_verify_request_end_hook = q{ 1;}; # $fmlhtmlify_verify_request_start_hook = q{ 1;}; # $fmlpgp_finish_end_hook = q{ 1;}; # $fmlpgp_finish_start_hook = q{ 1;}; # $fmlpgp_prepare_end_hook = q{ 1;}; # $fmlpgp_prepare_start_hook = q{ 1;}; # $fmlpgp_run_end_hook = q{ 1;}; # $fmlpgp_run_start_hook = q{ 1;}; # $fmlpgp_verify_request_end_hook = q{ 1;}; # $fmlpgp_verify_request_start_hook = q{ 1;}; # $makefml_finish_end_hook = q{ 1;}; # $makefml_finish_start_hook = q{ 1;}; # $makefml_prepare_end_hook = q{ 1;}; # $makefml_prepare_start_hook = q{ 1;}; # $makefml_run_end_hook = q{ 1;}; # $makefml_run_start_hook = q{ 1;}; # $makefml_verify_request_end_hook = q{ 1;}; # $makefml_verify_request_start_hook = q{ 1;}; ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Size Limit fml8 provides size limit for header and body. Also you can use different size limit of article or command mail. Implementation of this filter is easy since the input message is analyzed already. =head1 size limit =head2 default size limit # Descriptions: header size limit # History: # Value: NUM # Examples: 102400 default_mail_header_size_limit = 102400 # Descriptions: body size limit # History: # Value: NUM # Examples: 10240000 default_mail_body_size_limit = 10240000 # Descriptions: the maximum number of cached incoming mails # History: $NUM_LOG_MAIL # Value: NUM # Examples: 128 incoming_mail_cache_size = 128 # Descriptions: the maximum number of cached outgoing mails # History: $NUM_LOG_MAIL # Value: NUM # Examples: 128 outgoing_mail_cache_size = 128 # Descriptions: log rotation policy. # History: none # Value: SELECT ( size interval ) # Examples: size log_rotate_policy = size # Descriptions: rotate log if the size is over this size. # History: $LOGFILE_NEWSYSLOG_LIMIT value. # Value: NUM # Examples: 300000 (300K bytes) log_rotate_size_limit = 300000 =head2 size limit # Descriptions: maximum size limit of article header passed from MTA. # History: # Value: NUM # Examples: 102400 incoming_article_header_size_limit = $default_mail_header_size_limit # Descriptions: maximum size limit of article body passed from MTA. # History: # Value: NUM # Examples: 10240000 incoming_article_body_size_limit = $default_mail_body_size_limit # Descriptions: maximum size limit of deliverd article header. # (not yet implemented ;-) # History: # Value: NUM # Examples: 102400 outgoing_article_header_size_limit = $default_mail_header_size_limit # Descriptions: maximum size limit of deliverd article body. # (not yet implemented ;-) # Value: NUM # Examples: 10240000 outgoing_article_body_size_limit = $default_mail_body_size_limit # Descriptions: # History: # Value: MIX ( # article_size_filter # article_header_filter # article_non_mime_filter # article_mime_component_filter # article_text_plain_filter # article_spam_filter # article_virus_filter # ) # Examples: article_filter_functions = article_size_filter article_header_filter article_non_mime_filter article_mime_component_filter article_text_plain_filter article_spam_filter article_virus_filter =head2 size based filter # Descriptions: use size based filter. # History: no # Value: YES_OR_NO # Examples: use_article_size_filter = yes # Descriptions: size based filter rules. # first match. # permit post if no rule matched. # History: # Value: MIX ( check_header_size # check_body_size # permit # ) # Examples: article_size_filter_rules = check_header_size check_body_size permit =head2 size limit # Descriptions: maximum size limit of article header passed from MTA. # History: # Value: NUM # Examples: 102400 incoming_command_mail_header_size_limit = $default_mail_header_size_limit # Descriptions: maximum size limit of article body passed from MTA. # History: # Value: NUM # Examples: 10240000 incoming_command_mail_body_size_limit = $default_mail_body_size_limit # Descriptions: maximum size limit of deliverd article header. # (not yet implemented ;-) # History: # Value: NUM # Examples: 102400 outgoing_command_mail_header_size_limit = $default_mail_header_size_limit # Descriptions: maximum size limit of deliverd article body. # (not yet implemented ;-) # History: # Value: NUM # Examples: 10240000 outgoing_command_mail_body_size_limit = $default_mail_body_size_limit # Descriptions: # History: # Value: MIX ( command_mail_size_filter ) # Examples: command_mail_filter_functions = command_mail_size_filter =head2 size based filter # Descriptions: use size based filter # History: # Value: YES_OR_NO # Examples: use_command_mail_size_filter = yes # Descriptions: size based filter rules. # first match. # permit if no rule matched. # History: # Value: MIX ( # check_header_size # check_body_size # check_command_limit # check_line_length_limit # permit # ) # Examples: command_mail_size_filter_rules = check_header_size check_body_size check_command_limit check_line_length_limit permit # Descriptions: cache size. # it implies days if the cache mode is temporal. # History: none # Value: NUM # Examples: error_mail_analyzer_cache_size = 14 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Limit For Command Mail fml8 provides restrictions such as "the number of commands in one command mail message", "the number of articles in one command mail message", et.al. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Mime Component Filter Rules The format of fml8 mime component filter is space separeted. It is not fml4's content filter rules. text/plain permit text/html reject * permit This filter supporse MIME, not including non mime operations. To identify the whole type (e.g. text/plain) and the part type (e.g. text/plain in multipart/ mixed), we use the following format. Whole message type part type action ---------------------------------------------- text/plain * permit multipart/mixed text/plain permit multipart/mixed text/html reject multipart/mixed image/* cutoff * * permit the following operations are not implemented but needed ? text/plain :uuencoded: cutoff text/plain :size>500k cutoff But there are several problems of rule construction. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ First Match Vs Last Match ? This is a filter but not a router filter. Router filter is first match in almost cases. But both first match and last match are not suitable for mime component filter when we consider the meaning of "cutoff" operation. ( NOT TRANSLATED AFTER THIS ) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Discussion: Mime Component Filter Needs What Functions ? ( NOT TRANSLATED AFTER THIS ) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Chapter 36. Subscribe / Unsubscribe Which Map Subscribe/Unsubscribe Is Operated To ? Subscribe/unsubscribe is operated to $primary_*_map. For example, subscription of remote administrators is operated into both $primary_admin_member_map and $primary_admin_recipient_map. Unsubscription of remote administrators is operated into both $primary_admin_member_map and $primary_admin_recipient_map. Why use primary_*_map ? If we use admin_member_maps and admin_recipient_maps, it causes a problem. Subscription should be operated into one map. So we should operate it into primary_*_map. Unsubscription must be same since xxx_maps is composed of different privileged maps. For example, $member_maps is as follows. It contais a list of member and a list of remote administrators. member_maps = $primary_member_map $admin_member_maps So unsubscription operated for $member_maps may cause unsubscription of remote administrators. It is wrong logic. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Chapter 37. Command (Command Mail, CUI And GUI) Modules for commands In fml8, all command modules are shared among command mail, CUI (makefml, fml) and GUI (CGI). Commands are caregorized into user and administrative ones by the priviledge. FML::Command class consists of the following classes: FML::Command entrance into FML::Command. command dispatcher. FML::Command::User command for general ML users. FML::Command::Admin command for remote administrators. For example, a user command in a command mail kicks off FML::Command firstly, after some steps, calls FML::Command::User::$command where $command is the specified command name. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ User Command In Command Mail FML::Process::Command call FML::Command::User::$command for $command via FML::Command. FYI: some module calls FML::Command::Admin::$command for real work even if it is a user command. For example, FML::Command::Admin::subscribe works for subscription. In this case, FML::Command::User::subscribe module is a wrapper/ entrance for confirmation before the real subscription process runs. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Admin Command (Administrative Command In Command Mail) It calles FML::Command::Admin::$command for $command via FML::Command via FML::Process::Command. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CUI (makefml/fml) FML::Process::Configure calls FML::Command::Admin::$command via FML::Command. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ GUI (CGI) FML::Process::CGI calls FML::Command::Admin::$command via FML::Command. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Data Flow Of Command Request Processing All command processing calls FML::Command::MODE::COMMAND class via FML::Command class. GUI, CUI and command mail has different pre processing stage. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Command Mail Procssing ┌─────────────────────────────────────────────────────────────────────────────┐ │ Caution │ ├─────────────────────────────────────────────────────────────────────────────┤ │We adopt new frame work after 2004/03/05. │ └─────────────────────────────────────────────────────────────────────────────┘ Firstly, parse and analyze each line in one message. An empty line is ignored. The buffer is clean up. After them, check if the command line is allowed in our context. For example, 1) if this command matches anonymous command such as "guide" or "subscribe", call command processor. Allowd list of commands are defined in $anonymous_command_mail_allowed_commands. 2) if this command matches a normal command which are allowd for a member, check other conditions based on rules of $command_mail_restrictions. Allowd list of commands are defined in $user_command_mail_allowed_commands. Command dispatcher checks the return path dependent on the command and the syntax, finally executes the command via FML::Command class. This process runs as normal user priviledge. "admin" command needs administrator priviledge. So an exception. If "admin" command is given, process user priviledged "admin" command and execute FML::Command::User::admin class. [12] In this user command class, checks the context by $admin_command_mail_restrictions to see that the current context has remote administrator priveledge. If enough priviledge is satisfied, execute FML::Command::Admin::COMMAND class via FML::Command again. FML::Command::Admin::COMMAND needs admin priviledge. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CUI (makefml/fml) If you use this program, you can have priveledge to login the mailing list server host and switch user to the user "fml". So please use CUI as you like. In this case, CUI calls FML::Command::Admin::COMMAND directly. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Command Extension: Command Mail ┌─────────────────────────────────────────────────────────────────────────────┐ │ Warning │ ├─────────────────────────────────────────────────────────────────────────────┤ │To make a new local command usable for all ML's on this host, you need to put│ │the module you wrote at │ │ │ │/usr/local/lib/fml/site_local/ │ │ │ │. If the command is allowed only for the specifiec ML (e.g. elena ML), put it│ │at the ML local library path │ │ │ │/var/spool/ml/elena/local/lib/ │ │ │ │where $ml_home_dir = /var/spool/ml/elena. │ └─────────────────────────────────────────────────────────────────────────────┘ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Create A New User Command Consider to make a new local user command "uja". Pick up a command at FML::Command::User, cut and paste it. Please put it at /usr/local/lib/fml/site_local/FML/Command/User/uja.pm To permit the use of it for all ML's, edit site_default_config.cf to add it into $commands_for_user to permit the user of "uja" command. user_command_mail_allowed_commands += uja It you allow the command only for the specific elena ML, edit /var/spool/ml/ elena/config.cf in the same way. user_command_mail_allowed_commands += uja ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Create A New Admin Command Such As "admin uja" In the same way described above, hack the module!:) but the module path differs. Put it at the FML::Command::Admin:: class. For example /usr/local/lib/fml/site_local/FML/Command/Admin/uja.pm Edit site_default_config.cf to add it into $user_command_mail_allowed_commands to permit the use of "admin uja" command. admin_command_mail_allowed_commands += uja ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CUI Command Extension: makefml/fml ┌─────────────────────────────────────────────────────────────────────────────┐ │ Warning │ ├─────────────────────────────────────────────────────────────────────────────┤ │To make a new local command usable for all ML's on this host, put the module │ │you wrote at │ │ │ │/usr/local/lib/fml/site_local/ │ │ │ │If you permit the command is used only for the specifiec ML (e.g. elena ML), │ │put it at the ML local library path │ │ │ │/var/spool/ml/elena/local/lib/ │ │ │ │. │ │ │ │In this section, we consider the former case. In both cases, the module codes│ │are same. │ └─────────────────────────────────────────────────────────────────────────────┘ Create a module "uja" and put it at /usr/local/lib/fml/site_local/FML/Command/Admin/uja.pm You do not need to edit .cf files. The existence of module file enables the command automatically in the CUI case since the usability of CUI implies administrator use. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ GUI Command Extension: CGI ┌─────────────────────────────────────────────────────────────────────────────┐ │ Warning │ ├─────────────────────────────────────────────────────────────────────────────┤ │You need another work to create a menu screen. │ │ │ │To make a new local command usable for all ML's on this host, put the module │ │you wrote at │ │ │ │/usr/local/lib/fml/site_local/ │ │ │ │If you permit the command is used only for the specifiec ML (e.g. elena ML), │ │put it at the ML local library path │ │ │ │/var/spool/ml/elena/local/lib/ │ │ │ │. │ │ │ │In this section, we consider the former case. In both cases, the module codes│ │are same. │ └─────────────────────────────────────────────────────────────────────────────┘ Craete a module "uja" and put it at /usr/local/lib/fml/site_local/FML/Command/Admin/uja.pm Edit site_default_config.cf to add it into $admin_cgi_allowed_commands to permit the use of "uja" command. admin_cgi_allowed_commands += uja ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ How Differ Coding Style Among fml4 And fml8 Consider localization of "help" command as an example of an fml command, which sends back help message to the sender. In the case of fml4, prepare myProcHelpFileSendBack() function and register it at %LocalProcedure hash to enable it. %LocalProcedure = ( 'help', 'myProcHelpFileSendBack', ); myProcHelpFileSendBack as follows: sub myProcHelpFileSendBack { local($proc, *Fld, *e, *misc) = @_; my $UJA_FILE = "/some/where/help"; &SendFile($Envelope{'Addr2Reply:'}, "UJA $ML_FN", $UJA_FILE); } In the case of fml8, the main code of help command locates at FML::Command::User::help class. This class is called by FML::Process::Command via AUTOLOAD of FML::Command. ┌─────────────────────────────────────────────────────────────────────────────┐ │ Warning │ ├─────────────────────────────────────────────────────────────────────────────┤ │All fml8 commands are implemented at either of FML::Command::User or │ │FML::Command::Admin classes. Both CUI (makefml, fml) and GUI (CGI) uses │ │FML::Command::Admin class. Instead command mail users both classes according │ │to the context. │ └─────────────────────────────────────────────────────────────────────────────┘ The real content of help command is process() method in FML::Command::User::help class. sub process { my ($self, $curproc, $optargs) = @_; my $config = $curproc->{ config }; my $charset = $config->{ report_mail_charset_ja }; my $help_file = $config->{ help_file }; # template substitution: kanji code, $varname expansion et. al. my $params = { src => $help_file, charset_out => $charset, }; my $help_template = $curproc->reply_message_prepare_template( $params ); if (-f $help_template) { $curproc->reply_message( { type => "text/plain; charset=$charset", path => $help_template, filename => "help", disposition => "help", }); } else { croak("no help file ($help_template)\n"); } } where $curproc is an object, which type is hash reference. It corresponds to %Envelope of fml4. It contains several references to objects for this process. For exmple, variable $config is an object holding configuration variables. All variables of fml4 are global. Instead variables of fml8 locates within configuration space accessed via $config object. reply_message_prepare_template() converts the message language and expands the arguments in the message templates. $curproc->reply_message() inserts the specified mesage string into the message queue of this process on memory. The error/log messages queued in on memory are aggergated to one message at the last of the current process. Mail::Delivery class handles the aggregation and send it. If needed, the aggregator handles text strings or multipart properly to build one message. This mechanism is same as Notify() of fml4 but the last aggregator which handles all at the last is different. FYI: commands such as "get" for the file manipulation uses the same message queuing mechanism. fml4's Notify() sends back immediately. Instead fml8's mechanism is queuing based always. This fml8 mechanism is different from fml4's Notify() fundamentally. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Chapter 38. Internal Of CGI Process Method FML::CGI class should implement the following methods: html_start() run_cgi_main() run_cgi_title() run_cgi_navigator() run_cgi_menu() run_cgi_command_help() run_cgi_options() html_end() where html_start() prints out the header of HTML such as DOCTYPE ... BODY, html_end() prints /BODY and /HTML. run_XXX methons prints the main content. run() of $curproc method drives html_start() run_cgi_XXX() html_end() sequentially. That is, the flow of CGI process is as follows: new() prepare() verify_request() run() html_start() run_cgi_XXX() html_end() finish() ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Screen Of CGI And The Method fml8 CGI script creates the screen: header space menu space bar 1 main bar 2 space menu space footer The bar 1 and 2 are called as navigation bar. html_start() generates header part(DOCTYPE ... BODY of HTML, NOT HTTP HEADER). html_end() generates footer part. Instead, BODY content generates 3 x 3 tables by using methods drived by run_cgi (). 9 sub methods called by run_cgi() generetes the following 9 pieces on the screen. nw north ne west center east sw south se ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Screen Of The Current CGI CGI screen generates 3 x 3 table structure. The following methods generates the corresponding part of the screen. run_cgi_main run_cgi_title run_cgi_navigator run_cgi_menu run_cgi_command_help run_cgi_options These methods use TABLE to create 3 x 3 matrix. These methods are defined in hash table. run_cgi() executes them sequentially. run_cgi_main() print nothing if nothing to do. In almost cases, print just "OK ..." message. If needed, it shows error messages. run_cgi_main() runs before all other methonds to print out the latest information. run_cgi_main() is adapter layer defined at FML::CGI::Menu::Admin. Each command is executed via this layer. In a few cases such as showing log, listing up addresses, run_cgi_menu() print out the data. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Screen And Trampolin Mechanism CGI print engine is moved to FML::Command:: class. However FML::Command:: does not contains all content of print engine. By object composition, some modules use methods FML::CGI:: provides. For example, subscribe command internal is as follows. FML::CGI::Admin::Main -> FML::Command::Admin::subscribe -> FML::CGI::Admin::User -> SCREEN The flow goes and back again like trampolin mechanism. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ MISC: Hard Coding Is Mandatory ? FML::CGI::Admin::User contains the relation between $comname and maps. It is hard-coded. But it cannnot be avoided. If we move the relation to configuration space, we need a lot of variables in it. It is better to use configuration variables for cusotomization, but ... ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CGI Implementation: Inheritance Among CGI Classes @ISA of config.cgi follows: FML::CGI::Menu FML::Process::CGI::Kernel FML::Process::CGI::Param In the case of thread.cgi, @ISA is FML::CGI::Thread FML::Process::CGI::Kernel FML::Process::CGI::Param .cgi specific codes locate at FML::CGI:: class layer. FML::Process::CGI::Kernel provides the main part of CGI process and CGI specific function run_cgi_XXX(). If needed, FML::CGI:: class overloads this layer. Currently, the following methods in FML::Process::CGI::Kernel are not used. run_cgi_log run_cgi_dummy run_cgi_date ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CGI Implementation: config.cgi @ISA of config.cgi is as follows: FML::CGI::Menu FML::Process::CGI::Kernel FML::Process::CGI::Param Let see processing of config.cgi below. config.cgi process object $curproc is a FML::Process::CGI::Kernel class. new() prepare() verify_request() run() finish() is sequentially called from FML::Process::CGI::Kernel class. run() is important. run() executes the following methods sequentially. $curproc->html_start(); (FML::CGI::Menu) $curproc->_drive_cgi_by_table(); (FML::Process::CGI::Kernel) $curproc->html_end(); (FML::CGI::Menu) _drive_cgi_by_table() prepares the screen. This function calls the main part of CGI. $curproc->_drive_cgi_by_table() calles the following run_XXX() methods. run_cgi_main (FML::CGI::Menu) calls cgi_execute_command (FML::Process::CGI::Kernel) to execute FML::Command::Admin::$COMMAND via FML::Command class. This is the main part of command execution via CGI but the screen creation is a role of another part. For example, consider subscribe an address via CGI. run_cgi_main() executes the real process of subscription. Instead run_cgi_menu() creates input menu. Former calls FML::Command::Admin::subscribe::process() method, latter calls FML::Command::Admin::subscribe::cgi_menu() method. There are several other run_cgi_XXX() methods. They are optional for screen creation. The following run_cgi_XXX() uses the default method. run_cgi_title FML::Process::CGI::Kernel (show title) run_cgi_options FML::Process::CGI::Kernel (show language selection) .cgi specific methods are as follows: run_cgi_navigator FML::CGI::Menu run_cgi_help FML::CGI::Menu run_cgi_command_help FML::CGI::Menu run_cgi_menu FML::CGI::Menu run_cgi_menu() executes FML::Command::Admin::COMMAND::cgi_menu() via cgi_execute_cgi_menu() method. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Chapter 39. Directory Q: How Recursively Sub Directory Can Be Created ? The structore holding the html-ized article is as follows: 200201/msg\d+.html One sub-directory by default. Consider directory listing. "ls" returns 1000 files soon, but 10000 files a little slowly. To accelerate listing, we should use sub-directory structure. For example, each sub-directory holds 1000 files. The structure such as "spool/sub/file" holds 10 ^6 ( million ) files and listing of it is fast. It must be enough to assume that 1 million articles for one ML. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Recipes 1. Where directory names are defined ? 1. Where directory names are defined ? There are default definitiions at /usr/local/etc/fml/defaults/$VERSION/ default_config.cf file. Each config.cf of each ML overloads them. Use fmlconf command to show the current value. % fmlconf $ml_name | grep _dir You can extract values from config object in a hook. $_xxx_hook = q{ my $config = $curproc->config(); my $xxxdir = $config->{ some_where_dir }; ... snip ... } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Chapter 40. Restrict Input Data fml8 checks the input by regular expression FML::Restriction class provides. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Overview: Checks Of Input Data Restriction For Article Posting Restrictions for article are ambiguous or too restrictive. In fact FML::Restriction class does not provide restriction rules for article posting. Instead FML::Filter filter system checks each line of content. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Restrictions For Command Mail FML::Process::Command class parses each line of the command mail and checks the input by regular expressions FML::Restriction::Command provides. If the check is passed, fml8 calls FML::Command::{User,Admin}::COMMAND at the next step. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CGI CGI programs can receive the input from HTTP via only safe_param_XXX() method. It is expected that safe_param_*() and try_cgi_*() returns the safe value. These safe_param_XXX() functions checks the input by regular expressions FML::Restriction::CGI provides (FML::Restriction::CGI inherits FML::Restriction::Base). ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ makefml / fml CUI runs on the shell. It means he/she who runs CUI has priviledge to log in the mailing list server. So it does not check the input. Each module checks the input independetly in that case though no checks by FML::Restriction at the entrance. For example, "adduser" module checks whether the input address is valid or not even in the case of CUI. These restrictions are dependent command specific modules. These are applied even in the case of CUI. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ FML::Restriction Class ACLs for the input data and commands are found at FML::Restriction class. For example, CGI modules use FML::Restriction::CGI class to check if the input data matches the proper regular expression. Though FML::Restriction inherits FML::Restriction::Base class, fundamentally each module should use FML::Restriction as object composition. For example, use in the following way: use FML::Restriction::CGI; $safe = new FML::Restriction::CGI; my $allowed_regexp = $safe->param_regexp(); if ($value =~ /^$allowed_regexp{$key}$) { ... ok, do something ... ;} ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ How CGI Restricts The Input CGI checks the input data by using FML::Restriction::CGI class. The input should be restricted by FML::Restriction class. We should not use param() method provided by perl's CGI class. Instead use safe_param_xxx() method always to get value. The following use may be allowed for my $dirty_buf (param()) { ... check ... } but we should not use raw param() call. param($dirtty_buf) Instead, use safe_param_key(). for my $key (param()) { ... check ... if (key eq $key) { value = safe_param_key() } } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Discussion: FML::Restriction Is Too Restrictive ? FML::Restriction class allows a subset of RFC defined expression. RRC definition is too large. It is too difficult to implement it ;-) We restrict the expression a little. FML::Restriction::Command may be more granular but more granular version is not implemented. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Chapter 41. User Authentication User authentication is provided by methods of FML::Credential class. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Discussion: FML::Credential Implementation Case Sensitive / Case Insensitive For the user@domain address, we handle user part as case sensitively and domain as case insensitively. Is it better to prepare the option that handling of user part is insensitive? (Yes, I think so.) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Chapter 42. Hook Overview Hooks are required to resolve complicated problems or for compilcated customization. But there are several problems in implemantation. One problem is naming convension. $START_HOOK of fml4 is ambiguous. It means the location in process but not clarify where in which process. So, fml8 hook naming convension has role and function in it. $ROLE_FUNCTION_start_hook $ROLE_FUNCTION_end_hook There is no common hook among processes. Each process has each hook. In other words, there is no common hook. You need to define plural hooks for different processes even if the hook is same content. $distribute_XXX_start_hook = q{ ... }; $YYY_XXX_start_hook = $distribute_XXX_start_hook; Coding style of hooks are expected not too restrictive since perl beginners may code it. fml8 modules have use strict; definition but not effective in evalauating hooks. In evaluating a hook, fml8 evaluate it as no strict; HOOK CONTENT to disable the strict check. Function scope differs among fml4 and fml8. In fml4 all functions are global. Instead in fml8 functions are methods, which is not called anytime anywhere. We should provide hooks when we can see $curproc. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Hook Naming Convension Hook standard form is ROLE_METHOD_start_hook ROLE_METHOD_end_hook The role is "ROLE" part of $use_ROLE_function (e.g. $use_article_post_function) in configuration variables. This hook directory corresponds to some variables in configuration. More granular hooks do not match this rule. For example, the main part of fmlconf command, run() method, provide the following hooks: fmlconf_run_start_hook fmlconf_run_end_hook The actual code calling hooks as follows: sub run { my ($curproc, $args) = @_; my $config = $curproc->{ config }; my $eval = $config->get_hook( 'fmlconf_run_start_hook' ); if ($eval) { eval qq{ $eval; }; print STDERR $@ if $@; } $curproc->_fmlconf($args); $eval = $config->get_hook( 'fmlconf_run_end_hook' ); if ($eval) { eval qq{ $eval; }; print STDERR $@ if $@; } } This case is fundamental. More granular hooks must be needed. The naming convension may differ from this convension. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Recipes ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Chapter 43. Virtual Domain 2003/10: We enhanced fml8 to handle virtual domains as same way as default domain. It is difficult to handle virtual domains and the default domain in the same way. One proper enhancement is using "user@domain" form for the ML name as an argument of commands. For example, for a virtual domain, use makefml like this % makefml newml mlname@virtualdomain The following two syntaxes are acceptable for the default domain. % makefml newml mlname@defaultdomain % makefml newml mlname Fml treats these properly as could as possible. But fml needs some hints such as ml home directory information for each domain. You need to prepare /usr/ local/etc/fml/ml_home_prefix file for a hint on mappping between domain and directory. This file name is defined as $ml_home_prefix_maps (formerly $virtual_maps) in main.cf. $virtual_maps is obsolete but effective now for compatibility. To handle $ml_home_prefix_maps, you can use "makefml newdomain" and "makefml rmdomain". ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Overview: virtual domain handling in fml8 It is easy in use. For the first time to use a virtual domain, run "newdomain" command to add {domain => directory} relation to ml_home_prefix_maps (precisely primary_ml_home_prefix_map). After that, you can use "user@domain" form in makefml arguments in handling virtual domains. makefml newml ML@virtualdomain makefml add ML@virtualdomain address makefml bye ML@virtualdomain address Instead, for the default domain, definitions in ml_home_prefix_maps is not needed and either of user and user@domain is accpetable. When you use CGI, you need not to use user@domain syntax since config.cgi knows the domain name the cgi handles. http://lists/~fml/cgi-bin/fml/$domain/admin/config.cgi ┌─────────────────────────────────────────────────────────────────────────────┐ │ Warning │ ├─────────────────────────────────────────────────────────────────────────────┤ │The domain name is hard-coded within config.cgi since makefml injects the │ │domain name in creating config.cgi when "makefml newml" runs. That is, │ │"config.cgi" does not resolve its domain by the URL. │ └─────────────────────────────────────────────────────────────────────────────┘ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Case study: movement ? *** SORRY, NOT YET WRITTEN ***. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Chapter 44. Errormail Analyzer (libexec/error) fml8 error (/usr/local/libexec/fml/error) program corresponds to mead (/usr/ local/fml/libexec/mead) of fml4 Set "$use_error_mail_analyzer_function = yes" to enable error mail analyzer function. By default, $use_error_mail_analyzer_function is "yes". That is, fml8 error analyzer is enabled by default but fml4 not. This default behaviour differs from fml4. In fact, typical functions of fml8 are enabled by default. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Overview In creating a ML, fml8 sets up that $ml-admin address (address error messages returned to) calls /usr/local/libexec/fml/error. /usr/local/libexec/fml/error reads a message, analyzes it and creates a chain of Mail::Message objects on memory. Mail::Bounce class analyzes the detail of error based on the objects. Mail::Bounce analylzes which MTA generates the error, which address generates the error, and the error reason. The result is cached at $error_mail_analyzer_cache_dir directory. After some time interval, $error_mail_analyzer_function analyzes the cache data to determine if an address is effective or not. If some address is determined to be removed, fml8 removes it from member/recipient list. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Algorithm Of Error Detection Functions of $error_mail_analyzer_function_select_list are available to determine error or not. Currently "simple_count histgram" and "histgram" algorithm are supported. "histgram" is used by default. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Algorithm: simple_count Count up the number of error messages from an address and determine whether the address is effective or not. This logic depends on just the total number of errors. If the traffic of ML is high, even a little configuration error of recipients caueses removal of the address soon. This is the main problem of this logic. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Algorithm: histgram Count up the number of continuous days that error messages returned. If the number oversomes the threshold, fml8 removes the corresponding address. The threshold is 14 days by default. That implies continuous errors in 14 days. This logic assumes that the traffic of an ML is at least one message per day. In other words, this logic requires the continuous error. So, little configuration error in the side of recipient has no effect. fml8 uses this algorithm by default. Caution: If the traffic of the ML is too little under at least one message per day, this algorithm does not work. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Cache Of Error Messages Data Error messages data is cached at $error_mail_analyzer_cache_dir directory. IO to cache uses Tie::JournaledDir class via FML::Error::Cache. FML::Error::Cache is a front end (adapter layer) for Tie::JournaledDir class. All IO should be done via methods provided by FML::Error::Cache. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Forward Error Messages You can specify the location the error message is forwarded to as $maintainer_recipient_maps variable. Undefined by default. Error messages are logged at a log file but not forwarded. If enabled, this function forwards the error messages. Just forward it as mime/ multipart which contains one messages/rfc822 part. FUTURE PLAN: we forward error messages with the analyzed data. REFERENCE: fml-devel ML 451 around ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Chapter 45. IO Interface And Operations We need IO abstraction layer for porting and extension. See Vnode/VFS interface (vnode(9)) on IO abstraction. struct vnode { ... voff_t v_size; /* size of file */ int v_numoutput; /* num pending writes */ long v_writecount; /* ref count of writers */ ... int (**v_op)(void *); /* vnode ops vector */ ... void *v_data; /* private data for fs */ }; vop_open(), vop_read(), vop_getattr(), ... are defined over v_op. **v_op (vnode operation vector) corresponds to a method of object oriented programming. fml8 provides IO::Adapter class as IO abstraction layer. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Fundamentals Of IO::Adapter IO::Adapter is most fundamental in fml8 architecture. It is well considered and implemented. It provides enough primitive methods. IO::Adapter class abstracts KEY => VALUE or KEY => [ VALUE, VALUE2, VALUE3 ] type data structure. It is similar to RDBMS theory like this. KEY1 VALUE1-1 "" "" KEY2 VALUE2-1 VALUE2-2 VALUE2-3 KEY3 VALUE3-1 VALUE3-2 VALUE3-3 KEY4 VALUE4-1 VALUE4-2 VALUE4-3 To maintain address list, least fundamental methods of IO::Adapter are open() close() and IO operations to the object add(KEY, ARGV) (ARGV is class dependent) delete(KEY) find(KEY or REGEXP) get_next_key() methods. At least, enough to write user management codes. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Methods / Operation Vector Mentioned above, the fundamental methods of IO::Adapter are as follows: open() close() add(KEY, ARGV) (ARGV = class dependent) delete(KEY) find(KEY or REGEXP) get_next_key() Other than these methods, new() as a constructor and destructor() are needed. The constructor is new() methond. For example, use like this; $obj = new IO::Adapter MAP; The argument is a map which calls map dependent constructor. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ open() For a file, call open(2), for RDBMS, connect to the specified SQL server. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ close() Reverse of open(). ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ add(KEY, ARGV) add KEY (primary key) or KEY and the associated VALUE into the object. ARGV is class dependent. We assume an object is composed of a form. It is similar to RDBMS. The primary key is a mail address. This assumption is correct in the case of mailing list driver. This is basic data structure. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ delete(KEY) Delete KEY and the associated VALUE. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ find(KEY) / find(REGEXP) Search data corresponding with the primary key within an object. The target is specified as regular expression. Regular expression search is useful. The return value is STR of ARRAY_REF (KEY => [ VALUE, VALUE2, VALUE3 ]). ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ get_next_key() Return the list of primary keys like this: while ($obj->get_next_key()) { ... } This operation corresponds to FIRST_KEY() and NEXT_KEY() of perl hash. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Discussion What ARRAY_REF return ? What expected in using ARRAY_REF as the return value ? A list of PRIMARY KEY ? ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ How To Get All Primary Keys ? We need to call get_next_keys() again and again to retrieve all keys. It may be useful to implement special method to return a list of keys but it is not implemented. get_primary_keys() ? find('*', { all => 1 }) is used for this purpose. It is of no use to implement specific method for this. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ HASH_REF As Return Value ? What expected ? RETURN VALUE = { KEY_1 => VALUE_1, KEY_2 => VALUE_2, } If a mail address has several attributes, this method is useful. For example, consider digest delivery: ADDRESS => { internal => 3 hours, compression => no, format => mime/multipart, }; Abstracted Cache IO layer is this type such as: FML::Error -> FML::Error::Cache -> Tie::JournaledDir But ... dependent on Tie::* hmm .. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Chapter 46. Lock Synchronization among processes uses lock. fml8 provides flock(2) or lockf(2) based lock mechanism. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Overview: Lock After 2003/03, fml8 provides more granular not giant lock. Each resource defines each lock channel name. For example, Mail::Delivery related class accesses the member list. It needs several locks. Mail::Delivery::SMTP needs lock of member list. FML::Send and FML::Process::Delivery locks member list access in callling Mail::Delivery::SMTP. Instead Mail::Delivery::Queue just sees the mail queue. The function can access the queue concurrently, also. So this module does not need lock. Generally speaking, modules using maps require lock. For example, FML/Command/ UserControl.pm and FML/Command/Auth.pm needs write lock, but FML/Credential.pm needs only read lock. It is useful if fml8 provides reader writer lock. But it is not implemented. Currently we attension we use short critical region. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ TODO Mutex lock in calling *_maps. READER WRITER LOCK in calling IO::Adapter. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Chapter 47. Database Related Modules Overview ML driver needs to hold some data on mail. Some data exixsts persistently but some data with expiration (data is discarded after some interval). An example of permisistent data is thread database. The latter case, an exapmle of non persistent data, is message-id cache. The thread database also has message-id cache in it, which is a sub-set of all message-id set of incoming messages. We handle these two data separately. We should handle these data in integrated way. module A ---| A |--- persistent database module B ---| da | module C ---| pt | modlue D ---| er |--- cache with expiration An example of this persistent DB, thread DB, is Mail::Message::DB class. Examples of cache database are Tie::JournaledDir and FML::Cache::Ring classes. It is better to use RDBMS for important persistent data such as address list. This chapter describes persistent data handling only for fml8 internal use. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Persistent Data Use Handling of persistent data is important. We should consider use of DBMS [13] for important data. This chapter describes only fml8 internal use. fml8 provides two type of cache databases. The type is time saving or space saving. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Tie::JournaledFile Class This class appends data into a file. Tie::JournaledFile class provides this function. This class is append only. It is similar to LFS (Log Structured File System). Operation to extract a value is to get the latest (last appended) value. That is, the last match. In other words, data cache logs all data to enable back track. We cannot restrict the maximum size of this cache. This class holds data within some period without size limitation. We control cache expiration by time. To get the following structure as a result, you can use get_all_values_as_hash_ref() method. key => [ log1 (line A of file 1), log2 (line B of file 2), log2 (line C of file 3), ] ┌─────────────────────────────────────────────────────────────────────────────┐ │ Warning │ ├─────────────────────────────────────────────────────────────────────────────┤ │Search algorithm is either of first match or last match. The last match by │ │default since the last appended data is latest. │ └─────────────────────────────────────────────────────────────────────────────┘ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ FML::Cache::Ring Class FML::Cache::Ring holds data with size limit but without time limitation. It is suitable for debug since the debug data is expected not to eat disk. This class holds data in files in a directory such as $ml_home_dir/var/db/. For example, files named as db/1 .. db/100 are created. These files are used repeatedly. ┌─────────────────────────────────────────────────────────────────────────────┐ │ Warning │ ├─────────────────────────────────────────────────────────────────────────────┤ │RingBuffer class is integrated into FML::Cache::Ring class. FML::Cache::Ring │ │is derived from File::CacheDir class. │ └─────────────────────────────────────────────────────────────────────────────┘ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Chapter 48. Database Management System This chapter describes how to handle persistent data. You should use DBMS (DataBase Management System) for that data. See Chapter 47 on the internal use database. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Overview Communication with DBMS (database management system) via IO::Adapter class. This class provides fundamental functions such as insersion and deletion of data. If more complex operation is needed, the preprocessing module calling IO::Adapter should handle it. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Chapter 49. Convert Another ML System To fml8 Implementation: fml4 To fml8 Case 1: /var/spool/ml/elena/ From fml4 To fml8 This conversion does the following steps in fact. 1) install fml8 firstly. In this case, add /var/spool/ml/etc/mail/aliases into $alias_maps of postfix main.cf. /var/spool/ml/etc/mail/aliases may be empty. 2) run "makefml --force newml elena" to create several files fml8 needs. 3) convert address lists in /var/spool/ml/elena to fml8 style. 3-1) IO::Adapter ignores a line beginning with '^#' as a comment. We should handle carefully it since "actives" file contains ^# lines as "off" address. 3-2) s=skip (off) options is ignored. It handles as "on". 3-3) m=... (digest) options is ignored. Also, "# address" is "off" in the case of fml4 but ignored in the case of fml8. We should warn it ? 4) remove the corresponding entry of alias file (/var/spool/ml/etc/fml/aliases) of fml4 and rebuild .db. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Case 2: Convert The Whole /var/spool/ml/ From fml4 To fml8 Apply case 1 for all ML's. If we can stop all ML's, it is easy to remove /var/spool/ml/etc/fml/aliases of fml4 firstly and apply case 1 steps. Please stop MTA in migration. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Discussion: Use Half And Half Of fml4 And fml8 Softwares. (X-Sequence: fml-devel 389) How in half and half case. For example, site_init.ph or config.ph of fml4 follows [fml4] push(@ACTIVE_LIST,"$DIR/recipients") if( -f "$DIR/recipients" ) ; instead in the case of fml8 site_default_config.cf or config.cf follows: [fml8] html_archive_dir = $ml_home_dir/htdocs VIII. Modules This part descripbes how to use most important modules. Table of Contents 50. IO Abstraction Layer (IO::Adapter Class) 51. Mail::Message Module 52. Language Dependent Functions 53. Mail::Message::Encode Class 54. Execise: Create A New Program ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Chapter 50. IO Abstraction Layer (IO::Adapter Class) IO::Adapter Overview All IO of fml8 should use IO::Adapter class like vfs/vnode framework. For example, read/write member list, add/remove a user. The usage is like this: use IO::Adapter; $obj = new IO::Adapter $map, $map_params; $obj->open || croak("cannot open $map"); while ($x = $obj->get_next_key()) { ... } $obj->close; $map is map:identifier. file: can be omitted. Currently available maps follow: file:/var/spool/ml/elena/recipients unix.group:root nis.group:root mysql:id postgresql:id ldap:id "file:" map is a normal file (text file). "unix.group:root" map is to read root entry in /etc/group file. "nis.group:root" map is to read root entry in NIS (YP). "mysql:id" map implies the use of MySQL. Parameters for MySQL access is defined in "mysql:id" entry. These paraemeters should be specified before calling "new IO::Adapter". ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ IO::Adapter Methods Official methods IO::Adapter provides currently follow: new() open() close() get_next_key() add(KEY) delete(KEY) getpos() setpos(NUM) eof() touch() find(REGEXP, $args) KEY is a primary key to handle database access. In almost cases, the primary key is a mail address. REGEXP is a regular expression (regexp), this is usually also a mail address. Unification of all types of IO needs that we should implement least methods. The currently implemented methods are selected by test and our operations. If could, we refer SQL IO more than file IO as an abstraction base model of IO::Adapter. It introduces difference between fml4 and fml8 but it is mandatory for further abstraction. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Argument Type Of Methods The argument needs nothing, STR or ARRAY_REF as the argument and the return value is STR. get_next_key() is typical as the no argument case. This method is used to list up the content of files or retrieve the specific address in the file. In other case, the return value may be a pair of strings. KEY_STR => [ VALUE_STR_1 VALUE_STR_2 VALUE_STR_3 ] This is used as the return value to represent ARRAY_REF. For example, "actives" file of fml4 consists of lines which have plural space separeted entries. So it can be representated as a type of array. rudo@nuinui.net s=skip m=xxx.yyy.z # commnet rudo@nuinui.net => [ s=skip m=xxx.yyy.z # comment ] If retrieval value could be represented as ARRAY_REF, argument of store operations alsot needs ARRAY_REF. It is summarized as follows. The argument is one of "nothing", "STR" or ARRAY_REF. The return value is either of STR of ARRAY_REF (array reference). argument return value --------------------------------------- none => STR STR => STR none => [STR, STR, ... ] STR => [STR, STR, ... ] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ File Map "file:/some/where/file/name" or file name "/some/where/file/name" map is abstraction of IO to/from a text file. The format of text file is space separated. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Unixgroup Map Abstraction of /etc/group. IO is read only. For example, the access to wheel:*:0:root,rudo,kenken in /etc/group is "unixgroup:wheel" map in IO::Adapter. $obj = new IO::Adapter "unixgroup:wheel"; If you call get_next_key() method for this object, you will get the member of wheel group sequentially. In other words the wheel group is regarded as the following file by IO::Adapter. root rudo kenken ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Nis Map It is same as one of /etc/group but the data is retrieved from NIS/YP. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ MySQL Map For easy maintenance, it is better to write all mysql configurations in one file. For example, it is good that we have only to write SQL configurations in config.cf. But we identify plural mysql conditions. So, we use the tag [mysql:members] to declare one region between a tag to the next tag or =cut. It is similar to .ini file format used on Microsoft OS. We use the tags like this: config.cf example member_maps = mysql:members recipient_maps = mysql:recipients [mysql:members] sql_server = localhost sql_user = fml sql_password = uja sql_database = fml sql_table = ml sql_find = select * from ... ... In calling IO::Adapter, use new IO::Adapter "mysql:members", $config; where $config is a hash reference holding some paremeters like this: $config => { [mysql:members] => { sql_sever => localhost ... } } FML::Config prepares this $config by reading .cf files. Hence, we usually use FML::Config object as an argument of IO::Adapter::new() method. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Discussion: How To Write SQL Statements In config.cf ? (fml-devel 204) How about lexical scope ? The .cf files cannot contain all variables since lexical scope variables exist. We use &varname syntax for such lexical scope variables. For example, use different member and recipient maps. In SQL statements, the difference is a flag (fml_recipient) in a table. For example, consider the case that "where" statement has different value but it is determined lexically in calling MySQL. member_maps = mysql:members recipient_maps = mysql:recipients [mysql:members] sql_server = localhost sql_user = fml sql_password = uja sql_database = fml sql_table = ml sql_get_next_key = select fml_address from $sql_table where fml_ml = '$ml_name' and fml_domain = '$ml_domain' sql_getline = select * from $sql_table where fml_ml = '$ml_name' and fml_domain = '$ml_domain' sql_add = insert into $sql_table values ('$ml_name', '$ml_domain', '&address', 1, 1) sql_delete = delete from $sql_table where fml_ml = '$ml_name' and fml_domain = '$ml_domain' and fml_address = '&address' sql_find = select * from $sql_table where fml_ml = '$ml_name' and fml_domain = '$ml_domain' and fml_address like '®exp' [mysql:recipients] sql_server = localhost sql_user = fml sql_password = uja sql_database = fml sql_table = ml sql_get_next_key = select fml_address from $sql_table where fml_ml = '$ml_name' and fml_domain = '$ml_domain' and fml_recipient = '1' sql_getline = select * from $sql_table where fml_ml = '$ml_name' and fml_domain = '$ml_domain' and fml_recipient = '1' sql_add = update ml set recipient = 1 where fml_ml = '$ml_name' and fml_domain = '$ml_domain' and fml_address = '&address' sql_delete = update ml set recipient = 0 where fml_ml = '$ml_name' and fml_domain = '$ml_domain' and fml_address = '&address' sql_find = select * from $sql_table where fml_ml = '$ml_name' and fml_domain = '$ml_domain' and fml_recipient = '1' and fml_address like '®exp' ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Chapter 51. Mail::Message Module Mail::Message Overview Mail::Message object provides several methods to analyze a message and manipulate messages or parts of a message. Precisely speaking, this module analyzes the specified mail message and build a chain of Mail::Message objects. If not multipart header -> body else if multipart header -> preamble -> part1 -> part2 -> ... -> trailor The link between objects is double link list. Mail::Message class provides several methods to manipulate these structures. Each part of this chain is a Mail::Message object. In other words, one mail message consits of a chain of plural Mail::Message objects in fml8 internal. For example, "header" is a Mail::Message, which type is text/rfc822-headers and the data is stored as Mail::Header object. Instead "part1" is a Mail::Message object, which type is text/plain and the data is reference to the message string. References: Mail::Message module manual. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Mail::Message Module: Analyze parse() analyzes the file. The argument is the file name or the file handle for the file which should be specified at the argument. data_type_list() returns information of the chain. The return value is array reference. For example, MIME/multipart consists of the following objects. type[ 1]: text/rfc822-headers | multipart/mixed type[ 2]: multipart/mixed | multipart/mixed type[ 3]: multipart.preamble | multipart/mixed type[ 4]: multipart.delimiter | multipart/mixed type[ 5]: text/plain | multipart/mixed type[ 6]: multipart.delimiter | multipart/mixed type[ 7]: image/gif | multipart/mixed type[ 8]: multipart.close-delimiter | multipart/mixed type[ 9]: text/plain | multipart/mixed The center row is the object type, the right one is the mime type of the whole message (content-type in the mail header). ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Mail::Message Module: Create A New Object new() method is used to create a new object chain. The following MIME/multipart specific methdos exist. build_mime_multipart_chain($args) parse_and_build_mime_multipart_chain($args) build_mime_header($args) These methods are used internally now. So these will become private methods in the furure. Please do not use these methods. To create a new MIME/mulitpart message, use Mail::Message::Compose. It is MIME::Lite class in fact :-) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Mail::Message Module: Header Manipulations dup_header() method duplicates only header part of a chain and left the body part as it is. The new chain has different head (header object) but others begining from the second part is same as the original chain. |<--------------- mail body -------------> header0 ----> part1 -> part2 -> ... A | dup_header0 --- whole_message_header() returns the header object of the chain. The return value is a Mail::Message object not string. header_data_type() returns the type of the whole message as string. It tells whether this message is text or multipart. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Mail::Message Module: Manipulate Messabe Body Consider the following object chain. If not multipart header -> body else if multipart header -> preamble -> part1 -> part2 -> ... -> trailor header_data_type() return the type of the whole type. It is known from Content-Type: in the whole message header. whole_message_body() returns body or part1 if multipart. whole_message_body_head() is same. find_first_plaintext_message($args) return the first text/plain type object in the chain. This is useful in filter codes since filter system checks the first text field in a lot of cases. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Mail::Message Module: Search find() searches the specified type of Mail::Message in the object chain and returns the first matched object. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Mail::Message Module: Print print() method is usual print() function. Usually specify the file descriptor as an argument. print() has the concept "mode" to specify CRLF or LF. use set_print_mode(mode) and reset_print_mode() to set the mode. By default, mode is raw. Specify smtp mode in using print() within SMTP codes. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Mail::Message Module: Utility Functions Size size() returns the size of the object not the whole message size. is_empty() tells the object data is empty or not. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ General Information envelope_sender() returns the envelope sender as string. data_type() returns the type of the object (a part of an object chain) not the whole message type (Content-Type: in the whole message header). encoding_mechanism() returns the encoding mechanism of the object (a part of an object chain) as string. This is not of the whole message encoding mechanism. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Mail::Message Internals num_paragraph() returns the number of paragraphs in the data of the object. nth_paragraph(N) returns N-th paragrah as the string. Caution that N starts from 1 not 0. header() returns the header part of a multipart block (header part of an object). data() returns the data part (data part of an object). Respectively, alias of message_fields($size) and message_text($size). ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ References Mail::Message manual ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Chapter 52. Language Dependent Functions fml8 needs language dependent functions internally. Especially, JIS to/from EUC-JP Janapese code conversion is used anywhere since Japanese mail messages are written in JIS code but programs are easy to use strings in EUC-JP. See message internationalization for the language dependence handling in messages. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Something::Language:: Class Language dependent module locates at Something::Language. For example, there are FML::Language::Japanese::String Mail::Bounce::Language::Japanese , The former provides Japanese dependent string functions. The latter provides Japanese dependent error mail analyzer functions. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Chapter 53. Mail::Message::Encode Class [References] fml-help ML's Count: 02012, 02013, 02016. [Usage] use Mail::Message::Encode; my $encode = new Mail::Message::Encode; my $str_euc = $encode->convert( $s, 'euc-jp' ); my $str_euc = $encode->convert( $s, 'euc-jp', 'iso-2022-jp' ); my $encode = new Mail::Message::Encode; my $status = $encode->convert_str_ref( \$s, 'euc-jp' ); my $status = $encode->convert_str_ref( \$s, 'euc-jp', 'jis' ); my $fp = sub { ... }; $encode->run_in_chcode( $fp, $oout, $in ); * If you want to use 4.0 compatible functions, ues Mail::Message::Encode qw(STR2EUC); my $euc_s = STR2EUC( $s ); ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Mail::Message::Encode Specification The main code is within _convert_str_ref() method. sub convert # if the argument is STR. { my ($self, $str, $out_code, $in_code) = @_; _convert_str_ref(\$str, $out, $in); return $str; } sub convert_str_ref # if the argument is STR_REF. { my ($self, $str, $out, $in) = @_; _convert_str_ref($str, $out, $in); } sub _convert_str_ref # if the argument is STR_REF. { my ($str, $out, $in) = @_; # 1. speculate charset if $in unspecified -> speculat -> fail -> return 0 # 2. try conversion if ($in resolved or or $in specified in @_) { converted to $out charset (use jcode, Jcode, use Encode if perl version > 5.8). conversion return 1 ; # success } else { # principle of least surprise ? nothing todo ; return $str; } return 0 ; # failed } sub base64 {} sub quoted_printable {} is implemented for convenience. $x = $encode->base64($s); For backward compatibility, STR2XXX() functoins are prepared, too. STR2EUC( $str, [$icode] ) STR2JIS( $str, [$icode] ) STR2SJIS( $str, [$icode] ) These wraps convert_str_ref(). ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ run_in_chcode() In language dependent processes, convert the charset to machine friendly one, process something and back it to the original chaset each time. This step is widely used. So it is convenient to prepare a function to pack these steps into one function. run_in_chcode example: sub run_in_chcode { my ($self, $proc, $s, $out_code, $in_code) = @_; my $conv_status = convert_str_ref($s, $EUC_JP, $in_code); my $proc_status = &$proc($s, @_); convert_str_ref($s, $out_code, $EUC_JP) if $conv_status && $out_code; return wantarray ? ($conv_status, $proc_status): $conv_status; } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Chapter 54. Execise: Create A New Program Consider creation of a simple scheduler listing tool in the fml8 framework. Here the program name is "fmlsch" and the cgi is "fmlsch.cgi". ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Case Study: Create A fmlsch Step 1: Add fmlsch Into Installer Configuration Prepare fml/bin/fmlsch.in, add fmlsch into $bin_programs in fml/etc/ install.cf.in. Run configure to re-create fml/etc/install.cf. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Step 2: Build A Module Write fml/lib/FML/Demo/Calendar.pm as the main library of fmlsch. Import other libraries if needed. For fmlsch we import HTML-CalendarMonthSimple-1.02.tar.gz from CPAN. See cpan/ directory. Also, install Date-Calc if your system has not it. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Step 3: Modify FML::Process:: Class FML::Demo::Calendar works mainly. We need to prepare FML::Process class for fml8 bootloader to call FML::Demo::Calendar. Firstly, write mandatory methods for fmlsch process in fml/lib/FML/Process/ Calender.pm. You need to create this file. Secondly, set up boot loader configuration. In the case of fmlsch, the bootloader loads FML::Process::Calender. Define it in fml/etc/modules. Set up fml/etc/command_line_options properly. This "command_line_options" file has a map between a command and the command line options parsed by Getopt::Long(). Create FML::Process::Calender module by copy-and-pasting other FML::Process:: modules :-) Though fmlsch has only to contain least functions, you need to write FML::Process::Calender::run() method. For undefined methods, fml loads FML::Process::Kernel functions (inheritence). ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Case Study: fmlsch.cgi The way of hacking is similar to fmlsch. The differnce is the target to modify, which is FML::CGI:: class. FML::CGI::Calender is a sub-class of FML::Process::CGI. If undefined method is called, fml loads it from FML::Process::CGI or FML::Process::Kernel. FML::Process::CGI uses CGI.pm to create a http header et.al. If FML::Process::CGI functions are not enough, FML::CGI class module should support the lack. IX. Apendixes Table of Contents Glossary (function and variable names convention) A. Struct curproc (Object In Fact) Glossary (function and variable names convention) fml4 fml4 series fml8 fml8 series fml-devel current development version on the way to fml8 in the future. same as fml8 now. curproc abbrebiation of "current process". Typical abbrebiation form used in UNIX kernel. PCB Process Control Block. Typical abbrebiation form used in UNIX kernel. config configuration. conf configuration. arg / args argument / arguments. fh file handle. dh directory handle. fp function pointer == code reference of perl 5. _foobar keyword begining with _ is used for internal function or variable. private in other words. rfoobar The first "r" implies "reference". This called hangalian form but we use it very little in fml8. STR string. Japanese character set name JIS, SJIS, EUC ... 2 the same pronounciation as "to". STR2EUC (== STRing to EUC) use String qw(STR2EUC); $euc_string = STR2EUC($string); 4 the same pronounciation as "for". command mail a mail which message body includes commands for fml. By sending the command mail to some address, a user can make fml8 action something, such as subscribe, file retrieve, unsubscribe et.al, The address is typically $ml-ctl@$domain for $ml@$domain ML. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Appendix A. Struct curproc (Object In Fact) curproc Object Example of FML::Process::Distribute object. __parent_args => HASH { ARGV => ARRAY ___shared_memory___ => HASH argv => ARRAY cf_list => ARRAY curproc => FML::Process::Distribute fml_version main_cf => HASH module_info => HASH myname need_ml_name options => HASH program_fullname program_name } __print_style => SCALAR __start_time => SCALAR article => HASH { body => Mail::Message header => FML::Header message => Mail::Message } config => FML::Config credential => FML::Credential incoming_message => HASH { body => Mail::Message header => FML::Header message => Mail::Message } log_message_queue => FML::Log::Print::Simple main_cf => HASH { _hints => HASH config_dir debug default_command_line_option_config default_config_cf default_config_dir default_cui_menu default_domain default_gui_menu default_ml_home_prefix default_module_config default_paths_cf domain_default_config domain_default_config_cf exec_prefix executable_prefix fml_group fml_owner fml_version group_writable_config_dir lib_dir libexec_dir local_lib_dir ml_home_prefix_maps prefix prefix_dir primary_ml_home_prefix_map share_dir site_default_config_cf virtual_maps } pcb => FML::PCB scheduler => FML::Process::Scheduler ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ PCB Category List PCB category list, which contains module and function relation. module function category <-- (get value) --> (set value) -------------------------------------------------------------------------------- State command_context_get_ml_name <-- process_command State command_context_get_admin_auth <-- process_command State command_context_get_normal_stop <-- process_command State command_context_get_need_confirm <-- process_command State command_context_get_stop_process <-- process_command State command_context_get_admin_password <-- process_command State command_context_get_try_admin_auth_request <-- process_command State command_context_set_ml_name --> process_command State command_context_set_admin_auth --> process_command State command_context_set_normal_stop --> process_command State command_context_set_need_confirm --> process_command State command_context_set_stop_process --> process_command State command_context_set_admin_password --> process_command State command_context_set_try_admin_auth_request --> process_command State command_context_reset_try_admin_auth_request --> process_command State article_get_id <-- article_message State article_set_id --> article_message Utils incoming_message_get_cache_file_path <-- incoming_message Utils incoming_message_set_cache_file_path --> incoming_message State filter_state_get_error <-- filter_state State filter_state_get_tempfail_request <-- filter_state State filter_state_spam_checker_get_error <-- filter_state State filter_state_virus_checker_get_error <-- filter_state State filter_state_set_error --> filter_state State filter_state_set_tempfail_request --> filter_state State filter_state_spam_checker_set_error --> filter_state State filter_state_virus_checker_set_error --> filter_state State smtp_server_state_get_error <-- smtp_transaction State smtp_server_state_set_error --> smtp_transaction Utils incoming_message_get_current_queue <-- incoming_smtp_transaction Utils incoming_message_set_current_queue --> incoming_smtp_transaction Fake _get_emul_domain <-- faker Fake _get_emul_ml_list <-- faker Fake _get_emul_user_list <-- faker Fake _set_emul_domain --> faker Fake _set_emul_ml_list --> faker Fake _set_emul_user_list --> faker Error finish <-- error Error run --> error Kernel sysflow_finalize_stderr_channel <-- stderr Kernel sysflow_finalize_stderr_channel <-- stderr Kernel sysflow_reopen_stderr_channel --> stderr Kernel sysflow_reopen_stderr_channel --> stderr Kernel sysflow_finalize_stderr_channel --> stderr State restriction_state_get_deny_reason <-- check_restrictions State restriction_state_set_deny_reason --> check_restrictions State current_process_get_ml_name <-- current_process State current_process_set_ml_name <-- current_process Utils langinfo_get_charset <-- charset Utils langinfo_get_charset <-- charset Utils langinfo_set_charset --> charset Utils langinfo_get_language_hint <-- language_hint Utils langinfo_set_language_hint --> language_hint State error_message_get_count <-- reply_message_count State error_message_set_count <-- reply_message_count State error_message_set_count --> reply_message_count Notes [1] This corresponds to site_force.ph of fml4. [2] file extension corresponds to the format. [3] This file corresponds to fml4's site_force.ph. [4] This silent behaviour is proper for automatic work. If needed, makefml/fml shows log output for computer processing. [5] This is default in fml8 (default site_default_config.cf includes this configuration). [6] If it could be, it is useful to implement another command which fixes the article header later. It is not implemented. [7] It is similar to the conversion from .mc to .cf in sendmail. [8] tie() operation of perl [9] Almost cases, FML::Process::Kernel method is overloaded by other modules. So, not called directly. [10] See FML::Process::Kernel module. [11] "s" is the default message. [12] admin command is defined in $user_command_mail_allowed_commands as a normal user command. [13] DBMS = DataBase Management System