(* 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. *) (* Network messages *) structure Msg :> MSG = struct open OpenSSL MsgTypes Slave val a2i = fn Add => 0 | Delete true => 1 | Modify => 2 | Delete false => 3 val i2a = fn 0 => Add | 1 => Delete true | 2 => Modify | 3 => Delete false | _ => raise OpenSSL.OpenSSL "Bad action number to deserialize" fun sendAcl (bio, {user, class, value}) = (OpenSSL.writeString (bio, user); OpenSSL.writeString (bio, class); OpenSSL.writeString (bio, value)) fun recvAcl bio = case (OpenSSL.readString bio, OpenSSL.readString bio, OpenSSL.readString bio) of (SOME user, SOME class, SOME value) => SOME {user = user, class = class, value = value} | _ => NONE fun sendList f (bio, ls) = (app (fn x => (OpenSSL.writeInt (bio, 1); f (bio, x))) ls; OpenSSL.writeInt (bio, 0)) fun recvList f bio = let fun loop ls = case OpenSSL.readInt bio of SOME 0 => SOME (rev ls) | SOME 1 => (case f bio of SOME x => loop (x :: ls) | NONE => NONE) | _ => NONE in loop [] end fun sendOption f (bio, opt) = case opt of NONE => OpenSSL.writeInt (bio, 0) | SOME x => (OpenSSL.writeInt (bio, 1); f (bio, x)) fun recvOption f bio = case OpenSSL.readInt bio of SOME 0 => SOME NONE | SOME 1 => (case f bio of SOME x => SOME (SOME x) | NONE => NONE) | _ => NONE fun sendBool (bio, b) = if b then OpenSSL.writeInt (bio, 1) else OpenSSL.writeInt (bio, 0) fun recvBool bio = case OpenSSL.readInt bio of SOME 0 => SOME false | SOME 1 => SOME true | _ => NONE fun sendSockPerm (bio, p) = case p of Any => OpenSSL.writeInt (bio, 0) | Client => OpenSSL.writeInt (bio, 1) | Server => OpenSSL.writeInt (bio, 2) | Nada => OpenSSL.writeInt (bio, 3) fun recvSockPerm bio = case OpenSSL.readInt bio of SOME 0 => SOME Any | SOME 1 => SOME Client | SOME 2 => SOME Server | SOME 3 => SOME Nada | _ => NONE fun sendQuery (bio, q) = case q of QApt s => (OpenSSL.writeInt (bio, 0); OpenSSL.writeString (bio, s)) | QCron s => (OpenSSL.writeInt (bio, 1); OpenSSL.writeString (bio, s)) | QFtp s => (OpenSSL.writeInt (bio, 2); OpenSSL.writeString (bio, s)) | QTrustedPath s => (OpenSSL.writeInt (bio, 3); OpenSSL.writeString (bio, s)) | QSocket s => (OpenSSL.writeInt (bio, 4); OpenSSL.writeString (bio, s)) | QFirewall s => (OpenSSL.writeInt (bio, 5); OpenSSL.writeString (bio, s)) fun recvQuery bio = case OpenSSL.readInt bio of SOME n => (case n of 0 => Option.map QApt (OpenSSL.readString bio) | 1 => Option.map QCron (OpenSSL.readString bio) | 2 => Option.map QFtp (OpenSSL.readString bio) | 3 => Option.map QTrustedPath (OpenSSL.readString bio) | 4 => Option.map QSocket (OpenSSL.readString bio) | 5 => Option.map QFirewall (OpenSSL.readString bio) | _ => NONE) | NONE => NONE fun send (bio, m) = case m of MsgOk => OpenSSL.writeInt (bio, 1) | MsgError s => (OpenSSL.writeInt (bio, 2); OpenSSL.writeString (bio, s)) | MsgConfig s => (OpenSSL.writeInt (bio, 3); OpenSSL.writeString (bio, s)) | MsgFile {action, domain, dir, file} => (OpenSSL.writeInt (bio, 4); OpenSSL.writeInt (bio, a2i action); OpenSSL.writeString (bio, domain); OpenSSL.writeString (bio, dir); OpenSSL.writeString (bio, file)) | MsgDoFiles => OpenSSL.writeInt (bio, 5) | MsgGrant acl => (OpenSSL.writeInt (bio, 6); sendAcl (bio, acl)) | MsgRevoke acl => (OpenSSL.writeInt (bio, 7); sendAcl (bio, acl)) | MsgListPerms user => (OpenSSL.writeInt (bio, 8); OpenSSL.writeString (bio, user)) | MsgPerms classes => (OpenSSL.writeInt (bio, 9); sendList (fn (bio, (class, values)) => (OpenSSL.writeString (bio, class); sendList OpenSSL.writeString (bio, values))) (bio, classes)) | MsgWhoHas {class, value} => (OpenSSL.writeInt (bio, 10); OpenSSL.writeString (bio, class); OpenSSL.writeString (bio, value)) | MsgWhoHasResponse users => (OpenSSL.writeInt (bio, 11); sendList OpenSSL.writeString (bio, users)) | MsgMultiConfig codes => (OpenSSL.writeInt (bio, 12); sendList OpenSSL.writeString (bio, codes)) | MsgRmdom doms => (OpenSSL.writeInt (bio, 13); sendList OpenSSL.writeString (bio, doms)) | MsgRegenerate => OpenSSL.writeInt (bio, 14) | MsgRmuser dom => (OpenSSL.writeInt (bio, 15); OpenSSL.writeString (bio, dom)) | MsgCreateDbUser {dbtype, passwd} => (OpenSSL.writeInt (bio, 16); OpenSSL.writeString (bio, dbtype); sendOption OpenSSL.writeString (bio, passwd)) | MsgCreateDb {dbtype, dbname} => (OpenSSL.writeInt (bio, 17); OpenSSL.writeString (bio, dbtype); OpenSSL.writeString (bio, dbname)) | MsgNewMailbox {domain, user, passwd, mailbox} => (OpenSSL.writeInt (bio, 18); OpenSSL.writeString (bio, domain); OpenSSL.writeString (bio, user); OpenSSL.writeString (bio, passwd); OpenSSL.writeString (bio, mailbox)) | MsgPasswdMailbox {domain, user, passwd} => (OpenSSL.writeInt (bio, 19); OpenSSL.writeString (bio, domain); OpenSSL.writeString (bio, user); OpenSSL.writeString (bio, passwd)) | MsgRmMailbox {domain, user} => (OpenSSL.writeInt (bio, 20); OpenSSL.writeString (bio, domain); OpenSSL.writeString (bio, user)) | MsgListMailboxes domain => (OpenSSL.writeInt (bio, 21); OpenSSL.writeString (bio, domain)) | MsgMailboxes users => (OpenSSL.writeInt (bio, 22); sendList (fn (bio, {user, mailbox}) => (OpenSSL.writeString (bio, user); OpenSSL.writeString (bio, mailbox))) (bio, users)) | MsgSaQuery addr => (OpenSSL.writeInt (bio, 23); OpenSSL.writeString (bio, addr)) | MsgSaStatus b => (OpenSSL.writeInt (bio, 24); sendBool (bio, b)) | MsgSaSet (addr, b) => (OpenSSL.writeInt (bio, 25); OpenSSL.writeString (bio, addr); sendBool (bio, b)) | MsgSmtpLogReq domain => (OpenSSL.writeInt (bio, 26); OpenSSL.writeString (bio, domain)) | MsgSmtpLogRes domain => (OpenSSL.writeInt (bio, 27); OpenSSL.writeString (bio, domain)) | MsgDbPasswd {dbtype, passwd} => (OpenSSL.writeInt (bio, 28); OpenSSL.writeString (bio, dbtype); OpenSSL.writeString (bio, passwd)) | MsgShutdown => OpenSSL.writeInt (bio, 29) | MsgYes => OpenSSL.writeInt (bio, 30) | MsgNo => OpenSSL.writeInt (bio, 31) | MsgQuery q => (OpenSSL.writeInt (bio, 32); sendQuery (bio, q)) | MsgSocket p => (OpenSSL.writeInt (bio, 33); sendSockPerm (bio, p)) | MsgFirewall ls => (OpenSSL.writeInt (bio, 34); sendList OpenSSL.writeString (bio, ls)) | MsgRegenerateTc => OpenSSL.writeInt (bio, 35) | MsgDropDb {dbtype, dbname} => (OpenSSL.writeInt (bio, 36); OpenSSL.writeString (bio, dbtype); OpenSSL.writeString (bio, dbname)) | MsgGrantDb {dbtype, dbname} => (OpenSSL.writeInt (bio, 37); OpenSSL.writeString (bio, dbtype); OpenSSL.writeString (bio, dbname)) | MsgMysqlFixperms => OpenSSL.writeInt (bio, 38) | MsgDescribe dom => (OpenSSL.writeInt (bio, 39); OpenSSL.writeString (bio, dom)) | MsgDescription s => (OpenSSL.writeInt (bio, 40); OpenSSL.writeString (bio, s)) fun checkIt v = case v of NONE => raise OpenSSL.OpenSSL "Bad Msg format" | _ => v fun recv bio = case OpenSSL.readInt bio of NONE => NONE | SOME n => checkIt (case n of 1 => SOME MsgOk | 2 => Option.map MsgError (OpenSSL.readString bio) | 3 => Option.map MsgConfig (OpenSSL.readString bio) | 4 => (case (OpenSSL.readInt bio, OpenSSL.readString bio, OpenSSL.readString bio, OpenSSL.readString bio) of (SOME action, SOME domain, SOME dir, SOME file) => SOME (MsgFile {action = i2a action, domain = domain, dir = dir, file = file}) | _ => NONE) | 5 => SOME MsgDoFiles | 6 => (case recvAcl bio of SOME acl => SOME (MsgGrant acl) | _ => NONE) | 7 => (case recvAcl bio of SOME acl => SOME (MsgRevoke acl) | _ => NONE) | 8 => (case OpenSSL.readString bio of SOME user => SOME (MsgListPerms user) | _ => NONE) | 9 => Option.map MsgPerms (recvList (fn bio => case (OpenSSL.readString bio, recvList OpenSSL.readString bio) of (SOME class, SOME values) => SOME (class, values) | _ => NONE) bio) | 10 => (case (OpenSSL.readString bio, OpenSSL.readString bio) of (SOME class, SOME value) => SOME (MsgWhoHas {class = class, value = value}) | _ => NONE) | 11 => Option.map MsgWhoHasResponse (recvList OpenSSL.readString bio) | 12 => Option.map MsgMultiConfig (recvList OpenSSL.readString bio) | 13 => Option.map MsgRmdom (recvList OpenSSL.readString bio) | 14 => SOME MsgRegenerate | 15 => Option.map MsgRmuser (OpenSSL.readString bio) | 16 => (case (OpenSSL.readString bio, recvOption OpenSSL.readString bio) of (SOME dbtype, SOME passwd) => SOME (MsgCreateDbUser {dbtype = dbtype, passwd = passwd}) | _ => NONE) | 17 => (case (OpenSSL.readString bio, OpenSSL.readString bio) of (SOME dbtype, SOME dbname) => SOME (MsgCreateDb {dbtype = dbtype, dbname = dbname}) | _ => NONE) | 18 => (case (OpenSSL.readString bio, OpenSSL.readString bio, OpenSSL.readString bio, OpenSSL.readString bio) of (SOME domain, SOME user, SOME passwd, SOME mailbox) => SOME (MsgNewMailbox {domain = domain, user = user, passwd = passwd, mailbox = mailbox}) | _ => NONE) | 19 => (case (OpenSSL.readString bio, OpenSSL.readString bio, OpenSSL.readString bio) of (SOME domain, SOME user, SOME passwd) => SOME (MsgPasswdMailbox {domain = domain, user = user, passwd = passwd}) | _ => NONE) | 20 => (case (OpenSSL.readString bio, OpenSSL.readString bio) of (SOME domain, SOME user) => SOME (MsgRmMailbox {domain = domain, user = user}) | _ => NONE) | 21 => Option.map MsgListMailboxes (OpenSSL.readString bio) | 22 => Option.map MsgMailboxes (recvList (fn bio => case (OpenSSL.readString bio, OpenSSL.readString bio) of (SOME user, SOME mailbox) => SOME {user = user, mailbox = mailbox} | _ => NONE) bio) | 23 => Option.map MsgSaQuery (OpenSSL.readString bio) | 24 => Option.map MsgSaStatus (recvBool bio) | 25 => (case (OpenSSL.readString bio, recvBool bio) of (SOME user, SOME b) => SOME (MsgSaSet (user, b)) | _ => NONE) | 26 => Option.map MsgSmtpLogReq (OpenSSL.readString bio) | 27 => Option.map MsgSmtpLogRes (OpenSSL.readString bio) | 28 => (case (OpenSSL.readString bio, OpenSSL.readString bio) of (SOME dbtype, SOME passwd) => SOME (MsgDbPasswd {dbtype = dbtype, passwd = passwd}) | _ => NONE) | 29 => SOME MsgShutdown | 30 => SOME MsgYes | 31 => SOME MsgNo | 32 => Option.map MsgQuery (recvQuery bio) | 33 => Option.map MsgSocket (recvSockPerm bio) | 34 => Option.map MsgFirewall (recvList OpenSSL.readString bio) | 35 => SOME MsgRegenerateTc | 36 => (case (OpenSSL.readString bio, OpenSSL.readString bio) of (SOME dbtype, SOME dbname) => SOME (MsgDropDb {dbtype = dbtype, dbname = dbname}) | _ => NONE) | 37 => (case (OpenSSL.readString bio, OpenSSL.readString bio) of (SOME dbtype, SOME dbname) => SOME (MsgGrantDb {dbtype = dbtype, dbname = dbname}) | _ => NONE) | 38 => SOME MsgMysqlFixperms | 39 => Option.map MsgDescribe (OpenSSL.readString bio) | 40 => Option.map MsgDescription (OpenSSL.readString bio) | _ => NONE) end