summaryrefslogtreecommitdiff
path: root/src/sh
diff options
context:
space:
mode:
authorHenrik Rydberg <rydberg@euromail.se>2011-10-08 20:30:28 +0200
committerHenrik Rydberg <rydberg@euromail.se>2011-10-08 20:30:28 +0200
commit5df79c53745fde5d6c3340a2979b1429cd5892c1 (patch)
tree1a81af141708b826e9c61e8a04019994fcca8298 /src/sh
Initial import of htcd system 1.0
Signed-off-by: Henrik Rydberg <rydberg@euromail.se>
Diffstat (limited to 'src/sh')
-rw-r--r--src/sh/convert.cc376
-rw-r--r--src/sh/dates.cc138
-rw-r--r--src/sh/file.cc367
-rw-r--r--src/sh/htc.cc92
-rw-r--r--src/sh/htc.h77
-rw-r--r--src/sh/main.cc129
-rw-r--r--src/sh/net.cc122
-rw-r--r--src/sh/string.cc32
-rw-r--r--src/sh/sys.cc152
-rw-r--r--src/sh/tree.cc304
-rw-r--r--src/sh/user.cc445
-rw-r--r--src/sh/user.h92
12 files changed, 2326 insertions, 0 deletions
diff --git a/src/sh/convert.cc b/src/sh/convert.cc
new file mode 100644
index 0000000..8828c34
--- /dev/null
+++ b/src/sh/convert.cc
@@ -0,0 +1,376 @@
1/*************************************************************************
2 *
3 * HTCd - Copyright (C) 1998-2006 Henrik Rydberg
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20#include <sh/htc.h>
21#include <hdb/buffer.h>
22#include <http/http.h>
23
24static const charset htcmask("{}\\%&*$;");
25static const charset htmlmask("<&>\"");
26
27static void Mask(mstream& out,const charset& mask,const sref& msg)
28{
29 sref q,p=msg;
30 while(p.nempty()) {
31 p=p.adv(q=p.left_first_of(mask));
32 out<<q;
33 while(mask.test(p.front())) {
34 unsigned code=(unsigned char)*p; p=p.popf();
35 out<<"&#"<<code<<";";
36 }
37 }
38}
39
40TOK_IMPL(mask_htc) {
41 Mask(out,htcmask,env[0]);
42}
43
44TOK_IMPL(mask_html) {
45 Mask(out,htmlmask,env[0]);
46}
47
48TOK_IMPL(cdata) {
49 out.put('\"'); Mask(out,htmlmask,env[0]); out.put('\"');
50}
51
52//////////////////////////////////////////////////////////
53
54TOK_IMPL(wrap) {
55 int num=atoi(env[0]);
56 sref body=env[1];
57 int col=0;
58 for(int i=0;i<body.size();i++) {
59 if(cset_newl.test(body[i])) col=0; else col++;
60 if(cset_spaces.test(body[i])&&col>num) { out.put('\n'); col=0; }
61 else out.put(body[i]);
62 }
63}
64
65TOK_IMPL(htmlize) {
66 sref first,rest=env[0];
67 while(Splitln(first,rest)) {
68 Mask(out,htmlmask,first);
69 out<<"<br>\n";
70 }
71}
72
73TOK_IMPL(lf2crlf) {
74 LF2CRLF(out,env[0]);
75}
76TOK_IMPL(crlf2lf) {
77 CRLF2LF(out,env[0]);
78}
79
80//////////////////////////////////////////////////////////
81
82TOK_IMPL(twocolumn) {
83 int num=atoi(env[0]);
84 int page=atoi(env[1]);
85 sref head=env[2],mid=env[3],foot=env[4],body=env[5];
86 int row=0,col=0,pg=1;
87 out<<head;
88 for(int i=0;i<body.size()&&pg<=page;i++) {
89 if(pg==page) out.put(body[i]);
90 if(body[i]=='\n') {
91 row++;
92 if(row>=num) {
93 row=0;
94 col++;
95 if(col>=2) { col=0; pg++; }
96 else if(pg==page) { out<<mid; }
97 }
98 }
99 }
100 out<<foot;
101}
102
103//////////////////////////////////////////////////////////
104
105TOK_IMPL(encode) {
106 Pack(out,env[0]);
107}
108
109TOK_IMPL(decode) {
110 Unpack(out,env[0]);
111}
112
113TOK_IMPL(encode_header) {
114 encodeHeader(out,mime_default,env[0]);
115}
116
117TOK_IMPL(encode_base64) {
118 mstring buffer,path=DocPath(env,env[0]);
119 LoadBuffer(buffer,path);
120 encode64(out,buffer);
121}
122
123TOK_IMPL(pack) {
124 rrpile pile;
125 spile var(env.args);
126 for(int i=0;i<env.args;i++) {
127 env.parg(var[i],i);
128 pile.push_back(rrstring(var[i],env.glob(var[i])));
129 }
130 Pack(out,pile);
131}
132
133//////////////////////////////////////////////////////////
134
135TOK_IMPL(decode_base64) {
136 mstring buffer,name=env.parg(-1),uri=env.URI(env[0]),path=DocPath(env,env[0]);
137 LoadBuffer(buffer,path);
138 if(name.nempty()) {
139 swrite sw(Reference(*env.toks,name,uri,1)->data);
140 decode64(sw,buffer);
141 }
142 else decode64(out,buffer);
143}
144
145//////////////////////////////////////////////////////////
146
147TOK_IMPL(strip) {
148 sref s=env[0],a=env[1];
149 for(int i=0;i<s.size();i++) if(a.find(s[i])<0) out.put(s[i]);
150}
151
152TOK_IMPL(replace) {
153 mstring s=env[0]; sref a=env[1],b=env[2];
154 if(a!=b) { int p; while((p=s.find(a))>=0) s.replace(p,a.size(),b); }
155 out<<s;
156}
157
158//////////////////////////////////////////////////////////
159
160TOK_IMPL(left) {
161 int pad=atoi(env[1])-env[0].size();
162 out<<env[0]; while(pad-->0) out.put(' ');
163}
164TOK_IMPL(right) {
165 int pad=atoi(env[1])-env[0].size();
166 while(pad-->0) out.put(' '); out<<env[0];
167}
168
169TOK_IMPL(sub) {out<<env[0](atoi(env[1]),atoi(env[2]));}
170
171//////////////////////////////////////////////////////////
172
173TOK_IMPL(file2mime) {
174 const sref* p=file2mime(env[0]);
175 if(p) out<<*p; else out<<http_mime_default;
176}
177
178//////////////////////////////////////////////////////////
179
180TOK_IMPL(minilang) {
181 static const mstring lang_tag("\\lang");
182 sref p=env[0];
183 while(p.nempty()) {
184 sref e=p.left_first(lang_tag);
185 out<<e;
186 p=p.adv(e);
187 if(p.nempty()) {
188 p=p.adv(lang_tag.size());
189 e=p.right_first_not_of(cset_ws);
190 int n=0,s=e.skip(cset_braces);
191 while(s>0) {
192 p=e.adv(s);
193 if(n==env.req->lang) out<<e(1,s-2);
194 e=p.right_first_not_of(cset_ws);
195 s=e.skip(cset_braces);
196 n++;
197 }
198 if(n==0) out<<lang_tag;
199 if(*p==';') p=p.adv(1);
200 }
201 }
202}
203
204//////////////////////////////////////////////////////////
205
206void envAddConvert(tokmap& T)
207{
208 TOK_ADD(mask_htc,"x",tok_t::SYSONLY,
209 "%Mask HTC language\n"
210 "%Syntax: \\mask.htc{text}\n"
211 "%\n"
212 "%Converts 'hot' characters to HTML CDATA encoding\n"
213 "%CDATA encoding: &#hex;\n"
214 );
215 TOK_ADD(mask_html,"x",tok_t::PUBLIC,
216 "%Mask HTML language\n"
217 "%Syntax: \\mask.html{text}\n"
218 "%\n"
219 "%Converts 'hot' characters to HTML CDATA encoding\n"
220 "%CDATA encoding: &#hex;\n"
221 );
222 TOK_ADD(cdata,"x",tok_t::PUBLIC,
223 "%Convert to CDATA\n"
224 "%Syntax: \\cdata{text}\n"
225 "%\n"
226 "%Converts 'hot' characters to HTML CDATA encoding\n"
227 "%and encloses in \" characters\n"
228 "%\n"
229 "%HTML parsors usually does not nest the \" character,\n"
230 "%so this function is used extensively in arguments to\n"
231 "%HTML commands.\n"
232 );
233
234 ///////////////////////////////////////////////
235
236 TOK_ADD(wrap,"xx",tok_t::PUBLIC,
237 "%Wrap long lines\n"
238 "%Syntax: \\wrap{at column}{text}\n"
239 "%\n"
240 "%Wraps words that extend the given column by inserting\n"
241 "%newline characters.\n"
242 );
243 TOK_ADD(htmlize,"x",tok_t::PUBLIC,
244 "%HTMLize plain text\n"
245 "%Syntax: \\htmlize{text}\n"
246 "%\n"
247 "%Inserts a HTML break at each newline.\n"
248 );
249 TOK_ADD(lf2crlf,"x",tok_t::PUBLIC,
250 "%LF to CRLF\n"
251 "%Syntax: \\lf2crlf{text}\n"
252 "%\n"
253 "%Inserts a carriage return (CR) at each newline.\n"
254 );
255 TOK_ADD(crlf2lf,"x",tok_t::PUBLIC,
256 "%CRLF to LF\n"
257 "%Syntax: \\crlf2lf{text}\n"
258 "%\n"
259 "%Removes all carriage return (CR) characters.\n"
260 );
261
262 ///////////////////////////////////////////////
263
264 TOK_ADD(twocolumn,"xxxxxx",tok_t::PUBLIC,
265 "%Output column text\n"
266 "%Syntax: \\twocolumn{rows}{page}{head}{mid}{foot}{body}\n"
267 );
268
269 ///////////////////////////////////////////////
270
271 TOK_ADD(encode,"x",tok_t::PUBLIC,
272 "%Encode text\n"
273 "%Syntax: \\encode{text}\n"
274 "%\n"
275 "%Encodes text in x-www-form-urlencoded format (RFC HTTP)\n"
276 );
277 TOK_ADD(decode,"x",tok_t::PUBLIC,
278 "%Decode text\n"
279 "%Syntax: \\decode{text}\n"
280 "%\n"
281 "%Decodes text given in x-www-form-urlencoded format (RFC HTTP)\n"
282 );
283
284 TOK_ADD(encode_header,"x",tok_t::PUBLIC,
285 "%Encode header\n"
286 "%Syntax: \\encode.header{text}\n"
287 "%\n"
288 "%Encodes text in Quoted-printable header format (RFC MIME)\n"
289 );
290 TOK_ADD(encode_base64,"x",tok_t::PUBLIC,
291 "%Encode base64\n"
292 "%Syntax: \\encode.base64{uri}\n"
293 "%\n"
294 "%Encodes the uri, possible containing binary data,\n"
295 "%in BASE64 format (RFC MIME)\n"
296 );
297 TOK_ADD(decode_base64,"?x",tok_t::PUBLIC,
298 "%Decode base64\n"
299 "%Syntax: \\decode.base64{var}{uri}\n"
300 "%\n"
301 "%Encodes the uri, presumed to be in BASE64 format,\n"
302 "%and outputs or saves in var. (RFC MIME)\n"
303 );
304 TOK_ADD(pack,"*",tok_t::PUBLIC,
305 "%Encode text\n"
306 "%Syntax: \\pack<var><var>..\n"
307 "%\n"
308 "%Encodes a sequence of variables in\n"
309 "%x-www-form-urlencoded format (RFC HTTP)\n"
310 );
311
312 ///////////////////////////////////////////////
313
314 TOK_ADD(strip,"xx",tok_t::PUBLIC,
315 "%Strip text from special characters\n"
316 "%Syntax: \\stip{text}{chars}\n"
317 );
318 TOK_ADD(replace,"xxx",tok_t::PUBLIC,
319 "%Replace text\n"
320 "%Syntax: \\replace{text}{string}{subst}\n"
321 "%\n"
322 "%Replaces each occurence of string in text with subst.\n"
323 );
324
325 ///////////////////////////////////////////////
326
327 TOK_ADD(left,"xx",tok_t::PUBLIC,
328 "%Left-adjust text\n"
329 "%Syntax: \\left{text}{n}\n"
330 "%\n"
331 "%Outputs n characters, padding with spaces to the right.\n"
332 "%\n"
333 "%Writes out the full text if longer than n.\n"
334 );
335 TOK_ADD(right,"xx",tok_t::PUBLIC,
336 "%Right-adjust text\n"
337 "%Syntax: \\right{text}{n}\n"
338 "%\n"
339 "%Outputs n characters, padding with spaces to the left.\n"
340 "%\n"
341 "%Writes out the full text if longer than n.\n"
342 );
343
344 ///////////////////////////////////////////////
345
346 TOK_ADD(sub,"xxx",tok_t::PUBLIC,
347 "%Substring\n"
348 "%Syntax: \\sub{string}{pos}{n}\n"
349 "%\n"
350 "%Gets a substring of n characters, beginning at pos, from string.\n"
351 "%\n"
352 "%Negative pos values wraps to end.\n"
353 "%Negative n values wraps to 1+size.\n"
354 );
355
356 ///////////////////////////////////////////////
357
358 TOK_ADD(file2mime,"x",tok_t::PUBLIC,
359 "%Get MIME type\n"
360 "%Syntax: \\file2mime{path}\n"
361 "%\n"
362 "%Looks up the MIME type mapped to the extension of path.\n"
363 "%\n"
364 "%Defaults to application/octet-stream if not found.\n"
365 );
366
367 ///////////////////////////////////////////////
368
369 TOK_ADD(minilang,"x",tok_t::PUBLIC,
370 "%Parse lang only\n"
371 "%Syntax: \\minilang{body}\n"
372 "%\n"
373 "%This function is used to enable lang in html files,\n"
374 "%which otherwise are not parsed.\n"
375 );
376}
diff --git a/src/sh/dates.cc b/src/sh/dates.cc
new file mode 100644
index 0000000..a37103b
--- /dev/null
+++ b/src/sh/dates.cc
@@ -0,0 +1,138 @@
1/*************************************************************************
2 *
3 * HTCd - Copyright (C) 1998-2006 Henrik Rydberg
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20#include <sh/htc.h>
21#include <mt/dates.h>
22#include <limits.h>
23
24const int ENDTIME=INT_MAX-4*SEC_PER_DAY;
25
26TOK_IMPL(endtime) { out<<ENDTIME; }
27TOK_IMPL(now) { out<<Now(); }
28TOK_IMPL(minutes) { out<<(60*atoi(env[0])); }
29TOK_IMPL(days) { out<<Days(atoi(env[0])); }
30TOK_IMPL(today) { out<<Today(atoi(env[0])); }
31TOK_IMPL(sunday) { out<<Sunday(atoi(env[0])); }
32TOK_IMPL(week) { out<<Week(env.req->lang,atoi(env[0])); }
33TOK_IMPL(month) { out<<Month(env.req->lang,atoi(env[0])); }
34TOK_IMPL(sweek) { out<<SWeek(env.req->lang,atoi(env[0])); }
35TOK_IMPL(smonth) { out<<SMonth(env.req->lang,atoi(env[0])); }
36
37////////////////////////////////////////////////////////////
38
39TOK_IMPL(time2http) { out<<httpTime(atoi(env[0])); }
40TOK_IMPL(time2htc) { out<<htcTime(env.req->lang,atoi(env[0])); }
41TOK_IMPL(htc2time) { out<<htcTime(env.req->lang,env[0]); }
42TOK_IMPL(cvttime) { out<<cvtTime(env[0]); }
43
44////////////////////////////////////////////////////////////
45
46void envAddDates(tokmap& T)
47{
48 TOK_ADD(endtime,"",tok_t::PUBLIC,
49 "%Endtime\n"
50 "%Syntax: \\endtime\n"
51 "%\n"
52 "%Last time (safely) representable by internal format\n"
53 );
54 TOK_ADD(now,"",tok_t::PUBLIC,
55 "%Now\n"
56 "%Syntax: \\now\n"
57 "%\n"
58 "%Current system time. Note that this may be out of\n"
59 "%sync with filesystem.\n"
60 );
61 TOK_ADD(minutes,"x",tok_t::PUBLIC,
62 "%Minutes in seconds\n"
63 "%Syntax: \\minutes{m}\n"
64 );
65 TOK_ADD(days,"x",tok_t::PUBLIC,
66 "%Days in seconds\n"
67 "%Syntax: \\days{d}\n"
68 );
69 TOK_ADD(today,"x",tok_t::PUBLIC,
70 "%Beginning of day\n"
71 "%Syntax: \\today{t}\n"
72 "%\n"
73 "%Get beginning of day.\n"
74 );
75 TOK_ADD(sunday,"x",tok_t::PUBLIC,
76 "%Last sunday\n"
77 "%Syntax: \\sunday{t}\n"
78 "%\n"
79 "%Get beginning of last sunday.\n"
80 );
81 TOK_ADD(week,"x",tok_t::PUBLIC,
82 "%Weekday (long)\n"
83 "%Syntax: \\week{t}\n"
84 "%\n"
85 "%Get long weekday format.\n"
86 "%Output in current language.\n"
87 );
88 TOK_ADD(month,"x",tok_t::PUBLIC,
89 "%Month (long)\n"
90 "%Syntax: \\month{t}\n"
91 "%\n"
92 "%Get long month format.\n"
93 "%Output in current language.\n"
94 );
95 TOK_ADD(sweek,"x",tok_t::PUBLIC,
96 "%Weekday (short)\n"
97 "%Syntax: \\sweek{t}\n"
98 "%\n"
99 "%Get short weekday format.\n"
100 "%Output in current language.\n"
101 );
102 TOK_ADD(smonth,"x",tok_t::PUBLIC,
103 "%Month (short)\n"
104 "%Syntax: \\smonth{t}\n"
105 "%\n"
106 "%Get short month format.\n"
107 "%Output in current language.\n"
108 );
109
110 //////////////////////////////////////////////////////
111
112 TOK_ADD(time2http,"x",tok_t::PUBLIC,
113 "%HTTP Standard Time (GMT)\n"
114 "%Syntax: \\time2http{t}\n"
115 "%\n"
116 "%Outputs time in standard HTTP format.\n"
117 );
118 TOK_ADD(time2htc,"x",tok_t::PUBLIC,
119 "%HTC Standard Time (Local)\n"
120 "%Syntax: \\time2htc{t}\n"
121 "%\n"
122 "%Outputs time in standard HTC format, which is local time.\n"
123 "%Output in current language.\n"
124 );
125 TOK_ADD(htc2time,"x",tok_t::PUBLIC,
126 "%Convert to time from HTC (Local)\n"
127 "%Syntax: \\htc2time{timestring}\n"
128 "%\n"
129 "%Converts text to local time internal format.\n"
130 );
131 TOK_ADD(cvttime,"x",tok_t::PUBLIC,
132 "%Convert user input time (Local)\n"
133 "%Syntax: \\cvttime{timestring}\n"
134 "%\n"
135 "%Tries to make an intelligent conversion of user input\n"
136 "%under the assumption that a local time is given.\n"
137 );
138}
diff --git a/src/sh/file.cc b/src/sh/file.cc
new file mode 100644
index 0000000..3d885c5
--- /dev/null
+++ b/src/sh/file.cc
@@ -0,0 +1,367 @@
1/*************************************************************************
2 *
3 * HTCd - Copyright (C) 1998-2006 Henrik Rydberg
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20#include <sh/htc.h>
21#include <hdb/buffer.h>
22#include <mt/dates.h>
23#include <dirent.h>
24#include <sys/stat.h>
25
26const mstring sdot=".",sdots="..";
27
28///////////////////////////////////////////////////////////////////
29
30inline void stat(struct stat& fs,Env& env,const sref& path) throw(merror_t) {
31 if(::stat(DocPath(env,path).c_str(),&fs)<0)
32 THROW("htc: could not stat "<<path<<" - not found");
33}
34
35///////////////////////////////////////////////////////////////////
36
37TOK_IMPL(remfile) {
38 mstring path=DocPath(env,env[0]);
39 if(remove(path.c_str())<0) THROW("htc: Could not remove "<<path);
40}
41
42TOK_IMPL(renfile) {
43 mstring oldpath=DocPath(env,env[0]),newpath=DocPath(env,env[1]);
44 if(rename(oldpath.c_str(),newpath.c_str())<0)
45 THROW("htc: Could not rename "<<oldpath<<" to "<<newpath);
46}
47
48TOK_IMPL(filesafe) {
49 static const charset fsafe=cset_alphareal|'_';
50 mstring file=env[0];
51 int pos=file.rfind('/'); if(pos>=0) file=file.past(pos,1);
52 pos=file.rfind('\\'); if(pos>=0) file=file.past(pos,1);
53 while((pos=file.find(sdots))>=0) file.erase(pos,2);
54 mstring acc;
55 for(int i=0;i<file.size();i++) if(fsafe.test(file[i])) acc.append(1,file[i]);
56 out<<acc;
57}
58
59///////////////////////////////////////////////////////////////////
60
61TOK_IMPL(seturi) {
62 Req(env)->uri=env[0];
63}
64
65TOK_IMPL(uri) {
66 out<<Req(env)->uri;
67}
68
69TOK_IMPL(pwd) {
70 out<<Req(env)->uri.left_last('/');
71}
72
73TOK_IMPL(npwd) {
74 mstring s=Req(env)->uri.left_last('/');
75 for(int i=0;i<MAXLANG;i++) {
76 if(s.past_first('/').left_first('/')==LANG[i]) {
77 s=s.past_first('/').right_first('/');
78 break;
79 }
80 }
81 out<<s;
82}
83
84TOK_IMPL(home) {
85 if(Req(env)->htc()->docroot.nempty())
86 THROW("htc: home only works in absolute file mode");
87 out<<htchome();
88}
89
90///////////////////////////////////////////////////////////////////
91
92TOK_IMPL(load) {
93 mstring name=env.parg(-1),uri=env.URI(env[0]),path=DocPath(env,uri);
94 if(name.nempty()) LoadBuffer(Reference(*env.toks,name,uri,1)->data,path);
95 else { mstring buffer; LoadBuffer(buffer,path); out<<buffer; }
96}
97
98TOK_IMPL(open) {
99 mstring name=env[0],uri=env.URI(env[1]),path=DocPath(env,uri);
100 dbref_t* ref=DBRef(*env.toks,env[0],ms_empty,tok_t::PRIVATE,1);
101 ref->db.Open(path,atoi(env.parg(-1)));
102}
103
104TOK_IMPL(save) {
105 mstring path=DocPath(env,env[0]),var=env[1];
106 int prot=atoi(env.parg(2)); if(!prot) prot=0600;
107 tok_t* p=env.toks->get(var);
108 if(!p) THROW("htc: "<<var<<": no such variable");
109 if(p->is_reference()) SaveBuffer(((reference_t*)p)->data,path,prot);
110 else if(p->is_dbref()) ((dbref_t*)p)->db.Saveas(path,prot);
111 else SaveBuffer(p->body,path,prot);
112}
113
114TOK_IMPL(dbmod) {
115 dbref_t* p=(dbref_t*)env.toks->get(env[0]);
116 if(!p&&!p->is_dbref()) THROW("htc: "<<env[0]<<": no such database");
117 out<<p->db.Lastmod();
118}
119
120///////////////////////////////////////////////////////////////////
121
122static void Run(mstream& out,Env& env,const mstring& path) throw(merror_t) {
123 mstring buffer;
124 LoadBuffer(buffer,path);
125 env.parse(out,buffer);
126}
127
128TOK_IMPL(include) {
129 mstring cwd=env.URI(env[0]),path=DocPath(env,cwd);
130 if(!env.glob_find(cwd)) {
131 env.toks->add(new tok_t(cwd,ms_empty,tok_t::CONSTANT|tok_t::PRIVATE),0,1);
132 mstream m;
133 Env e(env,env.mod,cwd);
134 Run(m,e,path);
135 }
136}
137
138TOK_IMPL(parse) {
139 mstring cwd=env.URI(env[0]),path=DocPath(env,cwd);
140 Env e(env,env.mod,cwd);
141 Run(out,e,path);
142}
143
144TOK_IMPL(parse_private) {
145 mstring cwd=env.URI(env[0]),path=DocPath(env,cwd);
146 Env e(env,XPRIVATE,cwd);
147 Run(out,e,path);
148}
149
150TOK_IMPL(parse_public) {
151 mstring cwd=env.URI(env[0]),path=DocPath(env,cwd);
152 Env e(env,XPUBLIC,cwd);
153 Run(out,e,path);
154}
155
156///////////////////////////////////////////////////////////////////
157
158TOK_IMPL(dirent) {
159 mstring uri=env.URI(env[0]);
160 sref uribase=uri.leftand_last('/'),ext=uri.adv(uribase);
161 mstring dirpath=DocPath(env,uribase);
162 DIR* dir=opendir(dirpath.c_str());
163 if(dir) {
164 dirent* p;
165 while((p=readdir(dir))!=0) {
166 sref name(p->d_name);
167 if(name.empty()||name==sdot||name==sdots) continue;
168 if(ext.empty()||name.right(-ext.size()-1)==ext) out<<uribase<<name<<"\n";
169 }
170 closedir(dir);
171 }
172}
173
174TOK_IMPL(dirmod) {
175 struct stat fs;
176 if(::stat(DocPath(env,env[0]).c_str(),&fs)>=0) out<<fs.st_mode;
177 else out<<(int)0;
178}
179
180TOK_IMPL(dirmtime) { struct stat fs; stat(fs,env,env[0]); out<<fs.st_mtime; }
181TOK_IMPL(diruid) { struct stat fs; stat(fs,env,env[0]); out<<fs.st_uid; }
182TOK_IMPL(dirgid) { struct stat fs; stat(fs,env,env[0]); out<<fs.st_gid; }
183TOK_IMPL(filesize) { struct stat fs; stat(fs,env,env[0]); out<<fs.st_size; }
184
185TOK_IMPL(setperm) {
186 mstring path=DocPath(env,env[0]);
187 if(chmod(path.c_str(),atoi(env[1]))<0)
188 THROW("htc: could not set file permission for "<<path);
189}
190
191///////////////////////////////////////////////////////////////////
192
193void envAddFile(tokmap& T)
194{
195 TOK_ADD(remfile,"x",tok_t::SYSONLY,
196 "%Remove file\n"
197 "%Syntax: \\remfile{uri}\n"
198 );
199 TOK_ADD(renfile,"xx",tok_t::SYSONLY,
200 "%Rename file\n"
201 "%Syntax: \\renfile{olduri}{newuri}\n"
202 );
203 TOK_ADD(filesafe,"x",tok_t::PUBLIC,
204 "%Transform uri to something safe to save\n"
205 "%Syntax: \\filesafe{uri}\n"
206 "%\n"
207 "%Basically removes eventual path information and\n"
208 "%odd characters.\n"
209 );
210
211 ////////////////////////////////////////////////////////
212
213 TOK_ADD(seturi,"x",tok_t::SYSONLY,
214 "%Set current uri of current request\n"
215 "%Syntax: \\seturi\n"
216 "%\n"
217 "%Always points to a (virtual) uri.\n"
218 );
219 TOK_ADD(uri,"",tok_t::PUBLIC,
220 "%uri of current request\n"
221 "%Syntax: \\uri\n"
222 "%\n"
223 "%Always points to a (virtual) uri.\n"
224 );
225 TOK_ADD(pwd,"",tok_t::PUBLIC,
226 "%uri/directory of current request\n"
227 "%Syntax: \\pwd\n"
228 "%\n"
229 "%Always points to a (virtual) directory, and never contain any\n"
230 "%trailing slashes.\n"
231 );
232 TOK_ADD(npwd,"",tok_t::PUBLIC,
233 "%uri/directory of current request, without language reference\n"
234 "%Syntax: \\npwd\n"
235 "%\n"
236 "%Always points to a (virtual) directory, and never contain any\n"
237 "%trailing slashes.\n"
238 );
239 TOK_ADD(home,"",tok_t::PRIVATE,
240 "%Home directory\n"
241 "%Syntax: \\home\n"
242 "%\n"
243 "%Only works in absolute path mode, i.e. when no docroot is set.\n"
244 );
245
246 ////////////////////////////////////////////////////////
247
248 TOK_ADD(load,"?x",tok_t::PRIVATE,
249 "%Load file directly to output or to variable\n"
250 "%Syntax: \\load<varname>{uri}\n"
251 );
252 TOK_ADD(open,"xx?",tok_t::SYSONLY,
253 "%Open database to variable\n"
254 "%Syntax: \\load{varname}{uri}<update>\n"
255 "%\n"
256 "%If update is true, the database is opened for reading\n"
257 "%and writing. NOTE that all updates are syncronous and\n"
258 "%instantly - saves or locks are not needed.\n"
259 );
260 TOK_ADD(save,"xx?",tok_t::SYSONLY,
261 "%Save variable to file\n"
262 "%Syntax: \\save{uri}{varname}<prot>\n"
263 "%\n"
264 "%If the variable points to a reference object, the\n"
265 "%reference is saved. If it points to a database,\n"
266 "%the database is saved. For globals and functions,\n"
267 "%the body is saved.\n"
268 "%\n"
269 "%The optional prot argument is a (base 10) integer\n"
270 "%defining the creation mode mask (unix).\n"
271 );
272 TOK_ADD(dbmod,"x",tok_t::PUBLIC,
273 "%Get modification time of open database\n"
274 "%Syntax: \\dbmod{var}\n"
275 );
276
277 ////////////////////////////////////////////////////////
278
279 TOK_ADD(include,"x",tok_t::PRIVATE,
280 "%Include file in current running mode\n"
281 "%Syntax: \\include{uri}\n"
282 "%\n"
283 "%The file is loaded and evaluated, but produces no output\n"
284 "%Any uri can only be included once, so it is safe to use\n"
285 "%include as a precondition.\n"
286 "%\n"
287 "%NOTE that files parsed this way must be known to\n"
288 "%the super-user in order not to create a security hole -\n"
289 "%especially since this command is open in private mode also.\n"
290 );
291
292 TOK_ADD(parse,"x",tok_t::SYSONLY,
293 "%Parse file in current running mode\n"
294 "%Syntax: \\parse{uri}\n"
295 "%\n"
296 "%The file is loaded and evaluated to output.\n"
297 "%\n"
298 "%NOTE that files parsed this way must be known to\n"
299 "%the super-user in order not to create a security hole.\n"
300 );
301
302 TOK_ADD(parse_private,"x",tok_t::PRIVATE,
303 "%Parse file in private mode\n"
304 "%Syntax: \\parse.private{uri}\n"
305 "%\n"
306 "%The file is loaded and evaluated to output.\n"
307 "%\n"
308 "%System-mode commands are silently ignored.\n"
309 );
310
311 TOK_ADD(parse_public,"x",tok_t::PRIVATE,
312 "%Parse file in public mode\n"
313 "%Syntax: \\parse.public{uri}\n"
314 "%\n"
315 "%The file is loaded and evaluated to output.\n"
316 "%\n"
317 "%System/Private mode commands are silently ignored.\n"
318 );
319
320 ////////////////////////////////////////////////////////
321
322 TOK_ADD(dirent,"x",tok_t::SYSONLY,
323 "%Collect directory entries\n"
324 "%Syntax: \\dirent{uri/match}\n"
325 "%\n"
326 "%An argument of anydir/ collects all files in anydir.\n"
327 "%An argument of anydir/.ext collects all files ending with .ext\n"
328 "%\n"
329 "%Note that an argument of anydir collects files in the parent\n"
330 "%directory of anydir which end whith anydir, which probably is\n"
331 "%not what you want. Trailing slashes are important.\n"
332 );
333 TOK_ADD(dirmod,"x",tok_t::SYSONLY,
334 "%Return file mode of uri\n"
335 "%Syntax: \\dirmod{uri}\n"
336 "%\n"
337 "%dirmod uses the unix stat function.\n"
338 "%On failure to read, returns zero.\n"
339 );
340 TOK_ADD(dirmtime,"x",tok_t::SYSONLY,
341 "%Return modification time of uri\n"
342 "%Syntax: \\dirmtime{uri}\n"
343 );
344 TOK_ADD(diruid,"x",tok_t::SYSONLY,
345 "%Return UNIX uid of uri\n"
346 "%Syntax: \\diruid{uri}\n"
347 "%\n"
348 "%Note that the UNIX uid is different from the HTC one.\n"
349 );
350 TOK_ADD(dirgid,"x",tok_t::SYSONLY,
351 "%Return UNIX gid of uri\n"
352 "%Syntax: \\dirgid{uri}\n"
353 "%\n"
354 "%Note that the UNIX gid is different from the HTC one.\n"
355 );
356 TOK_ADD(filesize,"x",tok_t::SYSONLY,
357 "%Return filesize of uri\n"
358 "%Syntax: \\filesize{uri}\n"
359 );
360 TOK_ADD(setperm,"xx",tok_t::SYSONLY,
361 "%Set file permissions of uri\n"
362 "%Syntax: \\setperm{uri}{mode}\n"
363 "%\n"
364 "%Mode is an integer bitmask compliant with fcntl.\n"
365 );
366
367}
diff --git a/src/sh/htc.cc b/src/sh/htc.cc
new file mode 100644
index 0000000..9a87f2c
--- /dev/null
+++ b/src/sh/htc.cc
@@ -0,0 +1,92 @@
1/*************************************************************************
2 *
3 * HTCd - Copyright (C) 1998-2006 Henrik Rydberg
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20#include <sh/htc.h>
21#include <hdb/buffer.h>
22#include <mt/lock.h>
23
24const mstring RCPATH=htchome()+sref("/htc/htc.rc");
25const mstring left="{",right="}";
26static fp_stream mout(stdout),merr(stderr);
27
28static int unbalanced(const sref& in)
29{
30 static const charset tag("{[(");
31 if(in.empty()) return 1;
32 sref s=in.right_first_of(tag);
33 while(s.nempty()) {
34 int p=-1;
35 switch(*s) {
36 case '{': p=s.skip(cset_braces); break;
37 case '[': p=s.skip(cset_indices); break;
38 case '(': p=s.skip(cset_para); break;
39 }
40 if(p<0) return 1;
41 s=s.adv(p).right_first_of(tag);
42 }
43 return 0;
44}
45
46main(int argc,char* argv[]) try
47{
48 NODELOCK(USERMAP);
49 HTC htc(ms_empty);
50 htc_user user(htc.toks);
51 htc_req req(htc,user.toks); req.uri=Cwd();
52 Env env(htc.ops,req,XSYSTEM);
53 if(argc>1) {
54 for(int i=2;i<argc;i++) env.xpush(left+sref(argv[i])+right);
55 mstring buffer; LoadBuffer(buffer,argv[1]);
56 if(*buffer=='#') buffer.erase(0,buffer.find('\n')+1);
57 env.eval(mout,buffer,1);
58 }
59 else {
60 mstring buffer,line;
61 if(buffer.load(RCPATH.c_str())>=0) {
62 Env e(env,user.toks,RCPATH);
63 mstream m;
64 e.parse(m,buffer);
65 }
66 while(!feof(stdin)) {
67 merr<<"htc>";
68 buffer.clear();
69 while(!feof(stdin)&&unbalanced(buffer)) {
70 getline(line,stdin);
71 buffer.append(line);
72 buffer+='\n';
73 }
74 try {
75 env.parse(mout,buffer);
76 mout<<"\n";
77 }
78 catch(const merror_t& e) {
79 merr<<e.desc<<"\n";
80 }
81 }
82 }
83 return 0;
84}
85catch(const merror_t& e) {
86 merr<<"ERROR: ["<<e.desc<<"]\n";
87 return -1;
88}
89catch(...) {
90 merr<<"ERROR: [FATAL]\n";
91 return -1;
92}
diff --git a/src/sh/htc.h b/src/sh/htc.h
new file mode 100644
index 0000000..b566176
--- /dev/null
+++ b/src/sh/htc.h
@@ -0,0 +1,77 @@
1/*************************************************************************
2 *
3 * HTCd - Copyright (C) 1998-2006 Henrik Rydberg
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20#ifndef HTCH
21#define HTCH
22
23#include <sh/user.h>
24#include <lang/env.h>
25#include <mt/config.h>
26
27///////////////////////////////////////////////////
28
29mstring Cwd();
30
31const mstring USERMAP=htchome()+sref("/htc/users.hdb");
32
33///////////////////////////////////////////////////
34
35struct HTC : public Lang {
36 fp_stream syslog;
37 mstring docroot,username;
38 mstring host,domain,mailer;
39 IPnode node;
40 int port;
41
42 HTC(const sref& root);
43 ~HTC();
44
45 void setHost(const sref& s);
46 void setDomain(const sref& s);
47 void setPort(int p);
48 void setMailer(const sref& s);
49};
50
51///////////////////////////////////////////////////
52
53struct htc_user {
54 tokmap toks;
55
56 htc_user(tokmap& p);
57};
58
59///////////////////////////////////////////////////
60
61struct htc_req : public req_env {
62 mstring group;
63 user_t user;
64
65 HTC* htc() { return (HTC*)glob; }
66
67 htc_req(HTC& g,tokmap& p);
68};
69
70inline htc_req* Req(Env& env) { return (htc_req*)env.req; }
71inline const sref& DocRoot(Env& env) { return Req(env)->htc()->docroot; }
72inline mstring DocPath(Env& env,const sref& uri) { return DocRoot(env)+env.URI(uri); }
73
74///////////////////////////////////////////////////
75
76#endif
77
diff --git a/src/sh/main.cc b/src/sh/main.cc
new file mode 100644
index 0000000..4926b77
--- /dev/null
+++ b/src/sh/main.cc
@@ -0,0 +1,129 @@
1/*************************************************************************
2 *
3 * HTCd - Copyright (C) 1998-2006 Henrik Rydberg
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20#include <sh/htc.h>
21#include <pwd.h>
22#include <sys/stat.h>
23#include <sys/utsname.h>
24
25const mstring PREFSMAP=htchome()+sref("/htc/prefs.hdb");
26const mstring SYSLOG=htchome()+sref("/log/htc.log");
27
28static fp_stream mout(stdout),merr(stderr);
29
30///////////////////////////////////////////////////
31
32mstring Cwd() {
33 static char buf[1024];
34 mstring cwd=getcwd(buf,1024);
35 cwd+='/';
36 return cwd;
37}
38
39///////////////////////////////////////////////////
40
41static void OpenUSERS(dbmap& db)
42{
43 db.Open(USERMAP,1);
44 if(db.Tables()==0) for(int i=0;i<user_tabs;i++) db.InsertTable(i,user_tab[i]);
45}
46
47static void OpenPREFS(dbmap& db)
48{
49 db.Open(PREFSMAP,1);
50 if(db.Tables()==0) for(int i=0;i<prefs_tabs;i++) db.InsertTable(i,prefs_tab[i]);
51}
52
53htc_user::htc_user(tokmap& p) : toks(p)
54{
55 OpenUSERS(DBRef(toks,USERS_tag,ms_empty,tok_t::SYSONLY)->db);
56 OpenPREFS(DBRef(toks,PREFS_tag,ms_empty,tok_t::SYSONLY)->db);
57}
58
59///////////////////////////////////////////////////
60
61htc_req::htc_req(HTC& g,tokmap& p) : req_env(g,p)
62{
63 user.reset();
64}
65
66///////////////////////////////////////////////////
67
68void envAddFile(tokmap& map);
69void envAddConvert(tokmap& map);
70void envAddDates(tokmap& map);
71void envAddUser(tokmap& map) throw(merror_t);
72void envAddTree(tokmap& map);
73void envAddSys(tokmap& map);
74void envAddNet(tokmap& map);
75
76///////////////////////////////////////////////////
77
78HTC::HTC(const sref& root):
79 syslog(fopen(SYSLOG.c_str(),"a+"))
80{
81 docroot=root; if(docroot.back()=='/') docroot=docroot.popb();
82 username=getpwuid(getuid())->pw_name;
83
84 envAddFile(toks);
85 envAddConvert(toks);
86 envAddDates(toks);
87 envAddUser(toks);
88 envAddTree(toks);
89 envAddSys(toks);
90 envAddNet(toks);
91}
92
93///////////////////////////////////////////////////
94
95HTC::~HTC()
96{
97 fclose(syslog.fp);
98}
99
100///////////////////////////////////////////////////
101
102void HTC::setHost(const sref& s)
103{
104 host=s;
105 if(!Lookup(node,host)) THROW("sys: host "<<host<<" not listed in nameserver");
106}
107
108///////////////////////////////////////////////////
109
110void HTC::setDomain(const sref& s)
111{
112 domain=s;
113}
114
115///////////////////////////////////////////////////
116
117void HTC::setPort(int p)
118{
119 port=p;
120}
121
122///////////////////////////////////////////////////
123
124void HTC::setMailer(const sref& s)
125{
126 mailer=s;
127}
128
129///////////////////////////////////////////////////
diff --git a/src/sh/net.cc b/src/sh/net.cc
new file mode 100644
index 0000000..dc03901
--- /dev/null
+++ b/src/sh/net.cc
@@ -0,0 +1,122 @@
1/*************************************************************************
2 *
3 * HTCd - Copyright (C) 1998-2006 Henrik Rydberg
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20#include <sh/htc.h>
21
22/////////////////////////////////////////////////////////////////
23
24TOK_IMPL(sethost)
25{
26 Req(env)->htc()->setHost(env[0]);
27}
28TOK_IMPL(setdomain)
29{
30 Req(env)->htc()->setDomain(env[0]);
31}
32TOK_IMPL(setport)
33{
34 Req(env)->htc()->setPort(atoi(env[0]));
35}
36TOK_IMPL(setmailer)
37{
38 Req(env)->htc()->setMailer(env[0]);
39}
40
41/////////////////////////////////////////////////////////////////
42
43TOK_IMPL(HOST) {
44 out<<Req(env)->htc()->host;
45}
46
47TOK_IMPL(HOSTIP) {
48 out<<Req(env)->htc()->node.ip;
49}
50
51TOK_IMPL(DOMAIN) {
52 out<<Req(env)->htc()->domain;
53}
54
55TOK_IMPL(ROOT) {
56 out<<Req(env)->htc()->username;
57 if(Req(env)->htc()->domain.size()) out<<"@"<<Req(env)->htc()->domain;
58}
59
60TOK_IMPL(ADMIN) {
61 out<<Req(env)->htc()->username;
62 if(Req(env)->htc()->domain.size()) out<<"@"<<Req(env)->htc()->domain;
63}
64
65TOK_IMPL(port)
66{
67 out<<Req(env)->htc()->port;
68}
69
70/////////////////////////////////////////////////////////////
71
72void envAddNet(tokmap& T)
73{
74 TOK_ADD(sethost,"x",tok_t::SYSONLY,
75 "%Set host name\n"
76 "%Syntax: \\sethost{host}\n"
77 );
78 TOK_ADD(setdomain,"x",tok_t::SYSONLY,
79 "%Set default domain\n"
80 "%Syntax: \\setdomain{domain}\n"
81 );
82 TOK_ADD(setport,"x",tok_t::SYSONLY,
83 "%Set host port number\n"
84 "%Syntax: \\setport{port}\n"
85 );
86 TOK_ADD(setmailer,"x",tok_t::SYSONLY,
87 "%Set mail program path\n"
88 "%Syntax: \\setmailer{path}\n"
89 );
90
91 /////////////////////////////////////////////////////////////
92
93 TOK_ADD(HOST,"",tok_t::PUBLIC,
94 "%Host name\n"
95 "%Syntax: \\HOST\n"
96 );
97
98 TOK_ADD(HOSTIP,"",tok_t::PUBLIC,
99 "%Host IP address\n"
100 "%Syntax: \\HOSTIP\n"
101 );
102
103 TOK_ADD(DOMAIN,"",tok_t::PUBLIC,
104 "%Default domain\n"
105 "%Syntax: \\DOMAIN\n"
106 );
107
108 TOK_ADD(ROOT,"",tok_t::PUBLIC,
109 "%htcroot email address\n"
110 "%Syntax: \\ROOT\n"
111 );
112
113 TOK_ADD(ADMIN,"",tok_t::PUBLIC,
114 "%admin email address\n"
115 "%Syntax: \\ADMIN\n"
116 );
117
118 TOK_ADD(port,"",tok_t::PUBLIC,
119 "%Host port number\n"
120 "%Syntax: \\port\n"
121 );
122}
diff --git a/src/sh/string.cc b/src/sh/string.cc
new file mode 100644
index 0000000..8075a5b
--- /dev/null
+++ b/src/sh/string.cc
@@ -0,0 +1,32 @@
1/*************************************************************************
2 *
3 * HTCd - Copyright (C) 1998-2006 Henrik Rydberg
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20#include <htc.h>
21#include <mset.h>
22
23static mstring empty;
24
25TOK_IMPL(tolower) {mstring s=env[0];s.tolower();out<<s;}
26TOK_IMPL(toupper) {mstring s=env[0];s.toupper();out<<s;}
27
28void envAddString(tokmap& T)
29{
30 TOK_ADD(tolower,1,0,tok_t::PUBLIC,"%(s)");
31 TOK_ADD(toupper,1,0,tok_t::PUBLIC,"%(s)");
32}
diff --git a/src/sh/sys.cc b/src/sh/sys.cc
new file mode 100644
index 0000000..b70991b
--- /dev/null
+++ b/src/sh/sys.cc
@@ -0,0 +1,152 @@
1/*************************************************************************
2 *
3 * HTCd - Copyright (C) 1998-2006 Henrik Rydberg
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20#include <sh/htc.h>
21#include <mime/mime.h>
22#include <mt/lookup.h>
23#include <mt/issue.h>
24#include <mt/dates.h>
25#include <unistd.h>
26
27////////////////////////////////////////////
28
29TOK_IMPL(sleep) { sleep(atoi(env[0])); }
30TOK_IMPL(throw) { THROW(env[0]); }
31
32////////////////////////////////////////////
33
34TOK_IMPL(sync) { dbmap::Sync(); }
35
36////////////////////////////////////////////
37
38TOK_IMPL(gethost) {
39 IPnode node; if(Lookup(node,env[0])) out<<node.name; else out<<"UNKNOWN";
40}
41
42////////////////////////////////////////////
43
44TOK_IMPL(mail) {
45 mswrite ms;
46 if(env[0].size()<2) return;
47 ms<<"From: "; encodeHeader(ms,mime_default,env[3]); ms<<" <"<<env[0]<<">\n";
48
49 //if(env[1].nempty()) ms<<"Reply-To: "<<env[1]<<"\n";
50 //!! neat simple hack - never used except as should be
51 if(env[1].nempty()) ms<<"To: "<<env[1]<<"\n";
52
53 ms<<"Date: "<<httpTime(atoi(env[4]))<<"\n";
54 ms<<"Subject: "; encodeHeader(ms,mime_default,env[5]); ms<<"\n";
55 ms<<"MIME-Version: 1.0\n";
56 ms<<"Content-Transfer-Encoding: Quoted-Printable\n";
57 ms<<"Content-Type: "<<env[6]<<"\n";
58 mswrite body; encodeQP(body,env[7]);
59 ms<<"Content-Length: "<<body.str().size()<<"\n";
60 ms<<"\n";
61 ms<<body.str();
62 HTC* htc=Req(env)->htc();
63 if(htc->mailer.size()) {
64 issue_t cmd(htc->mailer+sref(" ")+env[2]);
65 mstream m;
66 cmd.run(m,ms.str());
67 htc->syslog<<"["<<time(0)<<"][mail]["<<env[2]<<"]\n";
68 }
69 else {
70 htc->syslog<<"["<<time(0)<<"][NOT SET]["<<env[2]<<"]\n";
71 htc->syslog<<"-----------------------------------------\n";
72 htc->syslog<<ms.str()<<"\n";
73 htc->syslog<<"=========================================\n";
74 }
75 htc->syslog.flush();
76}
77
78////////////////////////////////////////////
79
80TOK_IMPL(issue) {
81 HTC* htc=Req(env)->htc();
82 htc->syslog<<"["<<time(0)<<"][issue]["<<env[0]<<"]\n";
83 htc->syslog.flush();
84 issue_t cmd(DocPath(env,env[0]));
85 cmd.run(out,env[1]);
86 htc->syslog<<"["<<time(0)<<"][finish]["<<env[0]<<"]\n";
87 htc->syslog.flush();
88}
89
90//////////////////////////////////////////////////////////
91
92void envAddSys(tokmap& T)
93{
94 TOK_ADD(sleep,"x",tok_t::SYSONLY,
95 "%Sleep for seconds\n"
96 "%Syntax: \\sleep{t}\n"
97 "%\n"
98 "%This one works just like the UNIX command\n"
99 );
100 TOK_ADD(throw,"x",tok_t::SYSONLY,
101 "%Throw an exception\n"
102 "%Syntax: \\throw{text}\n"
103 "%\n"
104 "%Throw a, for the HTC system, standard error\n"
105 "%expection, which also many of the built-in\n"
106 "%do. Enables well-behaved error handling.\n"
107 );
108
109 /////////////////////////////////////////////////////////////
110
111 TOK_ADD(sync,"",tok_t::SYSONLY,
112 "%Syncronize all open writable databases\n"
113 "%Syntax: \\sync\n"
114 "%\n"
115 "%Use in crontab only.\n"
116 );
117
118 /////////////////////////////////////////////////////////////
119
120 TOK_ADD(gethost,"x",tok_t::SYSONLY,
121 "%Lookup hostname on nameserver\n"
122 "%Syntax: \\gethost{IP address}\n"
123 "%\n"
124 "%Normally performed automatically by the server.\n"
125 );
126
127 /////////////////////////////////////////////////////////////
128
129 TOK_ADD(mail,"xxxxxxxx",tok_t::SYSONLY,
130 "%System mail\n"
131 "%Syntax: \\mail{from}{replyto}{to}{fromname}{date}{subject}{mime}{body}\n"
132 "%\n"
133 "%This mail command can do almost anything, so be careful!\n"
134 "%Usually there are several htc commands simplifying the use\n"
135 "%of this one.\n"
136 );
137
138 /////////////////////////////////////////////////////////////
139
140 TOK_ADD(issue,"xx",tok_t::SYSONLY,
141 "%Issue piped command\n"
142 "%Syntax: \\issue{uri}{stdin}\n"
143 "%\n"
144 "%Pipes stdin to cmd and output stdout.\n"
145 "%An extremely powerful command that may be used\n"
146 "%to run external programs via the web.\n"
147 "%\n"
148 "%Note that the normal uri handling is performed.\n"
149 );
150
151 /////////////////////////////////////////////////////////////
152}
diff --git a/src/sh/tree.cc b/src/sh/tree.cc
new file mode 100644
index 0000000..0ec8f16
--- /dev/null
+++ b/src/sh/tree.cc
@@ -0,0 +1,304 @@
1/*************************************************************************
2 *
3 * HTCd - Copyright (C) 1998-2006 Henrik Rydberg
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20#include <sh/htc.h>
21#include <sh/user.h>
22#include <hdb/buffer.h>
23#include <http/http.h>
24#include <mt/dates.h>
25#include <sys/stat.h>
26
27const mstring index_tag="index.htc";
28const mstring sindex_tag="/index.htc";
29const mstring htc_mime="text/x-htc";
30const mstring htx_mime="text/x-htx";
31const mstring html_mime="text/html";
32
33const mstring uri_tag="stat.URI";
34const mstring refer_tag="stat.REFER";
35const mstring parent_tag="stat.PARENT";
36const mstring mime_tag="stat.MIME";
37
38const mstring mod_tag="stat.MOD";
39const mstring mtime_tag="stat.LASTMOD";
40const mstring uid_tag="stat.UID";
41const mstring gid_tag="stat.GID";
42const mstring size_tag="stat.SIZE";
43
44const mstring alias_tag="stat.ALIAS";
45const mstring banner_tag="stat.BANNER";
46
47const mstring xclear_tag="stat.X.CLEAR";
48const mstring xcookie_tag="stat.X.COOKIE";
49const mstring domain_tag="stat.X.DOMAIN";
50const mstring user_tag="stat.X.USER";
51const mstring xcache_tag="stat.X.CACHE";
52
53const mstring xmod_tag="stat.XMOD";
54
55/////////////////////////////////////////////////////////////////
56
57TOK_IMPL(alias) {
58 mstring acc;
59 Env nenv(env,XSYSTEM,env.pwd);
60 acc=env.arg(0)->expr;
61 nenv.sloc(alias_tag,acc);
62}
63
64TOK_IMPL(banner) {
65 mstring acc1;
66 Env nenv(env,XSYSTEM,env.pwd);
67 swrite sw(acc1);
68 nenv.parse(sw,env.arg(0));
69 acc1+=' '; acc1+=env.arg(1)->expr;
70 nenv.sloc(banner_tag,acc1);
71}
72
73/////////////////////////////////////////////////////////////////
74
75TOK_IMPL(clearance) {
76 mstring acc;
77 Env nenv(env,XSYSTEM,env.pwd);
78 swrite sw(acc);
79 nenv.parse(sw,env.arg(0));
80 sref first,rest=acc;
81 while(Split(first,rest))
82 if(first==root_tag) THROW("user: ROOT group not allowed in clearance");
83 nenv.sloc(xclear_tag,acc);
84}
85
86TOK_IMPL(clearance_cookie) {
87 mstring acc1,acc2;
88 Env nenv(env,XSYSTEM,env.pwd);
89 swrite sw1(acc1);
90 nenv.parse(sw1,env.arg(0));
91 swrite sw2(acc2);
92 nenv.parse(sw2,env.arg(1));
93 acc1+=' '; acc1+=acc2;
94 nenv.sloc(xcookie_tag,acc1);
95}
96
97TOK_IMPL(clearance_domain) {
98 mstring acc;
99 Env nenv(env,XSYSTEM,env.pwd);
100 swrite sw(acc);
101 nenv.parse(sw,env.arg(0));
102 nenv.sloc(domain_tag,acc);
103}
104
105TOK_IMPL(clearance_user) {
106 mstring acc;
107 Env nenv(env,XSYSTEM,env.pwd);
108 swrite sw(acc);
109 nenv.parse(sw,env.arg(0));
110 nenv.sloc(user_tag,acc);
111}
112
113TOK_IMPL(cache) {
114 mstring acc;
115 Env nenv(env,XSYSTEM,env.pwd);
116 swrite sw(acc);
117 nenv.parse(sw,env.arg(0));
118 nenv.sloc(xcache_tag,acc);
119}
120
121/////////////////////////////////////////////////////////////////
122
123inline int reachable(const sref& uri)
124{
125 static const mstring sys_tag="/sys/";
126 static const mstring bin_tag="/bin/";
127 static const mstring htc_tag="/htc/";
128 static const mstring sccs_tag="/SCCS/";
129 static const mstring cvs_tag="/CVS/";
130 if(uri.right_last(sindex_tag)==sindex_tag) return 0;
131 if(uri.find(sys_tag)>=0) return 0;
132 if(uri.find(bin_tag)>=0) return 0;
133 if(uri.find(htc_tag)>=0) return 0;
134 if(uri.find(sccs_tag)>=0) return 0;
135 if(uri.find(cvs_tag)>=0) return 0;
136 return 1;
137}
138
139TOK_IMPL(staturi) {
140 struct stat fs; int ok=0;
141 mstring parent,refer,uri=env.URI(env[0]);
142 if(reachable(uri)) {
143 refer=uri; parent=refer.leftand_last('/');
144 if(refer.back()=='/') { refer+=index_tag; parent=parent.popb().leftand_last('/'); }
145 int s=stat(DocPath(env,refer).c_str(),&fs);
146 if(s>=0) {
147 if(fs.st_mode&24576) {
148 uri+='/'; refer=uri+index_tag;
149 s=stat(DocPath(env,refer).c_str(),&fs);
150 }
151 if(s>=0) {
152 const sref* pmime=file2mime(refer);
153 mstring mime=pmime?*pmime:http_mime_default;
154 mstring index=refer.leftand_last('/')+index_tag;
155
156 Env nenv(env);
157 nenv.aloc(uri_tag,uri);
158 nenv.aloc(refer_tag,refer);
159 nenv.aloc(parent_tag,parent);
160 nenv.aloc(mime_tag,mime);
161
162 nenv.aloc(mod_tag,itoa(fs.st_mode));
163 nenv.aloc(uid_tag,itoa(fs.st_uid));
164 nenv.aloc(gid_tag,itoa(fs.st_gid));
165 nenv.aloc(size_tag,itoa(fs.st_size));
166 nenv.aloc(mtime_tag,itoa(fs.st_mtime));
167
168 nenv.aloc(alias_tag,ms_empty);
169 nenv.aloc(banner_tag,ms_empty);
170
171 nenv.aloc(xclear_tag,root_tag);
172 nenv.aloc(xcookie_tag,ms_empty);
173 nenv.aloc(domain_tag,ms_empty);
174 nenv.aloc(user_tag,ms_empty);
175 nenv.aloc(xcache_tag,ms_empty);
176
177 nenv.aloc(xmod_tag,itoa(time(0)));
178
179 mstring buffer;
180 if(mime==htc_mime||mime==htx_mime||mime==html_mime) {
181 LoadBuffer(buffer,DocPath(nenv,refer));
182 try {
183 Env e(nenv,XINIT,refer);
184 mstream m;
185 e.parse(m,buffer);
186 }
187 catch(const merror_t& e) {
188 THROW(refer<<": "<<e.desc);
189 }
190 }
191 if(mime!=htc_mime&&nenv.gloc(xclear_tag)==root_tag) {
192 if(buffer.load(DocPath(nenv,index).c_str())>=0) {
193 try {
194 Env e(nenv,XINIT,index);
195 mstream m;
196 e.parse(m,buffer);
197 nenv.sloc(alias_tag,ms_empty);
198 nenv.sloc(banner_tag,ms_empty);
199 }
200 catch(const merror_t& e) {
201 THROW(index<<": "<<e.desc);
202 }
203 }
204 }
205 nenv.parse(out,env.arg(1));
206 ok=1;
207 }
208 }
209 }
210 if(!ok) env.parg(out,2);
211}
212
213/////////////////////////////////////////////////////////////////
214
215void envAddTree(tokmap& T)
216{
217 TOK_ADD(alias,"r",tok_t::INIT,
218 "%Set alias used in sitemap\n"
219 "%Syntax: \\alias{name}\n"
220 "%\n"
221 "%If set, the URI appears in the automatic tree system.\n"
222 );
223
224 TOK_ADD(banner,"rr",tok_t::INIT,
225 "%Set banner used in layout\n"
226 "%Syntax: \\banner{height}{body}\n"
227 "%\n"
228 "%If set in index file, all URI descendants will use it.\n"
229 );
230
231 ///////////////////////////////////////////////////////
232
233 TOK_ADD(clearance,"r",tok_t::INIT,
234 "%Set clearance\n"
235 "%Syntax: \\clearance{group list}\n"
236 "%\n"
237 "%A user must have clearance to all groups in order\n"
238 "%to get access.\n"
239 );
240 TOK_ADD(clearance_domain,"r",tok_t::INIT,
241 "%Restrict clearance to domain\n"
242 "%Syntax: \\clearance.domain{domain list}\n"
243 "%\n"
244 "%A user must have clearance to at least one domain\n"
245 "%in order to get access.\n"
246 );
247 TOK_ADD(clearance_cookie,"rr",tok_t::INIT,
248 "%Restrict by cookie\n"
249 "%Syntax: \\clearance.cookie{name}{value}\n"
250 "%\n"
251 "%A user must have the cookie set to get access.\n"
252 );
253 TOK_ADD(clearance_user,"r",tok_t::INIT,
254 "%Restrict by user\n"
255 "%Syntax: \\clearance.user{user list}\n"
256 "%\n"
257 "%A user must appear in the list in order to get access.\n"
258 );
259
260 ///////////////////////////////////////////////////////
261
262 TOK_ADD(cache,"r",tok_t::INIT,
263 "%Set cache time in seconds\n"
264 "%Syntax: \\cache{t}\n"
265 "%\n"
266 "%If set, normal output is cached for the given time.\n"
267 "%\n"
268 "%There are a number of advantages of caching, the most\n"
269 "%pronounced being server load. Appropriate cache time\n"
270 "%is crucial to get a smooth server.\n"
271 );
272
273 ///////////////////////////////////////////////////////
274
275 TOK_ADD(staturi,"xr?",tok_t::SYSONLY,
276 "%Retrieve STAT and INIT information for URI\n"
277 "%Syntax: \\staturi{uri}{body}<else>\n"
278 "%\n"
279 "%Do body if a reference to uri is found.\n"
280 "%In the body environment, the record stat. is set\n"
281 "%with the following variables:\n"
282 "%\n"
283 "%URI the canonized URI\n"
284 "%REFER the file uri it refers to\n"
285 "%PARENT the parent uri\n"
286 "%MOD the file mode bits (unix)\n"
287 "%UID the file uid (unix)\n"
288 "%GID the file gid (unix)\n"
289 "%SIZE the file size (unix)\n"
290 "%LASTMOD the file modification time (unix)\n"
291 "%MIME the MIME type\n"
292 "%ALIAS alias used in tree\n"
293 "%X.CLEAR clerarance\n"
294 "%X.COOKIE cookie clearance\n"
295 "%X.DOMAIN domain clearance\n"
296 "%X.USER user clearance\n"
297 "%X.CACHE cache time in seconds\n"
298 "%\n"
299 "%The X. variables are inherited from index.htc\n"
300 "%if X.CLEAR remains equal to ROOT after init.\n"
301 "%\n"
302 "%Unreachable directories: /sys/, /bin/, /htc/, /SCCS/ and /CVS/.\n"
303 );
304}
diff --git a/src/sh/user.cc b/src/sh/user.cc
new file mode 100644
index 0000000..94285ef
--- /dev/null
+++ b/src/sh/user.cc
@@ -0,0 +1,445 @@
1/*************************************************************************
2 *
3 * HTCd - Copyright (C) 1998-2006 Henrik Rydberg
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20#include <sh/htc.h>
21
22int allow(const sref& s,const sref& grp,time_t now,int rootok)
23{
24 if(grp.empty()) return 1;
25 int n=s.find(':');
26 sref a=s.left(n);
27 if(rootok>=0&&a==root_tag) return rootok;
28 else if(grp==root_tag||a!=grp) return 0;
29 n=(a=s.past(n,1)).find(':'); sref b=a.past(n,1); a=a.left(n);
30 return (a.empty()||atoi(a)<=now)&&(b.empty()||now<atoi(b));
31}
32
33////////////////////////////////////////////////////////////////////////
34
35user_t::user_t(const user_t& us) : list(user_tabs)
36{
37 for(int i=0;i<user_tabs;i++) list[i]=us.list[i];
38}
39
40void user_t::operator=(const user_t& us)
41{
42 list.resize(user_tabs);
43 for(int i=0;i<user_tabs;i++) list[i]=us.list[i];
44}
45
46void user_t::reset()
47{
48 list.resize(user_tabs);
49 uid()=itoa(0);
50 group()=itoa(0);
51 fail()=itoa(0);
52 pin().clear();
53 alias().clear();
54 email().clear();
55 name().clear();
56 last()=itoa(0);
57 lastin()=lastin_def;
58 access().clear();
59}
60
61int user_t::allow(const sref& grp,time_t now,int rootok)
62{
63 sref first,rest=access();
64 while(Split(first,rest)) if(::allow(first,grp,now,rootok)) return 1;
65 return 0;
66}
67
68int user_t::allow_list(const sref& grps,time_t now,int rootok)
69{
70 sref first,rest=grps;
71 while(Split(first,rest)) if(!allow(first,now,rootok)) return 0;
72 return 1;
73}
74
75void user_t::add(const sref& grp)
76{
77 sref first,rest=access();
78 while(Split(first,rest)) if(first.left_first(':')==grp.left_first(':')) return;
79 mstring clear=grp;
80 if(clear.find(':')<0) { clear+=':'; clear+=itoa(time(0)); }
81 if(access().nempty()) access()+=' '; access()+=clear;
82}
83
84void user_t::add_list(const sref& grps) {
85 sref first,rest=grps;
86 while(Split(first,rest)) add(first);
87}
88
89void user_t::rem(const sref& grp)
90{
91 mstring m;
92 sref first,rest=access();
93 while(Split(first,rest))
94 if(first.left_first(':')!=grp) { if(m.nempty()) m+=' '; m+=first; }
95 access()=m;
96}
97
98void user_t::rem_list(const sref& grps)
99{
100 sref first,rest=grps;
101 while(Split(first,rest)) rem(first);
102}
103
104////////////////////////////////////////////////////////////////////////
105
106static dbmap* GetDB(Env& env,const sref& name)
107{
108 dbref_t* p=(dbref_t*)env.toks->get(name);
109 if(!env.is_clear(p)||!p->is_dbref()) THROW("htc: could not find system db "<<name);
110 p->db.remap();
111 return &p->db;
112}
113
114static int FindUser(Env& env,const sref& name)
115{
116 dbmap* users=GetDB(env,USERS_tag);
117 for(int i=0;i<users->size();i++) {
118 if(users->at(i,user_alias)==name) return atoi(users->at(i,user_uid));
119 sref first,rest=users->at(i,user_email);
120 while(Split(first,rest)) if(eqn(first,name)) return atoi(users->at(i,user_uid));
121 }
122 return 0;
123}
124
125////////////////////////////////////////////////////////////////////////
126
127TOK_IMPL(setgroup) { Req(env)->group=First(env[0]); }
128TOK_IMPL(group) { out<<Req(env)->group; }
129
130TOK_IMPL(getgroups) {
131 dbmap* users=GetDB(env,USERS_tag);
132 mset m;
133 for(int i=0;i<users->size();i++) {
134 sref first,rest=users->at(i,user_access);
135 while(Split(first,rest)) m.insert(first.left_first(':'));
136 }
137 out<<m;
138}
139
140////////////////////////////////////////////////////////////////////////
141
142TOK_IMPL(getuser) {
143 out<<FindUser(env,env[0]);
144}
145
146TOK_IMPL(setuser) {
147 dbmap* users=GetDB(env,USERS_tag);
148 int row=users->Find(env[0]);
149 if(row>=0) users->Get(row,Req(env)->user.list);
150 else Req(env)->user.reset();
151}
152
153TOK_IMPL(remuser) {
154 dbmap* users=GetDB(env,USERS_tag);
155 int row=users->Find(env[0]);
156 if(row>=0) users->Rem(row);
157}
158
159TOK_IMPL(newuser) {
160 static const charset namends("*@.+");
161 user_t user;
162 sref first,rest=env[0];
163 Split(first,rest);
164 user.group()=first.left_first(':');
165 do user.add(first);
166 while(Split(first,rest));
167 user.pin()=Random(4);
168 user.email()=env[1];
169 rest=env[1]; while(Split(first,rest)) if(FindUser(env,first)) { out<<0; return; }
170 mstring tag,alias=env[1].left_first_of(namends);
171 while(FindUser(env,alias+tag)) tag=itoa(atoi(tag)+1);
172 user.alias()=alias+tag;
173 user.name()=env[2];
174 dbmap* users=GetDB(env,USERS_tag);
175 if(users->empty()) user.uid()=itoa(1);
176 else user.uid()=itoa(atoi(users->at(users->size()-1,user_uid))+1);
177 int row=users->Insert(user.list,1);
178 if(row<0) THROW("htc: could not add user - record not unique");
179 out<<user.uid();
180}
181
182//////////////////////////////////////////////////////////////////////////
183
184TOK_IMPL(user_id) { out<<Req(env)->user.uid(); }
185TOK_IMPL(user_group) { out<<Req(env)->user.group(); }
186TOK_IMPL(user_access) { out<<Req(env)->user.access(); }
187TOK_IMPL(user_clear) {
188 sref first,rest=Req(env)->user.access(); int n=0;
189 while(Split(first,rest)) { if(n++) out.put(' '); out<<first.left_first(':'); }
190}
191
192TOK_IMPL(user_fail) { out<<Req(env)->user.fail(); }
193TOK_IMPL(user_pin) { out<<Req(env)->user.pin(); }
194TOK_IMPL(user_alias) { out<<Req(env)->user.alias(); }
195TOK_IMPL(user_email) { out<<First(Req(env)->user.email()); }
196TOK_IMPL(user_emails) { out<<Req(env)->user.email(); }
197TOK_IMPL(user_name) { out<<Req(env)->user.name(); }
198TOK_IMPL(user_last) { out<<Req(env)->user.last(); }
199TOK_IMPL(user_lastin) { out<<Req(env)->user.lastin(); }
200
201//////////////////////////////////////////////////////////////////////////
202
203TOK_IMPL(user_group_set) { Req(env)->user.group()=env[0]; }
204TOK_IMPL(user_access_add) { Req(env)->user.add_list(env[0]); }
205TOK_IMPL(user_access_rem) { Req(env)->user.rem_list(env[0]); }
206TOK_IMPL(user_fail_set) { Req(env)->user.fail()=env[0]; }
207TOK_IMPL(user_pin_set) { Req(env)->user.pin()=env[0]; }
208TOK_IMPL(user_alias_set) { Req(env)->user.alias()=env[0]; }
209TOK_IMPL(user_emails_set) { Req(env)->user.email()=env[0]; }
210TOK_IMPL(user_name_set) { Req(env)->user.name()=env[0]; }
211TOK_IMPL(user_last_set) { Req(env)->user.last()=env[0]; }
212TOK_IMPL(user_lastin_set) { Req(env)->user.lastin()=env[0]; }
213
214//////////////////////////////////////////////////////////
215
216TOK_IMPL(user_update) {
217 htc_req* htc=Req(env);
218 int uid=atoi(htc->user.uid());
219 int who=FindUser(env,htc->user.alias());
220 if(who&&who!=uid) return;
221 sref first,rest=htc->user.email();
222 while(Split(first,rest)) {
223 who=FindUser(env,first);
224 if(who&&who!=uid) return;
225 }
226 dbmap* users=GetDB(env,USERS_tag);
227 int row=users->Find(htc->user.uid());
228 if(row>=0) users->Set(row,htc->user.list);
229}
230
231//////////////////////////////////////////////////////////
232
233TOK_IMPL(su) {
234 htc_req* htc=Req(env);
235 user_t tmp(htc->user);
236 dbmap* users=GetDB(env,USERS_tag);
237 int row=users->Find(env[0]);
238 if(row>=0) {
239 try {
240 users->Get(row,htc->user.list);
241 env.parg(out,1);
242 htc->user=tmp;
243 }
244 catch(...) {
245 htc->user=tmp;
246 throw;
247 }
248 }
249 else env.parg(out,2);
250}
251
252//////////////////////////////////////////////////////////
253
254void envAddUser(tokmap& T) throw(merror_t)
255{
256 TOK_ADD(setgroup,"x",tok_t::SYSONLY,
257 "%Set current group\n"
258 "%Syntax: \\setgroup{group}\n"
259 "%\n"
260 "%Nop function; only for logging and structure.\n"
261 );
262 TOK_ADD(group,"",tok_t::PUBLIC,
263 "%Get current group\n"
264 "%Syntax: \\group\n"
265 "%\n"
266 "%Nop function; only for logging and structure.\n"
267 );
268
269 TOK_ADD(getgroups,"",tok_t::PUBLIC,
270 "%Get all groups\n"
271 "%Syntax: \\getgroups\n"
272 "%\n"
273 "%Scans users db for all groups used\n"
274 );
275
276 ///////////////////////////////////////////////////
277
278 TOK_ADD(getuser,"x",tok_t::SYSONLY,
279 "%Get user ID\n"
280 "%Syntax: \\getuser{alias/email}\n"
281 "%\n"
282 "%Returns the uid if found, or zero if not found\n"
283 );
284 TOK_ADD(setuser,"x",tok_t::SYSONLY,
285 "%Set current user\n"
286 "%Syntax: \\setuser{uid}\n"
287 );
288 TOK_ADD(remuser,"x",tok_t::SYSONLY,
289 "%Remove user\n"
290 "%Syntax: \\remuser{uid}\n"
291 );
292 TOK_ADD(newuser,"xxx",tok_t::SYSONLY,
293 "%Add a new user\n"
294 "%Syntax: \\newuser{clear}{email}{name}\n"
295 "%\n"
296 "%Returns the new uid if successful, otherwise zero.\n"
297 );
298
299 ///////////////////////////////////////////////////
300
301 TOK_ADD(user_id,"",tok_t::PUBLIC,
302 "%Get uid of current user\n"
303 "%Syntax: \\user.id\n"
304 );
305 TOK_ADD(user_group,"",tok_t::PUBLIC,
306 "%Get group of current user\n"
307 "%Syntax: \\user.group\n"
308 );
309 TOK_ADD(user_access,"",tok_t::PUBLIC,
310 "%Get access of current user\n"
311 "%Syntax: \\user.access\n"
312 );
313 TOK_ADD(user_clear,"",tok_t::PUBLIC,
314 "%Get clearance of current user\n"
315 "%Syntax: \\user.clear\n"
316 "%\n"
317 "%This is a compiled list, without the time info.\n"
318 );
319 TOK_ADD(user_fail,"",tok_t::PUBLIC,
320 "%Get fail number of current user\n"
321 "%Syntax: \\user.fail\n"
322 );
323 TOK_ADD(user_pin,"",tok_t::SYSONLY,
324 "%Get pin of current user\n"
325 "%Syntax: \\user.pin\n"
326 );
327 TOK_ADD(user_alias,"",tok_t::PUBLIC,
328 "%Get alias of current user\n"
329 "%Syntax: \\user.alias\n"
330 );
331 TOK_ADD(user_email,"",tok_t::PUBLIC,
332 "%Get email of current user\n"
333 "%Syntax: \\user.email\n"
334 "%\n"
335 "%Note that the email list may contain several addresses;\n"
336 "%this function returns the first in the list.\n"
337 );
338 TOK_ADD(user_emails,"",tok_t::PUBLIC,
339 "%Get all email addresses of current user\n"
340 "%Syntax: \\user.emails\n"
341 );
342 TOK_ADD(user_name,"",tok_t::PUBLIC,
343 "%Get name of current user\n"
344 "%Syntax: \\user.name\n"
345 );
346 TOK_ADD(user_last,"",tok_t::PUBLIC,
347 "%Get last time logged in of current user\n"
348 "%Syntax: \\user.last\n"
349 );
350 TOK_ADD(user_lastin,"",tok_t::PUBLIC,
351 "%Get last IP address of current user\n"
352 "%Syntax: \\user.lastin\n"
353 );
354
355 ///////////////////////////////////////////////////
356
357 TOK_ADD(user_group_set,"x",tok_t::SYSONLY,
358 "%Set group of current user\n"
359 "%Syntax: \\user.group.set{group}\n"
360 "%\n"
361 "%Note that the changes take effect after a \\user.update\n"
362 );
363 TOK_ADD(user_access_add,"x",tok_t::SYSONLY,
364 "%Add access to current user\n"
365 "%Syntax: \\user.access.add{group:start:stop}\n"
366 "%\n"
367 "%The :start:stop part may be omitted, in which case\n"
368 "%a start value of now, and a stop value of nil is set.\n"
369 "%\n"
370 "%In case of several group strings, they are all added.\n"
371 "%\n"
372 "%Note that the changes take effect after a \\user.update\n"
373 );
374 TOK_ADD(user_access_rem,"x",tok_t::SYSONLY,
375 "%Remove access from current user\n"
376 "%Syntax: \\user.access.rem{group}\n"
377 "%\n"
378 "%In case of several groups, they are all removed.\n"
379 "%\n"
380 "%Note that the changes take effect after a \\user.update\n"
381 );
382 TOK_ADD(user_fail_set,"x",tok_t::SYSONLY,
383 "%Set fail number of current user\n"
384 "%Syntax: \\user.fail.set{fail}\n"
385 "%\n"
386 "%Note that the changes take effect after a \\user.update\n"
387 );
388 TOK_ADD(user_pin_set,"x",tok_t::SYSONLY,
389 "%Set pin of current user\n"
390 "%Syntax: \\user.pin.set{pin}\n"
391 "%\n"
392 "%Note that the changes take effect after a \\user.update\n"
393 );
394 TOK_ADD(user_alias_set,"x",tok_t::SYSONLY,
395 "%Set alias of current user\n"
396 "%Syntax: \\user.alias.set{alias}\n"
397 "%\n"
398 "%Note that the changes take effect after a \\user.update\n"
399 );
400 TOK_ADD(user_emails_set,"x",tok_t::SYSONLY,
401 "%Set all email addresses of current user\n"
402 "%Syntax: \\user.emails.set{emails}\n"
403 "%\n"
404 "%Note that the changes take effect after a \\user.update\n"
405 );
406 TOK_ADD(user_name_set,"x",tok_t::SYSONLY,
407 "%Set name of current user\n"
408 "%Syntax: \\user.name.set{name}\n"
409 "%\n"
410 "%Note that the changes take effect after a \\user.update\n"
411 );
412 TOK_ADD(user_last_set,"x",tok_t::SYSONLY,
413 "%Set last time logged in of current user\n"
414 "%Syntax: \\user.last.set{last}\n"
415 "%\n"
416 "%Note that the changes take effect after a \\user.update\n"
417 );
418 TOK_ADD(user_lastin_set,"x",tok_t::SYSONLY,
419 "%Set last IP address of current user\n"
420 "%Syntax: \\user.lastin.set{addr}\n"
421 "%\n"
422 "%Note that the changes take effect after a \\user.update\n"
423 );
424
425 ///////////////////////////////////////////////////
426
427 TOK_ADD(user_update,"",tok_t::SYSONLY,
428 "%Update the current user\n"
429 "%Syntax: \\user.update\n"
430 "%\n"
431 "%All changes a synchronous and immediately available.\n"
432 );
433
434 ///////////////////////////////////////////////////
435
436 TOK_ADD(su,"xr?",tok_t::SYSONLY,
437 "%Set user temporary\n"
438 "%Syntax: \\su{uid}{body}<else>\n"
439 "%\n"
440 "%If set successfully, evaluates body, otherwise <else>.\n"
441 );
442
443 ///////////////////////////////////////////////////
444
445}
diff --git a/src/sh/user.h b/src/sh/user.h
new file mode 100644
index 0000000..cc00e21
--- /dev/null
+++ b/src/sh/user.h
@@ -0,0 +1,92 @@
1/*************************************************************************
2 *
3 * HTCd - Copyright (C) 1998-2006 Henrik Rydberg
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20#ifndef USERH
21#define USERH
22
23#include <lang/env.h>
24#include <mt/lookup.h>
25
26/////////////////////////////////////////////////////////
27
28const mstring root_tag="ROOT";
29const mstring lastin_def="0.0.0.0";
30
31const mstring USERS_tag="USERS";
32const mstring PREFS_tag="PREFS";
33const mstring TREE_tag="TREE";
34
35const int user_tabs=10,user_uid=0,user_alias=4,user_email=5,user_access=9;
36const mstring user_tab[user_tabs]={
37 "UID","GROUP","FAIL","PIN","ALIAS","EMAIL","NAME","LAST","LASTIN","ACCESS"
38};
39
40const int prefs_tabs=8;
41const mstring prefs_tab[prefs_tabs]={
42 "ID","EXT","ROOM","URL","POSIT","NOTE","ABSTRACT","LASTMOD"
43};
44
45const int tree_tabs=17;
46const mstring tree_tab[tree_tabs]={
47 "URI","REFER","PARENT","MIME",
48 "MOD","UID","GID","SIZE","LASTMOD",
49 "ALIAS","BANNER",
50 "X.CLEAR","X.COOKIE","X.DOMAIN","X.USER","X.CACHE",
51 "XMOD"
52};
53
54int allow(const sref& s,const sref& grp,time_t now,int rootok=0);
55
56struct user_t {
57 spile list;
58
59 user_t() : list(user_tabs) {}
60 user_t(const user_t& us);
61
62 void operator=(const user_t&);
63
64 mstring& uid() { return list[0]; }
65 mstring& group() { return list[1]; }
66 mstring& fail() { return list[2]; }
67 mstring& pin() { return list[3]; }
68 mstring& alias() { return list[4]; }
69 mstring& email() { return list[5]; }
70 mstring& name() { return list[6]; }
71 mstring& last() { return list[7]; }
72 mstring& lastin() { return list[8]; }
73 mstring& access() { return list[9]; }
74
75 void reset();
76 int allow(const sref& grp,time_t now,int rootok=0);
77 int allow_list(const sref& grps,time_t now,int rootok=0);
78 // rootok<0 -> ignore special root handling (new; should not interfere)
79 // rootok==0 -> root not allowed here
80 // rootok>0 -> root always allowed here
81
82 void add(const sref& grp);
83 void add_list(const sref& grps);
84 void rem(const sref& grp);
85 void rem_list(const sref& grps);
86};
87
88/////////////////////////////////////////////////////////
89
90void envAddUser(tokmap& T) throw(merror_t);
91
92#endif