4 val baseUrl
= "http://join.hcoop.net/join/"
5 val portalUrl
= "http://users.hcoop.net/portal/"
11 val db
= ref (NONE
: C
.conn option
)
13 val rnd
= ref (Random
.rand (0, 0))
17 val c
= C
.conn
"dbname='hcoop'"
21 rnd
:= Random
.rand (SysWord
.toInt (Posix
.Process
.pidToWord (Posix
.ProcEnv
.getpid ())),
22 SysWord
.toInt (Posix
.Process
.pidToWord (Posix
.ProcEnv
.getpid ())))
25 fun getDb () = valOf (!db
)
36 fun sendMail (to
, subj
, intro
, footer
, id
) =
38 val (name
, rname
, forward
, uses
, other
) =
39 case C
.oneOrNoRows (getDb ()) ($`SELECT name
, rname
, forward
, uses
, other FROM MemberApp WHERE id
= ^
(C
.intToSql id
)`
) of
40 SOME
[name
, rname
, forward
, uses
, other
] => (C
.stringFromSql name
, C
.stringFromSql rname
,
41 C
.boolFromSql forward
, C
.stringFromSql uses
,
42 C
.stringFromSql other
)
43 | _
=> raise Fail
"Bad sendMail row"
45 val proc
= Unix
.execute ("/usr/sbin/exim4", ["-t"])
46 fun mwrite s
= TextIO.output (Unix
.textOutstreamOf proc
, s
)
48 mwrite ("From: Hcoop Application System <join@hcoop.net>\nTo: ");
50 mwrite ("\nSubject: ");
54 mwrite ("\n\nUsername: ");
56 mwrite ("\nReal name: ");
58 mwrite ("\nForward e-mail: ");
59 mwrite (if forward
then "yes" else "no");
60 mwrite ("\n\nDesired uses:\n");
62 mwrite ("\n\nOther information:\n");
66 OS
.Process
.isSuccess (Unix
.reap proc
)
69 type application
= { name
: string, rname
: string, email
: string,
70 forward
: bool, uses
: string, other
: string }
72 fun apply
{name
, rname
, email
, forward
, uses
, other
} =
76 case C
.oneRow
db ($`SELECT
nextval('MemberAppSeq
')`
) of
79 val id
= C
.intFromSql id
80 val passwd
= Int.toString (Int.abs (Random
.randInt (!rnd
)))
82 C
.dml
db ($`INSERT INTO
MemberApp (id
, name
, rname
, email
, forward
, uses
, other
, passwd
, status
, applied
, msg
)
83 VALUES (^
(C
.intToSql id
), ^
(C
.stringToSql name
), ^
(C
.stringToSql rname
),
84 ^
(C
.stringToSql email
), ^
(C
.boolToSql forward
), ^
(C
.stringToSql uses
),
85 ^
(C
.stringToSql other
), ^
(C
.stringToSql passwd
), 0, CURRENT_TIMESTAMP
, '')`
);
86 sendMail (email
, "Confirm membership application",
87 "We've received a request to join the Internet Hosting Cooperative (hcoop.net) with this e-mail address.",
88 fn mwrite
=> (mwrite ("To confirm this application, visit ");
90 mwrite ("confirm?id=");
91 mwrite (Int.toString id
);
97 | _
=> raise Fail
"Bad next sequence val"
100 fun isIdent ch
= Char.isLower ch
orelse Char.isDigit ch
103 size s
> 0 andalso size s
< 20 andalso List.all
isIdent (String.explode s
)
106 size s
> 0 andalso size s
< 100 andalso List.all
validHost (String.fields (fn ch
=> ch
= #
".") s
)
109 size s
> 0 andalso size s
< 50 andalso List.all
110 (fn ch
=> isIdent ch
orelse ch
= #
"." orelse ch
= #
"_" orelse ch
= #
"-" orelse ch
= #
"+")
113 fun validEmailUser s
=
114 size s
> 0 andalso size s
< 50 andalso List.all
115 (fn ch
=> Char.isAlphaNum ch
orelse ch
= #
"." orelse ch
= #
"_" orelse ch
= #
"-" orelse ch
= #
"+")
119 (case String.fields (fn ch
=> ch
= #
"@") s
of
120 [user
, host
] => validEmailUser user
andalso validDomain host
123 fun userExists name
=
124 (Posix
.SysDB
.getpwnam name
; true) handle OS
.SysErr _
=> false
126 fun confirm (id
, passwd
) =
130 case C
.oneOrNoRows
db ($`SELECT id FROM MemberApp WHERE id
= ^
(C
.intToSql id
) AND passwd
= ^
(C
.stringToSql passwd
) AND status
= 0`
) of
132 (C
.dml
db ($`UPDATE MemberApp SET status
= 1, confirmed
= CURRENT_TIMESTAMP WHERE id
= ^
(C
.intToSql id
)`
);
133 sendMail ("board.fake@hcoop.net",
134 "New membership application",
135 "We've received a new request to join hcoop.",
136 fn mwrite
=> (mwrite ("Open applications: ");