(* HCoop Domtool (http://hcoop.sourceforge.net/) * Copyright (c) 2006, Adam Chlipala * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *) (* Configuring e-mail aliases *) structure Alias :> ALIAS = struct open Ast structure SM = DataStructures.StringMap val aliases : TextIO.outstream SM.map ref = ref SM.empty fun aliasesF node = valOf (SM.find (!aliases, node)) val aliasesD : TextIO.outstream SM.map ref = ref SM.empty fun aliasesDF node = valOf (SM.find (!aliasesD, node)) fun write nodes = let val files = map (fn node => aliasesF node) nodes in fn s => app (fn file => TextIO.output (file, s)) files end fun writeD nodes = let val files = map (fn node => aliasesDF node) nodes in fn s => app (fn file => TextIO.output (file, s)) files end fun openInAll base = foldl (fn (node, r) => SM.insert (r, node, Domain.domainFile {node = node, name = base})) SM.empty Domain.nodes val _ = Domain.registerBefore (fn _ => (aliases := openInAll "aliases"; aliasesD := openInAll "aliases.default")) val _ = Domain.registerAfter (fn _ => (SM.app TextIO.closeOut (!aliases); SM.app TextIO.closeOut (!aliasesD))) fun validEmailUser s = size s > 0 andalso size s < 50 andalso CharVector.all (fn ch => Char.isAlphaNum ch orelse ch = #"." orelse ch = #"_" orelse ch = #"-" orelse ch = #"+") s val _ = Env.type_one "emailUser" Env.string validEmailUser fun validEmail s = case String.fields (fn ch => ch = #"@") s of [user] => validEmailUser user | [user, host] => validEmailUser user andalso Domain.validDomain host | _ => false val _ = Env.type_one "email" Env.string validEmail datatype aliasSource = User of string | Default | CatchAll val source = fn (EApp ((EVar "userSource", _), e), _) => Option.map User (Env.string e) | (EVar "defaultSource", _) => SOME Default | (EVar "catchAllSource", _) => SOME CatchAll | _ => NONE datatype aliasTarget = Address of string | Addresses of string list | Drop val target = fn (EApp ((EVar "addressTarget", _), e), _) => Option.map Address (Env.string e) | (EApp ((EVar "addressesTarget", _), e), _) => Option.map Addresses (Env.list Env.string e) | (EVar "dropTarget", _) => SOME Drop | _ => NONE fun localhostify s = let val (prefix, suffix) = Substring.splitl (fn ch => ch <> #"@") (Substring.full s) in if Substring.size suffix = 0 then s ^ "@localhost" else s end fun writeSource (env, s, t) = let val nodes = Env.env (Env.list Env.string) (env, "MailNodes") val write = write nodes val writeD = writeD nodes fun writeTarget (writer, t) = case t of Address s => writer (localhostify s) | Addresses [] => writer "!" | Addresses ss => writer (String.concatWith "," (map localhostify ss)) | Drop => writer "!" in case s of User s => (write s; write "@"; write (Domain.currentDomain ()); write ": "; writeTarget (write, t); write "\n") | Default => (write "*@"; write (Domain.currentDomain ()); write ": "; writeTarget (write, t); write "\n") | CatchAll => (writeD "*@"; writeD (Domain.currentDomain ()); writeD ": "; writeTarget (writeD, t); writeD "\n") end val _ = Env.actionV_two "aliasPrim" ("from", source, "to", target) writeSource end