17
|
1 #!/usr/local/bin/ruby19
|
16
|
2 # -*- coding: euc-jp -*-
|
0
|
3 #
|
|
4 # Associative Scheduling Table - after5
|
18
|
5 # (C)2003, 2004, 2006, 2008, 2012 by HIROSE Yuuji [yuuji@gentei.org]
|
|
6 # $Id: after5.rb,v 1.18 2012/04/01 05:18:57 yuuji Exp yuuji $
|
|
7 # $HGid$
|
|
8 # Last modified Sun Apr 1 16:41:56 2012 on firestorm
|
0
|
9 # See http://www.gentei.org/~yuuji/software/after5/
|
|
10 # このスクリプトはEUCで保存してください。
|
|
11
|
|
12 require 'kconv'
|
17
|
13 require 'nkf'
|
0
|
14
|
|
15 $charset = 'EUC-JP'
|
|
16
|
|
17 class HTMLout
|
|
18 def contenttype(type = "text/html", charset = $charset)
|
|
19 sprintf "Content-type: %s; charset=%s\n\n", type, charset
|
|
20 end
|
|
21 def initialize(title = "Document")
|
|
22 @title = title
|
|
23 @eltstack = []
|
|
24 end
|
|
25 def resetstack()
|
|
26 @eltstack = []
|
|
27 end
|
|
28 def head(title = @title, css = "style.css")
|
|
29 sprintf <<__EOS__, title, css
|
|
30 <html>
|
|
31 <head>
|
|
32 <title>%s</title>
|
|
33 <link rel="stylesheet" type="text/css" href="%s">
|
|
34 </head>
|
|
35 __EOS__
|
|
36 end
|
|
37
|
|
38 def startelement(elt, attrs = {}, nl = true)
|
|
39 attr = ""
|
|
40 if attrs.is_a?(Hash)
|
|
41 for k in attrs.keys
|
|
42 attr += " %s=\"%s\"" % [k, attrs[k]]
|
|
43 end
|
|
44 end
|
|
45 @eltstack.push(elt)
|
|
46 sprintf "<%s%s>%s", elt, attr, nl ? "\n" : ""
|
|
47 end
|
|
48 def endelement(elt = nil, nl = true)
|
|
49 if elt
|
|
50 x = elt
|
|
51 @eltstack.pop
|
|
52 else
|
|
53 x = @eltstack.pop
|
|
54 end
|
|
55 sprintf "</%s>%s", x, nl ? "\n" : ""
|
|
56 end
|
|
57 def element(elt, attrs = nil, nl = nil)
|
|
58 attr = ""
|
|
59 lf = nl ? "\n" : ""
|
|
60 if attrs.is_a?(Hash)
|
|
61 for k in attrs.keys
|
|
62 attr += " %s=\"%s\"" % [k, attrs[k]]
|
|
63 end
|
|
64 end
|
|
65 body = yield
|
|
66 sprintf "<%s%s>%s%s%s</%s>%s", elt, attr, lf, body, lf, elt, lf
|
|
67 end
|
|
68 def elementln(elt, attr=nil)
|
|
69 body = yield
|
|
70 element(elt, attr, true){body}
|
|
71 end
|
|
72 def a(href, anchor = nil, attrs = {})
|
|
73 attr = attrs
|
|
74 attr['href'] = href
|
|
75 element("a", attr){
|
|
76 anchor or href
|
|
77 }
|
|
78 end
|
|
79 def p(msg, attrs=nil)
|
|
80 element("p", attrs){msg}
|
|
81 end
|
|
82 def text(name, value='', size=nil, maxlength=nil)
|
|
83 sprintf "<input type=\"text\" name=\"%s\" value=\"%s\"%s%s>",
|
|
84 name, value,
|
|
85 size ? " size=\"%s\""%size.to_s : '',
|
|
86 maxlength ? " maxlength=\"%s\""%maxlength.to_s : ''
|
|
87 end
|
|
88 def hidden(name, value='')
|
|
89 sprintf "<input type=\"hidden\" name=\"%s\" value=\"%s\">", name, value
|
|
90 end
|
|
91 def radio(name, value, text='', checked=nil)
|
|
92 sprintf "<input type=\"radio\" name=\"%s\" value=\"%s\"%s>%s",
|
|
93 name, value, checked ? " checked" : "", text
|
|
94 end
|
|
95 def checkbox(name, value, text='', checked=nil)
|
|
96 sprintf "<input type=\"checkbox\" name=\"%s\" value=\"%s\"%s>%s",
|
|
97 name, value, checked ? " checked" : "", text
|
|
98 end
|
|
99 def submit(name, value, text='')
|
|
100 sprintf "<input type=\"submit\" name=\"%s\" value=\"%s\">%s\n",
|
|
101 name, value, text
|
|
102 end
|
|
103 def reset(name, value, text='')
|
|
104 sprintf "<input type=\"reset\" name=\"%s\" value=\"%s\">\n",
|
|
105 name, value, text
|
|
106 end
|
|
107 def submit_reset(name)
|
|
108 submit(name, "GO")+reset(name, "Reset")
|
|
109 end
|
|
110
|
2
|
111 def select(name, range, selected=nil)
|
|
112 #start = (b<e ? b : e)
|
|
113 #last = (b>e ? b : e)
|
|
114 c=0
|
0
|
115 "<select name=\"#{name}\">\n" + \
|
2
|
116 range.collect{|i|
|
3
|
117 value = (i.is_a?(Array) ? i[1] : i).to_s
|
|
118 sprintf "<option%s%s>%s%s</option>",
|
|
119 (selected.to_s==value.to_s) ? " selected" : "",
|
|
120 i.is_a?(Array) ? " value=\"%s\"" % value : '',
|
|
121 i.is_a?(Array) ? i[0] : i.to_s,
|
2
|
122 (c+=1)%6==0 ? "\n" : ''
|
0
|
123 }.join + \
|
|
124 "\n</select>\n"
|
|
125 end
|
|
126 end
|
14
|
127 class TEXTout
|
|
128 def isBlock(elt)
|
|
129 /\b(tr|[udo]l|p|div)\b/i =~ elt
|
|
130 end
|
|
131 def isEOC(elt)
|
|
132 /\bt[dh]\b/i =~ elt
|
|
133 end
|
|
134 def eoelem(elt)
|
|
135 r = ""
|
|
136 r << "\n" if isBlock(elt)
|
|
137 r << " " if isEOC(elt)
|
|
138 r
|
|
139 end
|
|
140 def contenttype(type = "text/plain", charset = $charset)
|
|
141 ### sprintf "Content-type: %s; charset=%s\n\n", type, charset
|
|
142 ""
|
|
143 end
|
|
144 def initialize(title = "Document")
|
|
145 @title = title
|
|
146 @eltstack = []
|
|
147 end
|
|
148 def resetstack()
|
|
149 @eltstack = []
|
|
150 end
|
|
151 def head(title = @title, css = "style.css")
|
|
152 sprintf <<__EOS__, title, css
|
|
153 ===== [[[ %s ]]] =====
|
|
154 __EOS__
|
|
155 end
|
|
156
|
|
157 def startelement(elt, attrs = {}, nl = true)
|
|
158 attr = ""
|
|
159 x = sprintf "%s", " "*@eltstack.length
|
|
160 @eltstack.push(elt)
|
|
161 x
|
|
162 end
|
|
163 def endelement(elt = nil, nl = true)
|
|
164 if elt
|
|
165 x = elt
|
|
166 @eltstack.pop
|
|
167 else
|
|
168 x = @eltstack.pop
|
|
169 end
|
|
170 eoelem(x)
|
|
171 end
|
|
172 def element(elt, attrs = nil, nl = nil)
|
|
173 attr = ""
|
|
174 lf = nl ? "\n" : ""
|
|
175 body = yield
|
|
176 #sprintf "<%s%s>%s%s%s</%s>%s", elt, attr, lf, body, lf, elt, lf
|
|
177 sprintf "%s%s", body, eoelem(elt)
|
|
178 end
|
|
179 def elementln(elt, attr=nil)
|
|
180 body = yield
|
|
181 sprintf "%s\n", body
|
|
182 end
|
|
183 def a(href, anchor = nil, attrs = {})
|
|
184 attr = attrs
|
|
185 attr['href'] = href
|
|
186 # sprintf "%s\n", href
|
|
187 anchor
|
|
188 end
|
|
189 def p(msg, attrs=nil)
|
|
190 element("p", attrs){msg}
|
|
191 end
|
|
192 def text(name, value='', size=nil, maxlength=nil)
|
|
193 ""
|
|
194 end
|
|
195 def hidden(name, value='')
|
|
196 ""
|
|
197 end
|
|
198 def radio(name, value, text='', checked=nil)
|
|
199 ""
|
|
200 end
|
|
201 def checkbox(name, value, text='', checked=nil)
|
|
202 ""
|
|
203 end
|
|
204 def submit(name, value, text='')
|
|
205 ""
|
|
206 end
|
|
207 def reset(name, value, text='')
|
|
208 ""
|
|
209 end
|
|
210 def submit_reset(name)
|
|
211 ""
|
|
212 end
|
|
213 def select(name, range, selected=nil)
|
|
214 ""
|
|
215 end
|
|
216 end
|
0
|
217
|
|
218 class PasswdMgr
|
|
219 def initialize(name, mode=0640)
|
|
220 require 'dbm'
|
|
221 @pdb = DBM.open(name, mode)
|
|
222 end
|
|
223 def checkpasswd(user, passwd)
|
|
224 if @pdb[user] then
|
|
225 @pdb[user] == passwd.crypt(@pdb[user])
|
|
226 end
|
|
227 end
|
|
228 def setpasswd(user, passwd)
|
|
229 salt = [rand(64),rand(64)].pack("C*").tr("\x00-\x3f","A-Za-z0-9./")
|
|
230 @pdb[user] = passwd.crypt(salt)
|
|
231 end
|
|
232 def userexist?(user)
|
|
233 @pdb[user] ? true : false
|
|
234 end
|
|
235 def getpasswd(user)
|
|
236 @pdb[user]
|
|
237 end
|
|
238 def delete(user)
|
|
239 @pdb.delete(user)
|
|
240 end
|
|
241 def close()
|
|
242 @pdb.close()
|
|
243 end
|
|
244 def newpasswd(length)
|
|
245 srand(Time.now.to_i)
|
|
246 left = "qazxswedcvfrtgb12345"
|
|
247 right = "yhnmjuik.lop;/67890-"
|
|
248 array = [left, right]
|
|
249 (1..length).collect{|i|
|
|
250 a = array[i%array.length]
|
|
251 a[rand(a.length), 1]
|
|
252 }.join('')
|
|
253 end
|
|
254 def users()
|
|
255 @pdb.keys
|
|
256 end
|
|
257 private :newpasswd
|
|
258 def setnewpasswd(user, length=8)
|
|
259 newp = newpasswd(length)
|
|
260 setpasswd(user, newp)
|
|
261 newp
|
|
262 end
|
|
263 end
|
|
264
|
|
265 class ScheduleDir
|
|
266 def initialize(dir = "s")
|
|
267 @dir = dir
|
|
268 @schedulefile = "sched"
|
|
269 @usermapdir = File.join(@dir, "usermap")
|
|
270 @usermap = mkusermap()
|
|
271 @groupmapdir = File.join(@dir, "groupmap")
|
|
272 @groupmap = mkgroupmap()
|
|
273 @crondir = File.join(@dir, "crondir")
|
|
274
|
|
275 end
|
|
276 def mkusermap()
|
|
277 map = {}
|
|
278 unless test(?d, @usermapdir)
|
|
279 mkdir_p(@usermapdir)
|
|
280 end
|
|
281 Dir.foreach(@usermapdir){|u|
|
|
282 next if /^\./ =~ u
|
|
283 newu = ''
|
|
284 u.split('').each{|c| # for security wrapping
|
12
|
285 newu << c[0].chr if %r,[-A-Z0-9/+_.@],i =~ c
|
0
|
286 }
|
|
287 u = newu
|
|
288 map[u] = {}
|
17
|
289 d = File.join(@usermapdir, u).untaint
|
0
|
290 next unless test(?d, d)
|
|
291 Dir.foreach(d){|attr|
|
|
292 next if /^\./ =~ attr
|
12
|
293 attr.untaint if /^[A-Z_][-A-Z_0-9]*$/i =~ attr
|
17
|
294 file = File.join(@usermapdir, u, attr).untaint
|
0
|
295 next unless test(?s, file) && test(?r, file)
|
17
|
296 map[u][attr] = IO.readlines(file).join.toeuc.strip
|
0
|
297 }
|
|
298 }
|
|
299 map
|
|
300 end
|
|
301 def putuserattr(user, attr, text)
|
|
302 # if text==nil, remove it
|
|
303 d = File.join(@usermapdir, user)
|
|
304 Dir.mkdir(d) unless test(?d, d)
|
|
305 file = File.join(d, attr)
|
|
306 begin
|
2
|
307 unless @usermap[user]
|
|
308 @usermap[user] = {}
|
|
309 mkdir_p(d) unless test(?d, d)
|
|
310 end
|
0
|
311 @usermap[user][attr] = text
|
|
312 if text==nil
|
|
313 File.unlink(file)
|
|
314 else
|
|
315 open(file, "w"){|w| w.puts @usermap[user][attr]}
|
|
316 end
|
|
317 rescue
|
|
318 return nil
|
|
319 end
|
|
320 return {attr => text}
|
|
321 end
|
|
322 def getuserattr(user, attr)
|
|
323 # Should we distinguish between attribute is nil and "" ?
|
|
324 if @usermap.has_key?(user) && @usermap[user][attr].is_a?(String) &&
|
|
325 @usermap[user][attr] > ''
|
|
326 return @usermap[user][attr]
|
|
327 else
|
|
328 return nil
|
|
329 end
|
|
330 end
|
|
331
|
|
332 def nickname(user)
|
|
333 if @usermap.has_key?(user) && @usermap[user]['name'].is_a?(String) &&
|
|
334 @usermap[user]['name'] > ''
|
|
335 return @usermap[user]['name']
|
|
336 else
|
|
337 return user.sub(/@.*/, '')
|
|
338 end
|
|
339 end
|
|
340 def setnickname(user, nickname)
|
|
341 putuserattr(user, 'name', nickname)
|
|
342 end
|
|
343
|
|
344 #
|
|
345 # make group map
|
|
346 def collectmembers(gname)
|
|
347 @visitedgroup=[] unless @visitedgroup
|
|
348 return [] unless @visitedgroup.grep(gname).empty?
|
|
349 @visitedgroup.push(gname)
|
|
350 mdir = File.join(@groupmapdir, gname, 'members')
|
|
351 return [] unless test(?d, mdir)
|
|
352 members = []
|
|
353 Dir.foreach(mdir){|item|
|
|
354 next if /^\./ =~ item
|
|
355 item.untaint
|
|
356 next unless test(?f, File.join(mdir, item))
|
|
357 if /.+@.+/ =~ item
|
|
358 members << item
|
|
359 else
|
|
360 members += collectmembers(item)
|
|
361 end
|
|
362 }
|
|
363 @visitedgroup.pop
|
|
364 members
|
|
365 end
|
|
366 def mkgroupmap()
|
|
367 map = {}
|
|
368 return map unless test(?d, @groupmapdir)
|
|
369 @visitedgroup = []
|
|
370 Dir.foreach(@groupmapdir){|g|
|
|
371 next if /^\./ =~ g
|
|
372 newg = ''
|
|
373 next unless /^[-a-z0-9_.]+$/i =~ g
|
|
374 #g.untaint ## untaintじゃだめだ。map{g} のkeyがtaintedになっちゃうよ
|
|
375 gg = '' # for security wrapping
|
|
376 g.split('').each{|c| gg << c[0].chr if c != '`'}
|
|
377 g = gg
|
|
378 map[gg] = {}
|
17
|
379 d = File.join(@groupmapdir, g).untaint
|
0
|
380 next unless test(?d, d)
|
|
381 # get group name
|
17
|
382 gnf = File.join(d, 'name').untaint
|
0
|
383 if test(?r, gnf) && test(?s, gnf)
|
17
|
384 n = IO.readlines(gnf)[0].to_s.toeuc.strip
|
0
|
385 map[g]['name'] = if n > '' then n else g end
|
|
386 else
|
|
387 map[g]['name'] = g
|
|
388 end
|
|
389 # get administrators
|
|
390 #
|
17
|
391 gad = File.join(d, 'admin').untaint
|
0
|
392 map[g]['admin'] = []
|
|
393 if test(?d, gad)
|
|
394 Dir.foreach(gad){|a|
|
|
395 # administrator should be a person (not group)
|
|
396 next unless /@/ =~ a
|
|
397 map[g]['admin'] << a
|
|
398 }
|
|
399 end
|
|
400 # collect members
|
|
401 #map[g]['members'] = collectmembers(g)
|
17
|
402 memd = File.join(d, 'members').untaint
|
0
|
403 map[g]['members'] = []
|
|
404 if test(?d, memd)
|
|
405 Dir.foreach(memd){|a|
|
|
406 next if /^\./ =~ a
|
|
407 map[g]['members'] << a
|
|
408 }
|
|
409 end
|
|
410 }
|
|
411 map
|
|
412 end
|
|
413 def groupmap()
|
|
414 @groupmap
|
|
415 end
|
|
416 def groups()
|
|
417 @groupmap.keys
|
|
418 end
|
2
|
419 def addgroup(group, users, remove=nil, role='members')
|
|
420 grp = groups.grep(group)[0] # group may be tainted, using kept name
|
|
421 return nil unless grp
|
0
|
422 for u in users
|
|
423 next unless account_exists(u)
|
17
|
424 mdir = File.join(@groupmapdir, grp, role).untaint
|
|
425 file = File.join(mdir, u).untaint
|
0
|
426 if remove
|
|
427 @groupmap[grp][role].delete(u)
|
|
428 File.unlink(file) if test(?e, file)
|
|
429 else
|
|
430 @groupmap[grp][role] << u
|
|
431 @groupmap[grp][role].uniq
|
|
432 Dir.mkdir(file) unless test(?d, mdir)
|
|
433 open(file, "w"){|x|} # Touch it
|
|
434 end
|
|
435 end
|
|
436 grp
|
|
437 end
|
|
438 def setgroupname(grp, name)
|
|
439 return nil unless @groupmap[grp]
|
17
|
440 mdir = File.join(@groupmapdir, grp).untaint
|
|
441 nfile = File.join(mdir, 'name').untaint
|
0
|
442 @groupmap[grp]['name'] = name
|
|
443 if grp == name
|
|
444 # remove the name file because it is default name
|
|
445 File.unlink(nfile) if test(?e, nfile)
|
|
446 else
|
|
447 Dir.mkdir(mdir) unless test(?d, mdir)
|
|
448 open(nfile, "w"){|n| n.puts name.to_s.strip}
|
|
449 end
|
|
450 name
|
|
451 end
|
|
452 def creategroup(grp, grpname="", admin=[])
|
2
|
453 grpptnOK = /^[-A-Z0-9._:!$%,]+$/i
|
|
454 return nil unless grpptnOK =~ grp
|
|
455 gg = ''
|
|
456 grp.split('').each{|c| gg << c[0].chr if c =~ grpptnOK}
|
|
457 grp = gg
|
0
|
458 gdir = File.join(@groupmapdir, grp)
|
|
459 mkdir_p(gdir) # Should not care errors here
|
|
460 Dir.mkdir(File.join(gdir, "admin"))
|
|
461 Dir.mkdir(File.join(gdir, "members"))
|
|
462 @groupmap[grp] = {}
|
|
463 if grpname == ''
|
|
464 @groupmap[grp]['name'] = grp
|
|
465 else
|
|
466 setgroupname(grp, grpname)
|
|
467 end
|
|
468 @groupmap[grp]['members'] = []
|
|
469 @groupmap[grp]['admin'] = []
|
|
470 addgroup(grp, admin)
|
|
471 addgroup(grp, admin, nil, 'admin')
|
|
472 return @groupmap[grp]
|
|
473 end
|
|
474 def createuser(user, email = nil)
|
|
475 return nil unless /@/ =~ user
|
|
476 return nil if %r@[\/()\;|,$\%^!\#&\'\"]@ =~ user
|
|
477 email = email || user
|
|
478 @usermap[user] = {}
|
|
479 Dir.mkdir(File.join(@usermapdir, user))
|
|
480 putuserattr(user, 'email', email)
|
|
481 end
|
|
482 def deleteuser(user)
|
|
483 return nil unless @usermap[user]
|
|
484 begin
|
|
485 @usermap[user] # return value
|
|
486 ensure
|
|
487 @usermap.delete(user)
|
|
488 rm_rf(File.join(@usermapdir, user))
|
|
489 rm_rf(File.join(@groupmapdir, "*/members/#{user}"))
|
|
490 rm_rf(File.join(@crondir, "[1-9]*-*-*/#{user}"))
|
|
491 rm_rf(File.join(@dir, "[1-9]*/[0-9][0-9]/[0-9][0-9]/[0-9]???/#{user}"))
|
|
492 end
|
|
493 end
|
|
494 def destroygroup(grp)
|
|
495 return nil unless @groupmap[grp]
|
|
496 begin
|
|
497 @groupmap[grp] # return value
|
|
498 ensure
|
|
499 @groupmap.delete(grp)
|
|
500 rm_rf(File.join(@groupmapdir, grp))
|
|
501 rm_rf(File.join(@groupmapdir, "*/members/#{grp}"))
|
|
502 rm_rf(File.join(@crondir, "[1-9]*-*-*/#{grp}"))
|
|
503 rm_rf(File.join(@dir, "[1-9]*/[0-9][0-9]/[0-9][0-9]/[0-9]???/#{grp}"))
|
|
504 end
|
|
505 end
|
|
506 def rm_rf(path)
|
6
|
507 path.untaint
|
0
|
508 if (list = Dir.glob(path))[0]
|
|
509 for p in list
|
2
|
510 p.untaint
|
0
|
511 system "/bin/rm -rf \"#{p}\""
|
|
512 end
|
|
513 cleanup_files(list[0])
|
|
514 end
|
|
515 end
|
|
516 def account_exists(instance)
|
|
517 if /@/ =~ instance
|
|
518 true
|
|
519 else
|
|
520 ! @groupmap.select{|k, v| k==instance}.empty?
|
|
521 end
|
|
522 end
|
|
523 def ismember(user, grouporuser)
|
|
524 return true if user==grouporuser
|
|
525 if @groupmap[grouporuser]
|
|
526 @groupmap[grouporuser]['members'].grep(user)[0]
|
|
527 end
|
|
528 end
|
2
|
529 def isuser(user)
|
|
530 @usermap[user] && @usermap.keys.grep(user)[0]
|
|
531 end
|
0
|
532 def isgroup(grp)
|
|
533 @groupmap[grp]
|
|
534 end
|
|
535 def isadmin(user, group)
|
|
536 @groupmap[group] and @groupmap[group]['admin'].grep(user)[0]
|
|
537 end
|
|
538 def members(grp)
|
|
539 @groupmap[grp] and ####################@groupmap[grp]['members']
|
|
540 collectmembers(grp)
|
|
541 end
|
|
542 def admins(grp)
|
|
543 @groupmap[grp] and @groupmap[grp]['admin']
|
|
544 end
|
|
545 def groupname(grp)
|
|
546 @groupmap[grp] && @groupmap[grp]['name']
|
|
547 end
|
2
|
548 def name2group(name)
|
|
549 @groupmap.find{|g, v| v.is_a?(Hash) && v['name']==name}
|
|
550 end
|
|
551 def day_all(d, user=nil, personalonly = nil)
|
0
|
552 y, m, d = d.scan(%r,(\d\d\d\d+)/(\d+)/(\d+),)[0]
|
|
553 #daydir = File.join(@dir, "%04d"%y.to_i, "%02d"%m.to_i, "%02d"%d.to_i)
|
|
554 daydir = File.join("s", "%04d"%y.to_i, "%02d"%m.to_i, "%02d"%d.to_i)
|
|
555 sched = {}
|
|
556 return sched unless test(?d, daydir)
|
|
557 Dir.foreach(daydir) {|time|
|
|
558 next if /^\./ =~ time
|
|
559 next unless /^\d\d\d\d$/ =~ time
|
|
560 time.untaint
|
|
561 t = File.join(daydir, time)
|
|
562 next unless test(?d, t)
|
|
563 sched[time] = {}
|
|
564 Dir.foreach(t){|who|
|
|
565 next if /^\./ =~ who
|
|
566
|
|
567 visible = false
|
|
568 #next unless /@/ =~ who # user must be as user@do.ma.in
|
|
569 next unless account_exists(who)
|
7
|
570 ## next if personalonly && who != user #2004/1/16
|
0
|
571 who.untaint
|
|
572 dir = File.join(t, who)
|
|
573 next unless test(?d, dir) && test(?x, dir)
|
|
574 pub = File.join(dir, 'pub')
|
7
|
575 if test(?f, pub) && test(?r, pub) && test(?s, pub) &&
|
|
576 !personalonly # unneccessary if personal mode
|
0
|
577 if IO.readlines(pub)[0].to_i > 0
|
|
578 visible = true
|
|
579 end
|
|
580 end
|
|
581
|
|
582
|
|
583 if ismember(user, who) || visible
|
|
584 sched[time][who] = {}
|
|
585 file = File.join(dir, @schedulefile)
|
|
586 if test(?s, file) && test(?r, file) && test(?s, file)
|
17
|
587 sched[time][who]['sched'] = IO.readlines(file).join.toeuc.chomp!
|
6
|
588 sched[time][who]['regtime'] = File.stat(file).mtime
|
0
|
589 end
|
|
590 sched[time][who]['pub'] = visible
|
|
591 end
|
|
592 } #|who|
|
|
593 sched.delete(time) if sched[time].empty?
|
|
594 }
|
|
595 sched
|
|
596 end
|
|
597
|
|
598 def scheduledir(user, y, m, d, time)
|
|
599 sprintf("%s/%04d/%02d/%02d/%04d/%s",
|
|
600 @dir, y.to_i, m.to_i, d.to_i, time.to_i, user)
|
|
601 end
|
|
602 def schedulefile(user, y, m, d, time)
|
|
603 File.join(scheduledir(user, y, m, d, time), @schedulefile)
|
|
604 end
|
|
605 def mkdir_p(path, mode=0777)
|
|
606 # Do not mkdir `path' for
|
|
607 # absolute paths
|
|
608 # those paths which contains `../'
|
|
609 # for the sake of security reason
|
|
610 return false if %r,\.\./|^/, =~ path
|
|
611 p = 0
|
|
612 i=0
|
|
613 while p=path.index("/", p)
|
|
614 dir = path[0..p].chop
|
|
615 p += 1
|
|
616 break if i > 10 # overprotecting
|
|
617 next if test(?d, dir)
|
|
618 Dir.mkdir(dir, mode)
|
|
619 i += 1
|
|
620 end
|
|
621 Dir.mkdir(path, mode) unless test(?d, path)
|
|
622 end
|
|
623
|
|
624 #
|
|
625 # register schedule for user
|
|
626 #
|
|
627 def register(user, year, month, day, time, text, replace=nil)
|
|
628 # return code: 0 = succesfull new registration
|
|
629 # 1 = succesfull appending registration
|
|
630 dir = scheduledir(user, year, month, day, time)
|
|
631 file = schedulefile(user, year, month, day, time)
|
|
632 ret = 0
|
|
633 um = File.umask(027)
|
|
634 begin
|
|
635 if !replace && test(?s, file)
|
|
636 ret = 1
|
|
637 else
|
|
638 mkdir_p(dir, 0777)
|
|
639 end
|
|
640 ensure
|
|
641 File.umask(um)
|
|
642 end
|
|
643 open(file, replace ? "w" : "a"){|out|out.print text}
|
|
644 return ret
|
|
645 end
|
|
646 def getschedule(user, year, month, day, time)
|
|
647 file = schedulefile(user, year, month, day, time)
|
|
648 if test(?r, file) && test(?s, file)
|
17
|
649 return IO.readlines(file).join.toeuc
|
0
|
650 end
|
|
651 return nil
|
|
652 end
|
|
653 def remove(user, year, month, day, time)
|
|
654 file = schedulefile(user, year, month, day, time)
|
|
655 dir = File.dirname(file)
|
|
656 if test(?r, file) && test(?s, file)
|
|
657 File.unlink(file)
|
|
658 end
|
|
659 for f in Dir.glob(File.join(dir, "*"))
|
|
660 f.untaint
|
|
661 File.unlink(f)
|
|
662 end
|
|
663 Dir.rmdir(dir) if test(?d, dir)
|
|
664 begin
|
|
665 Dir.rmdir(File.dirname(dir))
|
|
666 rescue
|
|
667 end
|
|
668 end
|
|
669 #
|
|
670 # register file
|
|
671 #
|
|
672 def putfile(user, year, month, day, time, file, contents)
|
|
673 scback = @schedulefile
|
|
674 begin
|
|
675 @schedulefile = File.basename(file)
|
|
676 register(user, year, month, day, time, contents, true)
|
|
677 ensure
|
|
678 @schedulefile = scback
|
|
679 end
|
|
680 end
|
|
681 def getfile(user, year, month, day, time, file)
|
|
682 scback = @schedulefile
|
|
683 begin
|
|
684 @schedulefile = File.basename(file)
|
|
685 getschedule(user, year, month, day, time)
|
|
686 ensure
|
|
687 @schedulefile = scback
|
|
688 end
|
|
689 end
|
|
690 def removefile(user, year, month, day, time, file)
|
|
691 dir = scheduledir(user, year, month, day, time)
|
|
692 file = File.join(dir, file)
|
|
693 if test(?e, file)
|
|
694 File.unlink(file)
|
|
695 end
|
|
696 end
|
|
697 #
|
|
698 # registration to crondir
|
|
699 #
|
|
700 def cronlink_file(nt_time, user, y, m, d, time)
|
|
701 subdir = nt_time.strftime("%Y-%m-%d-%H%M/#{user}")
|
|
702 cdir = File.join(@crondir, subdir)
|
|
703 File.join(cdir, sprintf("%04d-%02d-%02d-%04d", y, m, d, time))
|
|
704 end
|
|
705 def register_crondir(nt_time, user, y, m, d, time)
|
|
706 linkfile = cronlink_file(nt_time, user, y, m, d, time)
|
|
707 mkdir_p(File.dirname(linkfile))
|
|
708 scfile = schedulefile(user, y, m, d, time)
|
|
709 if test(?s, scfile)
|
|
710 sclink = File.join("../../..", scfile.sub!(Regexp.quote(@dir+'/'), ''))
|
|
711 File.symlink(sclink, linkfile) unless test(?e, linkfile)
|
|
712 return linkfile
|
|
713 end
|
|
714 return false
|
|
715 end
|
|
716 def remove_crondir(nt_time, user, y, m, d, time)
|
|
717 linkfile = cronlink_file(nt_time, user, y, m, d, time)
|
|
718 scfile = schedulefile(user, y, m, d, time)
|
|
719 if test(?e, linkfile)
|
|
720 File.unlink(linkfile)
|
|
721 begin
|
|
722 dir = linkfile
|
|
723 2.times {|x|
|
|
724 dir = File.dirname(dir)
|
|
725 if Dir.open(dir).collect.length <= 2 # is empty dir
|
|
726 Dir.rmdir(dir)
|
|
727 else
|
|
728 break
|
|
729 end
|
|
730 }
|
|
731 rescue
|
|
732 end
|
|
733 return linkfile
|
|
734 end
|
|
735 return false
|
|
736 end
|
|
737
|
|
738 #
|
|
739 # return the Hash of crondir {user => files}
|
|
740 def notify_list(asof)
|
|
741 slack = 5*60
|
|
742 gomifiles = []
|
|
743 ntl = {}
|
|
744 return ntl unless test(?d, @crondir)
|
|
745 Dir.foreach(@crondir){|datedir|
|
2
|
746 next unless /(\d\d\d\d+)-(\d+)-(\d+)-(\d\d\d\d)/ =~ datedir
|
10
|
747 ##datedir = sprintf("%04d-%02d-%02d-%04d",
|
|
748 ## $1.to_i, $2.to_i, $3.to_i, $4.to_i)
|
|
749 datedir.untaint
|
0
|
750 dd = File.join(@crondir, datedir)
|
|
751 next unless test(?d, dd)
|
|
752 y, m, d, hm = $1.to_i, $2.to_i, $3.to_i, $4.to_i
|
|
753 hh = hm/100 % 60
|
|
754 mm = (hm%100) % 60
|
|
755 t = Time.mktime(y, m, d, hh, mm)
|
|
756 next if t-slack > asof
|
|
757 #
|
|
758 # collect them
|
|
759 Dir.foreach(dd){|user|
|
2
|
760 # next unless /@/ =~ user || isgroup(user)
|
|
761 next if /^\./ =~ user
|
|
762 if isgroup(user)
|
|
763 user = @groupmap.keys.grep(user)[0]
|
|
764 else
|
|
765 user = @usermap.keys.grep(user)[0]
|
|
766 end
|
|
767 next unless user
|
0
|
768 ud = File.join(dd, user)
|
|
769 next unless test(?d, ud)
|
|
770 ntl[user] = {}
|
|
771 Dir.foreach(ud){|date|
|
|
772 next if /^\./ =~ date
|
|
773 unless /(\d\d\d\d+)-(\d+)-(\d+)-(\d\d\d\d)/ =~ date
|
|
774 gomifiles << File.join(ud, date)
|
|
775 next
|
|
776 end
|
13
|
777 #date = sprintf("%04d-%02d-%02d-%04d",
|
|
778 # $1.to_i, $2.to_i, $3.to_i, $4.to_i)
|
|
779 date.untaint
|
0
|
780 f = File.join(ud, date)
|
|
781 if test(?s, f)
|
|
782 ntl[user][date] = {}
|
|
783 ntl[user][date]['file'] = f
|
17
|
784 ntl[user][date]['text'] = IO.readlines(f).toeuc
|
0
|
785 else
|
|
786 File.unlink(f) # symlink points to nonexistent file
|
|
787 end
|
|
788 }
|
|
789 if ntl[user].empty?
|
|
790 # if ud does not contain valid cron symlinks,
|
|
791 # ud had been left badly. Remove it.
|
|
792 ntl.delete(user)
|
|
793 cleanup_files(gomifiles)
|
|
794 end
|
|
795 }
|
|
796 }
|
|
797 ntl
|
|
798 end
|
|
799 #
|
|
800 # cleanup file and directories
|
|
801 def cleanup_crondir(time)
|
|
802 Dir.foreach(@crnondir){|datedir|
|
|
803 dd = File.join(@crondir, datedir)
|
|
804 next unless test(?d, dd)
|
|
805 next unless /(\d\d\d\d+)-(\d+)-(\d+)-(\d\d\d\d)/ =~ dd
|
|
806 y, m, d, hm = $1.to_i, $2.to_i, $3.to_i, $4.to_i
|
|
807 hh = hm/100 % 60
|
|
808 mm = (hm%100) % 60
|
|
809 t = Time.mktime(y, m, d, hh, mm)
|
|
810 if t < time
|
|
811 system "rm -rf #{dd}"
|
|
812 end
|
|
813 }
|
|
814 end
|
|
815 #
|
|
816 # remove files in FILES, and remove parent directory if possible
|
|
817 def cleanup_files(files)
|
|
818 sentinel = File.stat(@dir).ino
|
16
|
819 me = $0.dup.untaint
|
|
820 scriptsuid = File.stat(me).uid
|
0
|
821 for f in files
|
2
|
822 if $SAFE > 0
|
|
823 f.untaint
|
|
824 if test(?e, f) && File.stat(f).uid != scriptsuid
|
|
825 f.taint
|
|
826 end
|
|
827 end
|
|
828 printf "Removing %s\n", f if $DEBUG
|
0
|
829 File.unlink(f) if test(?e, f)
|
|
830 d = f
|
|
831 loop {
|
|
832 d = File.dirname(d)
|
|
833 break if d.length < 2
|
|
834 break if File.stat(d).ino == sentinel
|
|
835 begin
|
|
836 puts "rmdir #{d}" if $DEBUG
|
|
837 Dir.rmdir(d)
|
|
838 rescue
|
|
839 break
|
|
840 end
|
|
841 }
|
|
842 end
|
|
843 end
|
|
844 end
|
|
845
|
|
846 class StringIO<IO
|
|
847 def initialize()
|
|
848 @str=""
|
|
849 end
|
|
850 def foo=(str)
|
|
851 @str = str
|
|
852 end
|
2
|
853 def append(str)
|
|
854 @str = str+@str
|
|
855 end
|
0
|
856 def print(str)
|
|
857 @str << str
|
|
858 end
|
|
859 def puts(str)
|
|
860 @str << str+"\n"
|
|
861 end
|
|
862 def printf(*args)
|
|
863 @str << sprintf(*args)
|
|
864 end
|
|
865 def write(bytes)
|
|
866 print(bytes)
|
|
867 end
|
|
868 def gets()
|
|
869 return nil if @str == ''
|
|
870 p = @str.index(?\n)
|
|
871 if p
|
|
872 r = @str[0..p]
|
|
873 @str=@str[p+1..-1]
|
|
874 else
|
|
875 r = @str
|
|
876 end
|
|
877 return r
|
|
878 end
|
|
879 def readline()
|
|
880 this.gets()
|
|
881 end
|
|
882 def readlines()
|
|
883 r = @str
|
|
884 @str=''
|
|
885 r
|
|
886 end
|
|
887
|
|
888 def p(*obj)
|
|
889 STDOUT.p(*obj)
|
|
890 end
|
|
891 end
|
|
892
|
|
893 class CMDTimeout < Exception
|
|
894 def initialize()
|
|
895 @pw = IO.pipe
|
|
896 @pr = IO.pipe
|
|
897 @pe = IO.pipe
|
|
898 @timeout = false
|
|
899 end
|
|
900 def start(cmd, timeout, mixstderr=false)
|
|
901 if @pid=fork
|
|
902 @pw[0].close
|
|
903 @pr[1].close
|
|
904 @pe[1].close
|
|
905 # puts "parent!"
|
|
906 if @tk=fork
|
|
907 # main
|
|
908 else
|
|
909 @pw[1].close
|
|
910 @pr[0].close
|
|
911 @pe[0].close
|
|
912 trap(:INT){exit 0}
|
|
913 sleep timeout
|
|
914 begin
|
|
915 @timeout = true
|
|
916 STDERR.puts "TIMEOUT"
|
|
917 Process.kill :INT, @pid
|
|
918 rescue
|
|
919 #puts "Already done"
|
|
920 end
|
|
921 exit 0
|
|
922 end
|
|
923 else
|
|
924 # Running this block with pid=@pid
|
|
925 trap(:INT){@timeout = true; exit 0}
|
|
926 @pw[1].close
|
|
927 STDIN.reopen(@pw[0])
|
|
928 @pw[0].close
|
|
929
|
|
930 @pr[0].close
|
|
931 STDOUT.reopen(@pr[1])
|
|
932 if mixstderr
|
|
933 STDERR.reopen(@pr[1])
|
|
934 else
|
|
935 STDERR.reopen(@pe[1])
|
|
936 end
|
|
937 @pr[1].close
|
|
938 @pe[0].close
|
|
939 @pe[1].close
|
|
940
|
15
|
941 exec(*cmd)
|
0
|
942 exit 0
|
|
943 end
|
|
944 return [@pw[1], @pr[0], @pe[0]]
|
|
945 end
|
|
946 def wait()
|
|
947 Process.waitpid(@pid, nil)
|
|
948 end
|
|
949 def close()
|
|
950 @pr.each{|p| p.close unless p.closed?}
|
|
951 @pw.each{|p| p.close unless p.closed?}
|
|
952 @pe.each{|p| p.close unless p.closed?}
|
|
953 begin
|
|
954 Process.kill :INT, @tk
|
|
955 rescue
|
|
956 end
|
|
957 end
|
|
958 def timeout()
|
|
959 @timeout
|
|
960 end
|
|
961 end
|
|
962
|
|
963 class Holiday
|
|
964 def initialize(dir = ".")
|
|
965 @@dir = dir
|
|
966 defined?(@@holiday) || setupHoliday
|
|
967 end
|
|
968 def setupHoliday(file = "holiday")
|
|
969 @@holiday = {}
|
|
970 return unless test(?f, file) && test(?s, file)
|
|
971 IO.foreach(file){|line|
|
17
|
972 line = line.toeuc.strip
|
0
|
973 next if /^#/ =~ line
|
|
974 date, what = line.scan(/(\S+)\s+(.*)/)[0]
|
|
975 if %r,(\d+)/(\d+)/(\d+), =~ date
|
|
976 cdate = sprintf("%d/%d/%d", $1.to_i, $2.to_i, $3.to_i)
|
|
977 @@holiday[cdate] || @@holiday[cdate] = []
|
|
978 @@holiday[cdate] << what
|
|
979 elsif %r,(\d+)/(\d+), =~ date
|
|
980 cdate = sprintf("%d/%d", $1.to_i, $2.to_i)
|
|
981 @@holiday[cdate] || @@holiday[cdate] = []
|
|
982 @@holiday[cdate] << what
|
|
983 elsif %r,(\d+)/(\w+), =~ date
|
|
984 cdate = sprintf("%d/%s", $1.to_i, $2.downcase)
|
|
985 @@holiday[cdate] || @@holiday[cdate] = []
|
|
986 @@holiday[cdate] << what
|
|
987 end
|
|
988 }
|
|
989 end
|
|
990 def isHoliday(y, m, d, wday=nil)
|
|
991 y, m, d = y.to_i, m.to_i, d.to_i
|
|
992 wname = %w[sun mon tue wed thu fri sat]
|
|
993 holiday = @@holiday[sprintf("%d/%d/%d", y, m, d)] ||
|
|
994 @@holiday[sprintf("%d/%d", m, d)]
|
|
995 unless holiday
|
|
996 wday = wname[wday || Time.mktime(y, m, d).wday]
|
|
997 nthweek = (d-1)/7+1
|
|
998 holiday = @@holiday[sprintf("%d/w%d%s", m, nthweek, wday)]
|
|
999 end
|
|
1000 holiday
|
|
1001 end
|
|
1002 def holidays()
|
|
1003 @@holiday
|
|
1004 end
|
|
1005 end
|
|
1006
|
|
1007 class After5
|
|
1008 def initialize()
|
|
1009 @me = File.expand_path($0)
|
|
1010 @mydir, @myname = File.dirname(@me), File.basename(@me)
|
1
|
1011 @mybase = @myname.sub(/\.\w+$/, '')
|
0
|
1012 @mydir.untaint
|
1
|
1013 @mybase.untaint
|
0
|
1014 Dir.chdir @mydir
|
1
|
1015 @myname='a5.cgi' if test(?f, "a5.cgi")
|
0
|
1016 @conf = nil
|
|
1017 @schedulearea = {'rows'=>'4', 'cols'=>'60', 'name'=>'schedule'}
|
|
1018 @oldagent = (%r,Mozilla/4, =~ ENV['HTTP_USER_AGENT'])
|
2
|
1019 @lang = 0
|
14
|
1020 @mailmode = nil
|
7
|
1021 @saveprefsregexp = /^(display(mode|days)$|nt|headline)/
|
0
|
1022 @opt = {
|
|
1023 'conf' => @mybase+".cf",
|
|
1024 'css' => @mybase+".css",
|
13
|
1025 'logfile' => 's/'+@mybase+".log",
|
0
|
1026 "sendmail" => "/usr/sbin/sendmail",
|
|
1027 'hostcmd' => '/usr/bin/host',
|
|
1028 'nslookup' => '/usr/sbin/nsookup',
|
|
1029 'bg' => 'ivory',
|
8
|
1030 'name' => nil,
|
0
|
1031 'at_bsd' => '%H:%M %b %d %Y',
|
|
1032 'at_solaris' => '%H:%M %b %d,%Y',
|
|
1033 'schedir' => 's',
|
|
1034 'tdskip' => '<br>',
|
|
1035 'forgot' => 'wasureta',
|
|
1036 'size' => @oldagent ? '15' : '40',
|
|
1037 'morning' => '6',
|
|
1038 'night' => '22',
|
|
1039 'alldaydir' => '3000',
|
|
1040 'pswdlen' => 4,
|
6
|
1041 'pswddb' => 's/a5pswd',
|
2
|
1042 'lang' => 'j',
|
6
|
1043 'notifymail' => true,
|
0
|
1044 }
|
|
1045 @ntlist = [
|
|
1046 ['nt10m', "10"+msg('minutes', 'before')],
|
|
1047 ['nt30m', "30"+msg('minutes', 'before')],
|
|
1048 ['nt60m', "60"+msg('minutes', 'before')],
|
|
1049 ['nttoday', msg('theday')],
|
|
1050 ['nt1d', "1"+msg('days', 'before')],
|
|
1051 ['nt2d', "2"+msg('days', 'before')],
|
|
1052 ['nt3d', "3"+msg('days', 'before')],
|
|
1053 ['nt7d', "7"+msg('days', 'before')],
|
|
1054 ['nt30d', "30"+msg('days', 'before')],
|
|
1055 ]
|
|
1056 ##@job = "today"
|
3
|
1057 @wnames = %w[sun mon tue wed thu fri sat]
|
0
|
1058 @job = "login"
|
|
1059 @sc = ScheduleDir.new
|
|
1060 @O = StringIO.new
|
|
1061 @H = HTMLout.new()
|
|
1062 @umback = File.umask
|
|
1063 @author = 'yuuji@gentei.org'
|
|
1064 @after5url = 'http://www.gentei.org/~yuuji/software/after5/'
|
|
1065 File.umask(007)
|
|
1066 end
|
|
1067 def doit()
|
|
1068 @params = getarg()
|
|
1069 @cookie = getcookie()
|
3
|
1070 importcookie()
|
2
|
1071 @lang = (/^j/i =~ @opt['lang'] ? 0 : 1)
|
0
|
1072 p @cookie if $DEBUG
|
|
1073 p @params if $DEBUG
|
|
1074
|
3
|
1075 ### @params['displaymode'] = @params['displaymode'] || @cookie['displaymode']
|
2
|
1076 personal = /personal/i =~ @params['displaymode']
|
|
1077 bodyclass = if personal then {'class'=>'personal'} end
|
0
|
1078
|
|
1079 ## x = {"align"=>'center'}
|
|
1080 ## @H.element("p", x, "hoge", nil)
|
|
1081 ## @H.element("p", nil, "buha", nil)
|
|
1082
|
3
|
1083 if nil
|
0
|
1084 if !@params['passwd'] && @cookie['passwd']
|
|
1085 @params['passwd'] = @cookie['passwd']
|
|
1086 end
|
|
1087 if !@params['user'] && @cookie['user']
|
|
1088 @params['user'] = @cookie['user']
|
|
1089 end
|
3
|
1090 end
|
0
|
1091 @params['user'] = safecopy(@params['user'])
|
2
|
1092
|
15
|
1093 ######eval @job
|
8
|
1094 a5name = if @opt['name'] && @opt['name'] > ''
|
|
1095 sprintf("(%s)", @opt['name'])
|
|
1096 else
|
|
1097 ""
|
|
1098 end
|
2
|
1099 @O.append(@H.contenttype() +
|
8
|
1100 @H.head(a5name+"After 5"+@job.sub(/\s*/, ' '), @opt['css']))
|
2
|
1101 @O.print @H.startelement("body", bodyclass, true)
|
15
|
1102 # @job should be here because its output shoud go after <body>.
|
|
1103 eval @job
|
0
|
1104 @O.print @H.endelement(nil, true) # body
|
14
|
1105 @O.print @H.endelement("html", true) # html
|
0
|
1106 setcookie()
|
|
1107
|
|
1108 print @O.readlines
|
|
1109 end
|
|
1110 def msg(*keyword)
|
|
1111 unless defined?(@msg)
|
|
1112 @msg = {
|
3
|
1113 'title' => ['みんなの予定表 <img src="after5.png" alt="「アフター5」">', 'Schedule table for us all <img src="after5.png" alt="After 5">'],
|
0
|
1114 'login' => ['ログイン', 'Login'],
|
|
1115 'loginfirst' => ['最初にログインすべし', 'Login first'],
|
|
1116 'autherror' => ['認証エラーがあったと管理者に伝えてくれっす',
|
|
1117 'Unexpected authentication error. Please tell this to the administrator'],
|
|
1118 'yourmail' => ['あなたのメイルアドレス', 'Your email address'],
|
|
1119 'passwd' => ['パスワード<br>(初回時は空欄)',
|
|
1120 'Passowrd<br>Left blank, first time'],
|
|
1121 'error' => ['エラー:', 'Error: '],
|
|
1122 'mailerror' => ['メイルアドレスが違います', 'Invalid email address'],
|
|
1123 'pswderror' => ['パスワードが違います', 'Password incorrect'],
|
8
|
1124 'fmtdaysschedule'=> ['%s〜の予定', 'Schedule from %s'],
|
18
|
1125 'schedtable' => ['予定表', 'Schedule Table'],
|
0
|
1126 'noplan' => ['登録されている予定はありません', 'No plans'],
|
|
1127 'allday' => ['全日', 'whole day'],
|
|
1128 'addsched' => ['新規予定項目の登録', 'Register new schedule'],
|
|
1129 'defthisday' => ['デフォルトの日付はこの日になってま', ''],
|
|
1130 '24hour' => ['24時間制4桁でね<br>(0000〜2359)<br>%sは時刻指定なし', 'in 24-hour<br>(0000-2359)<br>%s for whole day'],
|
14
|
1131 '24hourtxt' => ['24時間制4桁でね(0000〜2359), %sは時刻指定なし', 'in 24-hour(0000-2359), %s for whole day'],
|
0
|
1132 'reqnotify' => ['通知メイルいるけ?', 'Previous notification'],
|
|
1133 'rightnow' => ['登録時にすぐ', 'Right now on registration'],
|
|
1134 'immediatenote' => ['に以下の予定を登録しました',
|
|
1135 ", Your schedule has been registered as follows;"],
|
|
1136 'registerer_is' => ['登録名義: ', 'Register as '],
|
|
1137 'registerer' => ['登録者: ', 'registerer: '],
|
|
1138 'about' => ['約', 'about'],
|
|
1139 'minutes' => ['分', 'minutes'],
|
|
1140 'hours' => ['時間', 'hour(s)'],
|
|
1141 'days' => ['日', 'day(s)'],
|
2
|
1142 'daystodisplay' => ['日分表示', 'days to display'],
|
0
|
1143 'before' => ['前', 'before'],
|
2
|
1144 'precedingday' => ['前日', 'Preceding day'],
|
0
|
1145 'theday' => ['当日朝', "the day's morning"],
|
|
1146 'night' => ['(夜)', '(night)'],
|
|
1147 'publicok' => ['メンバーに<br>見せてもええね?',
|
|
1148 'visible from other members?'],
|
|
1149 'public' => ['公', 'pub'],
|
|
1150 'nonpublic' => ['非', 'sec'],
|
2
|
1151 'through' => ['〜', '=>'],
|
0
|
1152 'yes' => ['はいな', 'yes'],
|
17
|
1153 'no' => ['やだ(非公開)', 'nope'],
|
2
|
1154 'wnames' => [%w[日 月 火 水 木 金 土],
|
|
1155 %w[sun mon tue wed thu fri sat]],
|
|
1156 'whichday' => ['<small>(まとめ登録の場合)</small><br>期間中のどの日に?',
|
|
1157 '<small>(On multiple registration)</small><br>Which days in the term?'],
|
|
1158 'singleday' => ['一日分だけ登録', '1day regist'],
|
|
1159 'everyday' => ['毎日', 'everyday'],
|
0
|
1160 'invaliddate' => ['日付指定が変みたい', 'Invalid time string'],
|
|
1161 'past' => ['それはもう過去の話ね', 'It had Pasted'],
|
|
1162 'putsomething' => ['何か書こうや', 'Write some message please'],
|
|
1163 'appended' => ['既存の予定に追加しました', 'Appended'],
|
|
1164 'append' => ['追加', 'append'],
|
|
1165 'join' => ['参加', 'join'],
|
|
1166 'regist' => ['登録', 'register'],
|
|
1167 'remove' => ['削除', 'remove'],
|
14
|
1168 'move' => ['移動', 'move'],
|
|
1169 'newdate' => ['移動先時刻', 'New date'],
|
0
|
1170 'deletion' => ['完全消去', 'deletion'],
|
|
1171 'deletionwarn' => ['OK押したら即消去。確認とらないぞ',
|
|
1172 'Hitting OK immediately delets this group, be carefully!'],
|
|
1173 'deluser' => ['%s ユーザ消してええかの?', "Delete the user `%s'"],
|
|
1174 'delgroup' => ['%s グループ消してええかの?', "Delete the group `%s'"],
|
|
1175 'really?' => ['ほんまにええけ?', 'Really?'],
|
|
1176 'chicken' => ['ふっ、腰抜けめ', 'Hey, chicken boy'],
|
|
1177 'modify' => ['修正', 'modify'],
|
|
1178 'done' => ['完了', 'done'],
|
|
1179 'success' => ['成功', 'success'],
|
|
1180 'failure' => ['失敗', 'failure'],
|
|
1181 'tomonthlist' => ['%s の一覧', 'all %s table'],
|
|
1182 'notifysubj' => @mybase+"'s reminder for your plan",
|
|
1183 'introduce' => ['はいこんにちは、'+@mybase+'ですよ〜。',
|
|
1184 "Hi, this is #{@mybase}'s notification."],
|
|
1185 'notifymail' => ['こんな予定がありまっせ。',
|
|
1186 "You have some eschedule below;"],
|
|
1187 'notification' => ['の通知', 'notification'],
|
|
1188 'newaccount' => ["新しいアカウントを作りました。\n"+
|
|
1189 "パスワードは %s さん宛に送信しておきました。\n",
|
|
1190 "You got new account for #{@mybase}\n" +
|
|
1191 "Password was sent to %s.\nThank you.\n"],
|
|
1192 'accessfrom' => ["%s からのアクセスによる送信\n",
|
|
1193 "This mail was sent by the access from %s\n"],
|
|
1194 'newpassword' => ["%s さんのパスワードは %s です。\n",
|
|
1195 "The password of %s is %s\n"],
|
|
1196 'mischief' => ["身に覚えのない場合はいたずらです。どうしましょ。",
|
|
1197 'If you have no idea for getting this message, '+
|
|
1198 'it is mischief by someone else'],
|
|
1199 'user' => ['ユーザ', 'user'],
|
|
1200 'group' => ['グループ', 'group'],
|
|
1201 'personal' => ['個人で', 'personal'],
|
17
|
1202 'registas' => ['グループ予定として登録?', 'Register as group?'],
|
|
1203 'headsched' => ['下の枠内に予定を記入: 1行以内で短めに。
|
|
1204 長くなるときは2行目以降に詳細を。',
|
|
1205 'Put shortest sentence as possible within 1 line.
|
|
1206 Or, put short subject in the first line, details in latter lines.'],
|
0
|
1207 'joinquit' => ['入退', 'joining/quiting'],
|
|
1208 'of' => ['の', "'s"],
|
|
1209 'id' => ['ID(ローマ字1単語空白なしで)', 'ID(without spaces)'],
|
|
1210 'name' => ['名前', 'name'],
|
|
1211 'anystring' => ['(日本語OK)', '(any length, any characters)'],
|
|
1212 'setto' => ['を設定 → ', 'set to '],
|
2
|
1213 'dupname' => ['あー、%sってグループ名は既にあるん素。別のにして.',
|
|
1214 "Group name `%s' already exists, choose another name."],
|
0
|
1215 'management' => ['管理', 'management'],
|
|
1216 'administrator' => ['管理者', 'Administrator'],
|
|
1217 'newgroup' => ['新規グループ作成', 'Create new group'],
|
|
1218 'adminop' => ['管理<br>操作', "Administrative<br>operation"],
|
|
1219 'member' => ['メンバー', 'Member'],
|
2
|
1220 'personalmode' => ['自分のだけ表示モード', 'Display Personal Only'],
|
|
1221 'normalmode' => ['全員分表示モード', "Display Everyone's"],
|
3
|
1222 'display' => ['予定表示行: ', 'Display schedule of: '],
|
|
1223 'nameonly' => ['名前のみ', 'Name Only'],
|
|
1224 'head5char' => ['先頭5文字', 'Head 5 chars'],
|
|
1225 'headline' => ['先頭1行', 'Headline only'],
|
|
1226 'whole' => ['長くても全部', 'Whole text'],
|
6
|
1227 'hldays' => ['最新X日分強調', 'Hilight Recent X-days'],
|
0
|
1228 'addedtogroup' => ['をグループに追加 →', 'added to the group:'],
|
|
1229 'removedfromgp' => ['をグループから削除:', 'removed from the group:'],
|
|
1230 'soleadmin' => ['%s は %s の唯一の管理者なのでやめられないのだ',
|
|
1231 "%s is sole administrator of %s. Cannot retire."],
|
|
1232 'recursewarn' => ['個人では加入してないが、別の加入グループがこのグループに入っているので実質参加していることになっている。',
|
|
1233 'Though this member does not join to this group, it is assumed to be joining this group because other group where one joins is joined to this group.'],
|
|
1234 'regaddress' => ['登録アカウント名', 'Account id'],
|
|
1235 'existent' => ['既にあるんすよ → ', 'Already exists: '],
|
|
1236 'mailaddress' => ['通知送付先アドレス', 'Notification email address'],
|
|
1237 'weburl' => ['ゲストブックとかURL<br><small>(予定への反応を書いて欲しい場所)</small>', 'Your guest book URL'],
|
|
1238 'usermodwarn' => ['いちいち yes/no とか確認取らないから押したら最後、気いつけて。',
|
|
1239 'This is the final decision. Make sure and sure.'],
|
|
1240 'joinmyself' => ['自分自身が既存のグループに対して入る(IN)か出る(OUT)かを決めるのがここ。自分管理のグループに誰かを足すなら「管理操作」、新たにグループを作るなら',
|
|
1241 'In this page, you can decide put yourself IN or OUT of the existing groups. If you want to manage the member of your own group, go to'],
|
|
1242 'groupwarn' => ['自分が参加してないグループAに、自分が参加しているグループBが含まれている場合、グループAにも加入していると見なされるので気をつけよう。管理者はグループのニックネームを変えられるよ。',
|
|
1243 'Though you are not member of group A, you are treated as a member of A, if you join to the group B, which is a member of A. Think the nesting of groups carefully, please. Group administrator can change the group nickname.'],
|
|
1244 'wholemembers' => ['グループ内グループを考慮した上で、現在グループ %s への通知は以下のメンバーに送られる。',
|
|
1245 "Consiering the groups registered in another group, notification to the group `%s' is send to members as follows."],
|
|
1246 'noadmingroup' => ['管理できるグループはないっす',
|
|
1247 "'There's no groups under your administration."],
|
|
1248 'multiplemail' => ['複数の宛先に通知したいなら..',
|
|
1249 'Wanna send notify to multiple address...'],
|
|
1250 'nickname' => ['ニックネーム', 'nickname'],
|
|
1251 'shortnameplz' => ['表が崩れるほど長すぎるニックネームは嫌われるよ。短めにね。',
|
|
1252 'Because nickname is displayed many times in table, shorter name is prefered.'],
|
|
1253 'nicknamenote' => ['ニックネームを消去するとデフォルト名になりんす.',
|
|
1254 'Default name is displayed if you remove nickname.'],
|
|
1255 'nothingtodo' => ['って何もやることあらへんかったで',
|
14
|
1256 'Nothing to do for this transaction.'],
|
|
1257 'schedlist' => [' and %d days Schedule list',
|
|
1258 'から%d日間の予定一覧'],
|
|
1259 'nothing' => ['なんもないす', 'Nothing'],
|
|
1260 'sessionpswd' => ['セッションパスワード(これはいじらないでね)',
|
|
1261 'Session Password(Do not modify this)'],
|
|
1262 'date' => ['日付', 'Date'],
|
|
1263 'time' => ['時刻指定', 'Time'],
|
|
1264 'publicp' => ['公開=yes、非公開=no', 'Public?'],
|
|
1265 'neednotify' => ['通知メイル(要らないのは消してね)',
|
|
1266 'Leave lines for notification timing'],
|
|
1267 'schedulehere' => ['以下登録内容', 'Your Schedule below']
|
0
|
1268 }
|
|
1269 end
|
|
1270 keyword.collect{|k|
|
|
1271 if @msg[k].is_a?(Array)
|
2
|
1272 @msg[k][@lang]
|
0
|
1273 elsif @msg[k].is_a?(String)
|
|
1274 @msg[k]
|
|
1275 else
|
|
1276 ''
|
|
1277 end
|
2
|
1278 }.join(['', ' '][@lang])
|
0
|
1279 end
|
|
1280
|
3
|
1281 def importcookie()
|
7
|
1282 @cookie.keys.grep(@saveprefsregexp){|v|
|
3
|
1283 @params[v] = @params[v] || @cookie[v]
|
|
1284 }
|
7
|
1285 for v in %w[user passwd]
|
|
1286 @params[v] = @params[v] || @cookie[v]
|
|
1287 end
|
3
|
1288 end
|
0
|
1289 def setcookie()
|
7
|
1290 a = {}
|
|
1291 a['user'] = @params['user'] if @params['user']
|
|
1292 a['passwd'] = @params['passwd'] if @params['passwd']
|
|
1293 ac = gencookie("value", a, 3600*6*1)
|
|
1294 printf "Set-Cookie: %s\n", ac if ac
|
0
|
1295 p = {}
|
7
|
1296 @params.keys.grep(@saveprefsregexp){|v|
|
6
|
1297 p[v] = @params[v].to_s.strip if @params[v] && @params[v] > ''
|
0
|
1298 }
|
7
|
1299 c = gencookie("prefs", p, 3600*24*7)
|
|
1300 str = [ac, c].select{|x|x}.join("; ")
|
|
1301 # printf "Set-Cookie: %s\n", str if str>''
|
0
|
1302 printf "Set-Cookie: %s\n", c if c
|
|
1303 end
|
|
1304
|
|
1305 def encode(string) # borrowed from cgi.rb
|
|
1306 string.gsub(/([^ a-zA-Z0-9_.-]+)/n) do
|
|
1307 '%' + $1.unpack('H2' * $1.size).join('%').upcase
|
|
1308 end.tr(' ', '+')
|
|
1309 end
|
14
|
1310 def purify(string)
|
|
1311 string.gsub(/[\040-\177]/) {encode($&)}
|
|
1312 end
|
0
|
1313 def decode!(string)
|
|
1314 string.gsub!(/\+/, ' ')
|
|
1315 string.gsub!(/%(..)/){[$1.hex].pack("c")}
|
|
1316 end
|
14
|
1317 def decode(string)
|
17
|
1318 string.gsub(/\+/, ' ').gsub(/%(..)/){[$1.hex].pack("c")}
|
14
|
1319 end
|
0
|
1320
|
7
|
1321 def gencookie(name, a, expire)
|
0
|
1322 x = a.collect{|k, v|
|
|
1323 sprintf("%s=%s", k, encode(v)) if v
|
|
1324 }
|
|
1325 x.delete(nil)
|
|
1326 return nil if x.empty?
|
|
1327 str = x.join('&')
|
|
1328 ex = (Time.new+expire).to_s
|
7
|
1329 sprintf "%s=%s; expires=%s", name, encode(str), ex
|
0
|
1330 end
|
|
1331
|
|
1332 def login()
|
|
1333 @O.print @H.elementln("h1", nil){msg('title')}
|
|
1334 @O.print @H.elementln("h2", nil){msg('login')}
|
|
1335 format = {'method'=>'POST', 'action'=>@myname+"?-today"}
|
|
1336 @O.print @H.elementln("form", format){
|
|
1337 @H.elementln("table", nil){
|
|
1338 @H.elementln("tr", nil){
|
|
1339 @H.element("td", nil){msg('yourmail')} + \
|
|
1340 @H.element("td", nil){
|
|
1341 sprintf '<input type="text" size="%s" name="user">', @opt['size']
|
|
1342 }
|
|
1343 } + \
|
|
1344 @H.elementln("tr", nil){
|
|
1345 @H.element("td", nil){msg('passwd')} + \
|
|
1346 @H.element("td", nil){
|
|
1347 sprintf '<input type="password" size="%s" name="passwd">', @opt['size']
|
|
1348 }
|
|
1349 }
|
|
1350 } + '<input type="submit" value="LOGIN">'
|
|
1351 }
|
|
1352 @O.print footer2()
|
|
1353 end
|
|
1354 def open_pm()
|
|
1355 begin
|
|
1356 PasswdMgr.new(@opt['pswddb'])
|
|
1357 rescue
|
|
1358 STDERR.printf "Cannot open pswd file [%s]\n", @opt['pswddb']
|
|
1359 STDERR.printf "euid=#{Process.euid}, uid=#{Process.uid}\n", @opt['pswddb']
|
|
1360 nil
|
|
1361 end
|
|
1362 end
|
|
1363 def outputError(*msg)
|
|
1364 @O.print @H.p(msg('error')+sprintf(*msg))
|
|
1365 end
|
|
1366 def mailaddress(user)
|
|
1367 email = @sc.getuserattr(user, "email")
|
|
1368 email || user
|
|
1369 end
|
|
1370 def webpage(user)
|
|
1371 @sc.getuserattr(user, "webpage")
|
|
1372 end
|
14
|
1373 def checkauth_mail()
|
|
1374 return true # temporary
|
|
1375 end
|
0
|
1376 def checkauth()
|
14
|
1377 if @mailmode && @params['sessionpw']
|
|
1378 return checkauth_mail
|
|
1379 end
|
|
1380 auth = catch(:auth) {
|
0
|
1381 unless @params['user']
|
|
1382 outputError(@H.a(@myname, msg('loginfirst')))
|
|
1383 throw :auth, nil
|
|
1384 end
|
|
1385 unless pm=open_pm()
|
|
1386 outputError(msg('autherror'))
|
|
1387 throw :auth, nil
|
|
1388 end
|
|
1389 user, passwd = @params['user'], @params['passwd']
|
|
1390 email = mailaddress(user)
|
|
1391 if !checkmail(user)
|
|
1392 outputError(msg('mailerror'))
|
|
1393 throw :auth, nil
|
|
1394 end
|
|
1395 if pm.userexist?(user)
|
|
1396 if pm.checkpasswd(user, passwd)
|
|
1397 throw :auth, true
|
|
1398 elsif passwd == @opt['forgot']
|
|
1399 newp = pm.setnewpasswd(user, @opt['pswdlen'])
|
|
1400 sendMail(email, "#{@mybase} password",
|
|
1401 "(#{ENV['REMOTE_ADDR']} からのアクセスによる送信)\n" +
|
7
|
1402 @opt['url'] + "\n" +
|
0
|
1403 "#{@mybase} 用の #{user} さんのパスワードは\n" +
|
|
1404 (newp || "未定義") + "\nです。\n")
|
|
1405 @O.print @H.p("#{email} 宛に送信しておきました")
|
|
1406 throw :auth, nil
|
|
1407 else
|
|
1408 outputError(msg('pswderror'))
|
|
1409 throw :auth, nil
|
|
1410 end
|
7
|
1411 elsif passwd == ''
|
0
|
1412 newp = pm.setnewpasswd(user, @opt['pswdlen'])
|
|
1413 @sc.createuser(user, user)
|
|
1414 sendMail(email, "#{@mybase} new account",
|
|
1415 sprintf(msg('accessfrom'), ENV['REMOTE_ADDR']) +
|
7
|
1416 sprintf(@opt['url']) + "\n" +
|
0
|
1417 sprintf(msg('newpassword'), user, newp) +
|
|
1418 sprintf(msg('mischief')))
|
|
1419 @O.print @H.p(sprintf(msg('newaccount'), user))
|
|
1420 @O.print @H.p(@H.a(@myname, msg('login')))
|
|
1421 throw :auth, nil
|
7
|
1422 else
|
|
1423 outputError(msg('pswderror'))
|
|
1424 throw :auth, nil
|
0
|
1425 end
|
|
1426 }
|
|
1427 if auth
|
|
1428 return true
|
|
1429 else
|
|
1430 return false
|
|
1431 end
|
|
1432 end
|
|
1433 def safecopy(string)
|
|
1434 return nil unless string
|
|
1435 if $SAFE > 0
|
|
1436 cpy=''
|
|
1437 string.split('').each{|c|
|
|
1438 cpy << c[0].chr if c[0] != ?` # `
|
|
1439 }
|
|
1440 cpy
|
|
1441 else
|
|
1442 string
|
17
|
1443 end.untaint
|
0
|
1444 end
|
|
1445 def checkmail(mail)
|
|
1446 account, domain = mail.scan(/(.*)@(.*)/)[0]
|
|
1447 return false unless account != nil && domain != nil
|
17
|
1448 return false unless /^[-0-9a-z_.]+$/oi =~ domain.toeuc
|
0
|
1449 domain = safecopy(domain)
|
|
1450 require 'socket'
|
|
1451 begin
|
|
1452 TCPSocket.gethostbyname(domain)
|
|
1453 return true
|
|
1454 rescue
|
|
1455 if test(?x, @opt["hostcmd"])
|
|
1456 open("| #{@opt['hostcmd']} -t mx #{domain}.", "r") {|ns|
|
|
1457 #p ns.readlines.grep(/\d,\s*mail exchanger/)
|
|
1458 return ! ns.readlines.grep(/is handled .*(by |=)\d+/).empty?
|
|
1459 }
|
|
1460 elsif test(?x, @opt["nslookup"])
|
|
1461 open("| #{@opt['nslookup']} -type=mx #{domain}.", "r") {|ns|
|
|
1462 #p ns.readlines.grep(/\d,\s*mail exchanger/)
|
|
1463 return ! ns.readlines.grep(/\d,\s*mail exchanger/).empty?
|
|
1464 }
|
|
1465 end
|
|
1466 return false
|
|
1467 end
|
|
1468 end # checkmail
|
|
1469
|
|
1470 # Logging
|
|
1471 #
|
|
1472 def putLog(msg)
|
|
1473 msg += "\n" unless /\n/ =~ msg
|
|
1474 open(@opt["logfile"], "a+") {|lp|
|
|
1475 lp.print Time.now.to_s + " " + msg
|
|
1476 }
|
|
1477 end
|
|
1478
|
|
1479 def sendnotify(whom, subj, body)
|
|
1480 users = users()
|
|
1481 if grepgroup(whom)
|
|
1482 recipients = @sc.members(whom)
|
|
1483 else
|
|
1484 recipients=[whom]
|
|
1485 end
|
|
1486 for u in recipients
|
|
1487 if users.grep(u)[0]
|
|
1488 sendMail(mailaddress(u), subj, body)
|
|
1489 end
|
|
1490 end
|
|
1491 end
|
|
1492
|
|
1493 def sendMail(to, subject, body)
|
17
|
1494 body = NKF.nkf("-j", body)
|
|
1495 subject = NKF.nkf("-jM", subject)
|
0
|
1496 to = safecopy(to) # cleanup tainted address
|
|
1497 subject.gsub!(/\n/, '')
|
|
1498 begin
|
|
1499 if (m=open("|-", "w"))
|
|
1500 m.print "To: #{to}\n"
|
|
1501 m.print "Subject: #{subject}\n"
|
|
1502 m.print "Mime-Version: 1.0
|
|
1503 Content-Transfer-Encoding: 7bit
|
|
1504 Content-Type: Text/Plain; charset=iso-2022-jp
|
|
1505
|
|
1506 "
|
|
1507 m.print body, "\n"
|
|
1508 m.close
|
|
1509 else
|
|
1510 # exec(@attr['mail'], "-s", subject, to)
|
|
1511 exec(@opt['sendmail'], to)
|
|
1512 exit 0;
|
|
1513 end
|
|
1514 putLog("Sent '#{subject}' to #{to}\n")
|
|
1515 return true
|
|
1516 rescue
|
|
1517 putLog("FAILED! - Sent '#{subject}' to #{to}\n")
|
|
1518 return nil
|
|
1519 end
|
|
1520 end # sendMail
|
|
1521
|
|
1522 def today()
|
|
1523 today = Time.now
|
|
1524 showtable(today)
|
|
1525 end
|
|
1526 def isleap?(y)
|
|
1527 if y%400 == 0
|
|
1528 true
|
|
1529 elsif y%100 == 0 || y%4 != 0
|
|
1530 false
|
|
1531 else
|
|
1532 true
|
|
1533 end
|
|
1534 end
|
|
1535 def daysofmonth(year, month)
|
|
1536 dl = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
|
|
1537 if month != 2 || !isleap?(year)
|
|
1538 dl[month-1]
|
|
1539 else
|
|
1540 29
|
|
1541 end
|
|
1542 end
|
|
1543 #
|
|
1544 # Return the Time object at the last day of last month
|
|
1545 def lastmonth(today)
|
|
1546 Time.at(Time.mktime(today.year, today.month)-3600*24)
|
|
1547 end
|
|
1548 #
|
|
1549 # Return the Time object at the first day of next month
|
|
1550 def nextmonth(today)
|
|
1551 y, m = today.year, today.month
|
|
1552 Time.at(Time.mktime(y, m, daysofmonth(y, m))+3600*24)
|
|
1553 end
|
|
1554
|
|
1555 def month(month)
|
|
1556 y, m = month.scan(%r,(\d\d\d\d+)/(\d+),)[0]
|
|
1557 if y && m
|
|
1558 showtable(Time.mktime(y, m, 1))
|
|
1559 else
|
|
1560 outputError "%s %s", msg('invaliddate'), month
|
|
1561 return nil
|
|
1562 end
|
|
1563 end
|
|
1564 def footer1()
|
|
1565 "<br>" + \
|
|
1566 @H.element("p"){
|
|
1567 me = @myname+"?-"; delim = " / "
|
|
1568 @H.a(me+'userman', msg('user', 'management')) + delim + \
|
2
|
1569 @H.a(me+'groupman', msg('group', 'management')) + delim + \
|
|
1570 if /personal/i =~ @params['displaymode']
|
|
1571 @H.a(me+'today_n', msg('normalmode'))
|
|
1572 else
|
|
1573 @H.a(me+'today_p', msg('personalmode'))
|
|
1574 end
|
0
|
1575 }
|
|
1576 end
|
|
1577
|
|
1578 def footer2()
|
|
1579 "<hr>" + \
|
|
1580 @H.element("code") {
|
|
1581 "This " + \
|
|
1582 @H.a(@after5url, "After5") + \
|
|
1583 " board is maintained by " + \
|
|
1584 @opt['maintainer'].sub('@', "@") + "."
|
|
1585 }
|
|
1586 end
|
|
1587 def footer()
|
|
1588 footer1+footer2
|
|
1589 end
|
|
1590 def nickname(userORgroup)
|
|
1591 if grepgroup(userORgroup)
|
|
1592 @sc.groupname(userORgroup)
|
|
1593 else
|
|
1594 @sc.nickname(userORgroup)
|
|
1595 end
|
|
1596 end
|
|
1597 #
|
|
1598 # show specified month's calendar
|
|
1599 def showtable(day)
|
|
1600 if !checkauth
|
|
1601 return nil
|
|
1602 end
|
17
|
1603
|
0
|
1604 month = day.month.to_s
|
|
1605 first = Time.mktime(day.year, day.month, 1)
|
|
1606 last = daysofmonth(day.year, day.month)
|
|
1607 wday1 = first.wday
|
|
1608 start = 1-wday1
|
3
|
1609 wname = @wnames
|
0
|
1610 today = Time.now
|
8
|
1611 todayy = today.year
|
0
|
1612 todaym = today.month
|
|
1613 todayd = today.day
|
|
1614 tdclass = {}
|
|
1615 tdclass["width"] = "64px" if @oldagent # workaround for NN4
|
2
|
1616 personal = /personal/ =~ @params['displaymode']
|
3
|
1617 headline = @params['headline']
|
6
|
1618 headlinehl = @params['headlinehl']
|
|
1619 hldays = headlinehl.to_i * 3600*24
|
|
1620 recent = {'class'=>'recent'}
|
3
|
1621 monthstr = sprintf "%d/%d", day.year, day.month
|
|
1622
|
0
|
1623 holiday = Holiday.new
|
|
1624 # create dayofweek header
|
3
|
1625 @O.print @H.elementln("h1", nil){monthstr}
|
2
|
1626 # which mode?
|
|
1627 @O.print @H.p(msg(personal ? 'personalmode' : 'normalmode'))
|
|
1628 #
|
|
1629 # display table
|
0
|
1630 @O.print @H.startelement("table", {'border'=>"1", 'class'=>'main'})
|
|
1631
|
|
1632 # day of week
|
|
1633 @O.print @H.startelement("tr")
|
|
1634 for w in wname
|
|
1635 @O.print @H.element("th", {'class'=>w}){w.capitalize}
|
|
1636 end
|
|
1637 @O.print "\n"+@H.endelement(nil, true)
|
|
1638
|
|
1639 # create day table
|
|
1640 column = start
|
|
1641 ## p day, last
|
|
1642 while column <= last
|
|
1643 @O.print @H.elementln("tr", nil){
|
|
1644 (column..column+6).collect{|d|
|
8
|
1645 todayp = (day.year==todayy && day.month==todaym && d==todayd)
|
0
|
1646 wd=d-column
|
|
1647 hd = holiday.isHoliday(day.year, day.month, d, wd)
|
|
1648 tdclass['class'] = (hd ? 'holiday' : wname[wd])
|
|
1649 @H.element("td", tdclass){
|
13
|
1650 if d>0
|
|
1651 thisday = first+(d-1)*3600*24
|
|
1652 #date = "%d/%d/%d"%[day.year, day.month, d]
|
|
1653 date = "%d/%d/%d"%[thisday.year, thisday.month, thisday.day]
|
0
|
1654 @H.element("p", {'class'=>todayp ? 'todayline' : 'dayline'}){
|
13
|
1655 ##@H.a(@myname+"?-show+"+date, "%4d"%d)
|
|
1656 @H.a(@myname+"?-show+"+date, "%4d"%thisday.day)
|
0
|
1657 } + \
|
|
1658 # isHoliday?
|
|
1659 if hd
|
|
1660 @H.element("small"){hd.join("<br>")}
|
|
1661 end.to_s + \
|
|
1662 @H.element("p", {'class'=>'topic'}){
|
2
|
1663 s = @sc.day_all(date, @params['user'], personal)
|
0
|
1664 if !s.empty?
|
|
1665 s.keys.sort.collect{|time|
|
|
1666 s[time].keys.sort.collect{|who|
|
14
|
1667 text = decode(s[time][who]['sched'])
|
6
|
1668 topic = sprintf "%s%s",
|
3
|
1669 time == @opt['alldaydir'] ? '' : time+":",
|
2
|
1670 if personal
|
9
|
1671 (@params['user'] == who ? "" : nickname(who)+"=") +
|
7
|
1672 text ## .split("\n") ##[0]
|
2
|
1673 else
|
5
|
1674 nickname(who) + \
|
3
|
1675 if headline == 'whole'
|
5
|
1676 '=' + text
|
3
|
1677 elsif headline == 'head5char'
|
5
|
1678 '=' + text.gsub(/\n/, '').sub(/(.{5}).*/, '\1')
|
3
|
1679 elsif headline == 'headline'
|
5
|
1680 '=' + text.split("\n")[0]
|
3
|
1681 end.to_s
|
2
|
1682 end
|
6
|
1683 if hldays > 0 &&
|
|
1684 (today - s[time][who]['regtime']) < hldays
|
|
1685 topic = @H.element("span", recent){topic}
|
|
1686 end
|
|
1687 topic
|
3
|
1688 }.join("<br>")
|
|
1689 }.join("<br>\n")
|
0
|
1690 else
|
|
1691 @opt['tdskip']
|
|
1692 end
|
|
1693 }
|
|
1694 else
|
|
1695 @opt['tdskip']
|
|
1696 end
|
|
1697 }
|
|
1698 }.join
|
|
1699 }
|
|
1700 column += 7
|
|
1701 end
|
|
1702
|
|
1703 # month-link
|
|
1704 @O.print @H.elementln("tr", {'class'=>'monthlink'}){
|
|
1705 lm1 = lastmonth(day)
|
|
1706 lm2 = lastmonth(lm1)
|
|
1707 lm3 = lastmonth(lm2)
|
|
1708 nm1 = nextmonth(day)
|
|
1709 nm2 = nextmonth(nm1)
|
|
1710 nm3 = nextmonth(nm2)
|
|
1711 [lm3, lm2, lm1, nil, nm1, nm2, nm3].collect{|t|
|
|
1712 @H.element("td"){
|
|
1713 if t.is_a?(Time)
|
|
1714 ym = sprintf("%d/%d", t.year, t.month)
|
|
1715 @H.a(sprintf("%s?-month+%s", @myname, ym), ym)
|
|
1716 else
|
|
1717 sprintf "%d/%d", day.year, day.month
|
|
1718 end
|
|
1719 }
|
|
1720 }.join("\n")
|
|
1721 }
|
|
1722 @O.print "\n"+@H.endelement(nil, true)
|
|
1723
|
|
1724 @O.print "showtable" if @params['user'] == @author
|
3
|
1725 @O.print @H.elementln("form", {'action'=>@myname+"?-month+#{monthstr}", 'method'=>'POST'}){
|
|
1726 choice = [
|
|
1727 [msg('nameonly'), 'name'],
|
|
1728 [msg('head5char'), 'head5char'],
|
|
1729 [msg('headline'), 'headline'],
|
|
1730 [msg('whole'), 'whole']]
|
|
1731 msg('display') + \
|
6
|
1732 @H.select('headline', choice, headline) + "/" + \
|
|
1733 msg('hldays') + \
|
|
1734 @H.select('headlinehl', 0..30, headlinehl) + \
|
3
|
1735 @H.submit("GO", "GO")
|
|
1736 }
|
0
|
1737 @O.print footer
|
|
1738 ##schedule.day_all("2003/12/22")
|
|
1739 # @O.print @H.endelement()
|
|
1740 end
|
|
1741
|
|
1742 #
|
|
1743 # Put carrying values
|
|
1744 def hiddenvalues()
|
2
|
1745 h = %w[user displaymode].collect{|v|
|
0
|
1746 if @params[v]
|
|
1747 sprintf "<input type=\"hidden\" name=\"%s\" value=\"%s\">\n",
|
|
1748 v, @params[v]
|
|
1749 end
|
|
1750 }
|
|
1751 h.delete(nil)
|
|
1752 h.join
|
|
1753 end
|
2
|
1754 def date2ymd(date)
|
|
1755 %r,(\d\d\d\d+)/(\d\d?)/(\d\d?), =~ date and
|
|
1756 [$1.to_i, $2.to_i, $3.to_i]
|
|
1757 end
|
0
|
1758 #
|
|
1759 # Return the string of table
|
2
|
1760 def dayTableString(user, datestr, range, personal = nil)
|
|
1761 #s = @sc.day_all(date, user, personal)
|
|
1762 #return '' if s.empty?
|
0
|
1763 r = ''
|
2
|
1764 header = @H.startelement("table", {'border'=>'1'}, true)
|
|
1765
|
|
1766 day = Time.mktime(*date2ymd(datestr))
|
|
1767 i = -1
|
|
1768 while (i+=1) < range
|
|
1769 d = Time.at(day+i*3600*24)
|
|
1770 date = sprintf("%04d/%02d/%02d", d.year, d.month, d.day)
|
3
|
1771 datewn = @H.element("span", {'class'=>@wnames[d.wday]}){
|
|
1772 sprintf("%s(%s)", date, @msg['wnames'][@lang][d.wday])
|
|
1773 }
|
2
|
1774 s = @sc.day_all(date, user, personal)
|
|
1775 next if s.empty?
|
|
1776
|
|
1777 r << @H.element("tr", nil){
|
|
1778 @H.element("th", {'class'=>'time'}){'TIME'} + \
|
3
|
1779 @H.element("th", nil){'Who - '+datewn+' - What'}
|
2
|
1780 }
|
6
|
1781 for time in s.keys.sort
|
2
|
1782 tstr = case time
|
|
1783 when @opt['alldaydir']
|
|
1784 msg('allday')
|
|
1785 else
|
|
1786 sprintf "%02d:%02d", time.to_i/100, time.to_i%100
|
|
1787 end
|
|
1788 r << @H.startelement("tr", nil, true)
|
|
1789 r << @H.element("th", {'class'=>'time'}){tstr}
|
|
1790 r << @H.element("td"){
|
|
1791 @H.elementln("table"){
|
|
1792 s[time].keys.collect{|who|
|
|
1793 editable = (user==who || @sc.ismember(user, who))
|
|
1794 groupp = grepgroup(who)
|
|
1795 @H.element("tr"){
|
|
1796 @H.element("td", {'class'=>groupp ? 'group' : 'who'}){
|
|
1797 if !groupp && webpage(who)
|
|
1798 @H.a(webpage(who), nickname(who))
|
|
1799 else
|
|
1800 nickname(who)
|
|
1801 end
|
|
1802 } + \
|
|
1803 @H.element("td"){
|
|
1804 if editable
|
|
1805 s[time][who]['pub'] ? msg('public') :
|
|
1806 msg('nonpublic')
|
|
1807 else
|
|
1808 @opt['tdskip']
|
|
1809 end
|
|
1810 } + \
|
|
1811 @H.element("td"){
|
|
1812 if editable
|
|
1813 @H.a(@myname+"?-modify+#{date}/#{time}/#{who}",
|
|
1814 msg('modify'))
|
|
1815 else
|
|
1816 @opt['tdskip']
|
|
1817 end
|
|
1818 } + \
|
|
1819 @H.element("td"){
|
|
1820 if editable
|
|
1821 @H.a(@myname+"?-remove+#{date}/#{time}/#{who}",
|
|
1822 msg('remove'))
|
|
1823 else
|
|
1824 @opt['tdskip']
|
|
1825 end
|
|
1826 } + \
|
14
|
1827 @H.element("td"){
|
|
1828 if editable
|
|
1829 @H.a(@myname+"?-move+#{date}/#{time}/#{who}",
|
|
1830 msg('move'))
|
|
1831 else
|
|
1832 @opt['tdskip']
|
|
1833 end
|
|
1834 } + \
|
15
|
1835 @H.element("td"){decode(s[time][who]['sched'])}
|
2
|
1836 }
|
|
1837 }.join("\n")
|
|
1838 }
|
0
|
1839 }
|
2
|
1840 r << @H.endelement()
|
|
1841 end
|
0
|
1842 end
|
2
|
1843 footer = @H.endelement()
|
|
1844 if r > ''
|
|
1845 header + r + footer
|
|
1846 else
|
|
1847 ''
|
|
1848 end
|
0
|
1849 end
|
14
|
1850 def dayTextString(user, datestr, range, personal = nil)
|
|
1851 r = ''
|
|
1852 cols = 20
|
|
1853 header = "-" * cols + "\n"
|
|
1854
|
|
1855 day = Time.mktime(*date2ymd(datestr))
|
|
1856 i = -1
|
|
1857 while (i+=1) < range
|
|
1858 d = Time.at(day+i*3600*24)
|
|
1859 date = sprintf("%04d/%02d/%02d", d.year, d.month, d.day)
|
|
1860 datewn = sprintf("%s(%s)", date, @msg['wnames'][@lang][d.wday])
|
|
1861 s = @sc.day_all(date, user, personal)
|
|
1862 next if s.empty?
|
|
1863
|
|
1864 r << sprintf("TIME Who %s - What\n", datewn)
|
|
1865
|
|
1866 for time in s.keys.sort
|
|
1867 tstr = case time
|
|
1868 when @opt['alldaydir']
|
|
1869 msg('allday')
|
|
1870 else
|
|
1871 sprintf "%02d:%02d", time.to_i/100, time.to_i%100
|
|
1872 end
|
|
1873 r << s[time].keys.collect{|who|
|
|
1874 editable = (user==who || @sc.ismember(user, who))
|
|
1875 groupp = grepgroup(who)
|
|
1876 sprintf("%-5s %-10s %s", tstr, nickname(who), s[time][who]['sched'])
|
|
1877 }.join("\n") + "\n"
|
|
1878 end
|
|
1879 r << "-" * cols + "\n"
|
|
1880 end
|
|
1881 footer = "That's all\n"
|
|
1882 if r > ''
|
|
1883 header + r + footer
|
|
1884 else
|
|
1885 ''
|
|
1886 end
|
|
1887
|
|
1888 end
|
0
|
1889 #
|
2
|
1890 # new form
|
|
1891 def displayRegistForm(date, multiple = true)
|
0
|
1892 #
|
|
1893 # Link button to add new plan
|
|
1894 #now = Time.now+3600*24
|
2
|
1895 thisyear, thismonth, thisday = date.scan(%r,(\d\d\d\d+)/(\d+)/(\d+),)[0]
|
|
1896 user = @params['user']
|
0
|
1897 now = Time.mktime(thisyear, thismonth, thisday.to_i, Time.now.hour)
|
|
1898 y, m, d, h, min = now.year, now.month, now.day, now.hour, now.min
|
2
|
1899 nextweek = Time.at(now+3600*24*7)
|
|
1900 ey, em, ed = nextweek.year, nextweek.month, nextweek.day
|
|
1901 rcsp = (multiple ? {'colspan'=>'2'} : nil)
|
|
1902 wnames = @msg['wnames'][@lang]
|
|
1903 wnames << @msg['everyday'][@lang]
|
|
1904
|
0
|
1905 @O.print @H.element('h2', nil, true){msg('addsched')}
|
|
1906 @O.print @H.element('p', nil){msg('defthisday')}
|
2
|
1907
|
0
|
1908 @O.print @H.element("form", {'action'=>@myname+"?-addsched", 'method'=>'POST'}){
|
2
|
1909 border1 = {'border'=>'1'}
|
|
1910 border1c = {'border'=>'1', 'class'=>'c'}
|
|
1911 mygroup = @sc.groups().select{|g|@sc.ismember(user, g)}
|
0
|
1912 @H.elementln('table', border1){
|
|
1913 @H.elementln('tr'){
|
|
1914 @H.element('th'){'Name'} + \
|
2
|
1915 @H.element('td', rcsp){
|
0
|
1916 hiddenvalues() + @sc.nickname(user)
|
|
1917 }
|
|
1918 } + \
|
|
1919 @H.elementln('tr'){
|
|
1920 @H.element('th'){'Year'} + \
|
2
|
1921 @H.element('td'){@H.select("year", y..y+5, y)} + \
|
|
1922 if multiple
|
|
1923 @H.element('td'){
|
|
1924 d1 = msg('singleday')
|
|
1925 msg('through')+@H.select("endyear", [d1]+(y..y+5).to_a, d1)
|
|
1926 }
|
|
1927 end
|
0
|
1928 } + \
|
|
1929 @H.elementln('tr'){
|
|
1930 @H.element('th'){'Month'} + \
|
2
|
1931 @H.element('td'){@H.select("month", 1..12, m)} + \
|
|
1932 if multiple
|
|
1933 @H.element('td'){
|
|
1934 msg('through')+@H.select("endmonth", 1..12, em)
|
|
1935 }
|
|
1936 end
|
0
|
1937 } + \
|
|
1938 @H.elementln('tr'){
|
|
1939 @H.element('th'){'Day'} + \
|
2
|
1940 @H.element('td'){@H.select("day", 1..31, d)} + \
|
|
1941 if multiple
|
|
1942 @H.element('td'){
|
|
1943 msg('through')+@H.select("endday", 1..31, ed)
|
|
1944 }
|
|
1945 end
|
0
|
1946 } + \
|
2
|
1947 if multiple
|
|
1948 @H.elementln('tr'){
|
|
1949 @H.element('th'){
|
|
1950 msg('whichday')
|
|
1951 } + \
|
|
1952 @H.element('td', rcsp){
|
|
1953 @H.elementln('table', border1c){
|
|
1954 @H.element('tr'){
|
|
1955 i=-1
|
|
1956 wnames.collect{|w|
|
|
1957 @H.element('td'){
|
|
1958 i+=1
|
|
1959 @H.radio('whichday', i.to_s, '', i==wnames.length-1)
|
|
1960 }
|
|
1961 }.join("\n")
|
|
1962 } + \
|
|
1963 @H.element('tr'){
|
|
1964 i=-1
|
|
1965 wnames.collect{|w|
|
|
1966 @H.element('td'){w}
|
|
1967 }.join
|
|
1968 }
|
|
1969 }
|
|
1970 }
|
|
1971 }
|
|
1972 end + \
|
0
|
1973 @H.elementln('tr'){
|
|
1974 @H.element('th'){'Time<br>'+ \
|
|
1975 sprintf(msg('24hour'), @opt['alldaydir'])} + \
|
2
|
1976 @H.element('td', rcsp){
|
0
|
1977 '<input type=text name="time" value="3000" size=8 maxlength="4">'
|
|
1978 }
|
|
1979 } + \
|
|
1980 @H.elementln('tr'){
|
|
1981 @H.element('th'){msg('publicok')} + \
|
2
|
1982 @H.element('td', rcsp){
|
0
|
1983 @H.radio('pub', 'yes', msg('yes')+'<br>', true) + \
|
|
1984 @H.radio('pub', 'no', msg('no'))
|
|
1985 }
|
|
1986 }
|
|
1987 ## table
|
|
1988 } + \
|
|
1989 @H.elementln("p"){ # put notify mail checkbox
|
|
1990 msg('reqnotify') + '<br>' + \
|
|
1991 @ntlist.collect{|n, v|
|
8
|
1992 # Actual variables of notifylist for submitting is "sub_"+n
|
|
1993 @H.checkbox("sub_"+n, 'yes', v, @params[n])
|
0
|
1994 }.join("\n") + \
|
|
1995 " " + @H.checkbox('rightnow', 'yes', msg('rightnow'), true) + \
|
|
1996 "\n"
|
|
1997 } + \
|
|
1998 if mygroup[0]
|
|
1999 @H.elementln("p"){ # put "register as"
|
|
2000 msg('registas') + "<br>\n" + \
|
|
2001 mygroup.collect{|g|
|
|
2002 @H.radio('registas', g, @sc.groupname(g))
|
|
2003 }.join(' ') + "\n/ " + \
|
|
2004 @H.radio('registas', 'no', msg('personal'))
|
|
2005 }
|
|
2006 end.to_s + "\n" + \
|
2
|
2007 @H.radio('editmode', 'remove', 'Delete?') + " / " + \
|
|
2008 @H.radio('editmode', 'modify', 'Overwrite?') + " / " + \
|
|
2009 @H.radio('editmode', 'append', 'Append?', true) + "<br>\n" + \
|
17
|
2010 @H.element("p"){msg('headsched') + \
|
|
2011 @H.element("textarea", @schedulearea){}} + # textarea
|
0
|
2012 @H.submit_reset("GO")
|
|
2013 } #form
|
2
|
2014 end
|
|
2015 #
|
|
2016 # show the schedule list of specified date
|
|
2017 #
|
|
2018 def show(date)
|
|
2019 if !checkauth
|
|
2020 return nil
|
|
2021 end
|
|
2022 user = safecopy(@params['user'])
|
|
2023 personal = (/personal/i =~ @params['displaymode'])
|
|
2024 @params['displaydays'] = @params['displaydays'] || @cookie['displaydays']
|
3
|
2025 days = @params['displaydays'].to_i
|
18
|
2026 days = (days > 0 ? days : 3)
|
2
|
2027
|
|
2028 # str = @sc.day_all(date, user, personal)
|
|
2029 outstr = dayTableString(user, date, days, personal)
|
|
2030
|
|
2031 @O.print @H.element("h1", nil){
|
|
2032 sprintf msg('fmtdaysschedule'), date
|
|
2033 }
|
18
|
2034 @O.print @H.element("h2"){msg('schedtable')}
|
2
|
2035 ## @O.print @H.p()
|
|
2036 @O.print @H.elementln("form", {'action'=>@myname+"?-show+#{date}", 'method'=>'POST'}){
|
|
2037 @H.elementln("p"){
|
6
|
2038 msg(personal ? 'personalmode' : 'normalmode') + "<br>" + \
|
2
|
2039 @H.select("displaydays", 1..30, days) + msg('daystodisplay') + \
|
|
2040 @H.submit("GO", "GO")
|
|
2041 }
|
|
2042 }
|
|
2043 if outstr > ''
|
|
2044 @O.print outstr
|
|
2045 else
|
|
2046 @O.print @H.p(msg('noplan'))
|
|
2047 end #is_empty?
|
|
2048 thisyear, thismonth, thisday = date.scan(%r,(\d\d\d\d+)/(\d+)/(\d+),)[0]
|
|
2049 mstr = sprintf "%04d/%02d", thisyear.to_i, thismonth.to_i
|
|
2050 @O.print @H.a(@myname+"?-month+"+mstr,
|
|
2051 sprintf(msg('tomonthlist'), mstr))
|
|
2052
|
|
2053
|
|
2054 #
|
|
2055 # Display registration form
|
|
2056 displayRegistForm(date)
|
0
|
2057 @O.print "show" if user == @author
|
|
2058 end
|
|
2059
|
|
2060 #
|
|
2061 # call process
|
|
2062 def call_process(cmd, input=nil, timeout=10)
|
|
2063 prc = CMDTimeout.new
|
|
2064 fds = prc.start(cmd, timeout, true)
|
|
2065 if input
|
|
2066 Thread.start {
|
|
2067 fds[0].sync = true
|
|
2068 fds[0].print.input
|
|
2069 fds[0]
|
|
2070 }
|
|
2071 end
|
|
2072 begin
|
|
2073 fds[1].readlines
|
|
2074 ensure
|
|
2075 prc.close()
|
|
2076 end
|
|
2077 end
|
|
2078 #
|
|
2079 # notification registerer
|
|
2080 def notify_time(year, month, day, time, symbol)
|
|
2081 if (t = time.to_i) > 2359
|
|
2082 hh = mm = 0
|
|
2083 else
|
|
2084 hh, mm = t/100, t%100
|
|
2085 end
|
|
2086 base = Time.mktime(year.to_i, month.to_i, day.to_i, hh, mm)
|
|
2087 if /nt(\d+)([mh])$/ =~ symbol
|
|
2088 return nil if t > 2359
|
|
2089 num, unit = $1.to_i, $2.downcase
|
|
2090 rate = {'h'=>3600, 'm'=>60}[unit] || 3600
|
|
2091 return Time.at(base-rate*num)
|
|
2092 elsif /nt(\d+)d/ =~ symbol
|
|
2093 seconds = $1.to_i*3600*24
|
14
|
2094 tday= Time.at(base-seconds)
|
|
2095 target = [tday.year, tday.month, tday.day, @opt['night'].to_i]
|
|
2096 targetnight = Time.mktime(*target)
|
0
|
2097 elsif "nttoday" == symbol
|
|
2098 Time.mktime(year.to_i, month.to_i, day.to_i, @opt['morning'])
|
|
2099 end
|
|
2100 end
|
|
2101 def reg_notify(user, year, month, day, time, text, cancelall = nil)
|
6
|
2102 return nil unless @opt['notifymail']
|
0
|
2103 threshold = 5*60 # Omit notifycation within 30min future
|
|
2104
|
|
2105 y, m, d, t, = year.to_i, month.to_i, day.to_i, time.to_i
|
|
2106 if t > 2359
|
|
2107 hh = mm = 0
|
|
2108 else
|
|
2109 hh = t/100
|
|
2110 mm = t%100
|
|
2111 end
|
|
2112 now = Time.now
|
|
2113
|
|
2114 filearg = [user, year, month, day, t]
|
|
2115 @ntlist.each{|k, v|
|
8
|
2116 # @params[k]s are always defined in cookies, so we use @params["sub_"+k]
|
|
2117 @params[k] = @params["sub_"+k]
|
0
|
2118 nt_time = notify_time(year, month, day, t, k)
|
|
2119 if !nt_time
|
|
2120 # do nothing for allday schedule's notification before some minutes
|
|
2121 elsif cancelall || nt_time < now+threshold ||
|
|
2122 /yes|on|true|1/ !~ @params[k] || !@params[k]
|
|
2123 # cancel
|
|
2124 uf = @sc.remove_crondir(nt_time, user, year, month, day, t)
|
|
2125 @sc.removefile(*(filearg+[k]))
|
|
2126 else
|
|
2127 # register
|
|
2128 lf = @sc.register_crondir(nt_time, user, year, month, day, t)
|
|
2129 @sc.putfile(*(filearg+[k, lf]))
|
|
2130 end
|
|
2131 }
|
|
2132 end
|
|
2133 def cancel_notify(user, year, month, day, time)
|
|
2134 reg_notify(user, year, month, day, time, 'dummy', true)
|
|
2135 end
|
2
|
2136
|
|
2137 def commit_schedule(who, y, m, d, timedir, text, repl, pub)
|
|
2138
|
|
2139 end
|
|
2140
|
14
|
2141 def regulate_time(y, m, d, tm)
|
|
2142 if tm > 2399
|
|
2143 sh, smin = 23, 59
|
|
2144 timedir=@opt['alldaydir']
|
|
2145 tmstr = msg('allday')
|
|
2146 else
|
|
2147 sh = (tm/100).to_i
|
|
2148 smin = (tm%100).to_i
|
|
2149 timedir = sprintf("%04d", tm)
|
|
2150 tmstr = sprintf("%d:%02d", sh, smin)
|
|
2151 end
|
|
2152 time = nil
|
|
2153 begin
|
|
2154 time = Time.mktime(y, m, d, sh, smin)
|
|
2155 rescue
|
|
2156 outputError "%s<br>\nyear=%s<br>month=%s<br>day=%s<br>time=%s\n",
|
|
2157 msg('invaliddate'),
|
|
2158 @params['year'], @params['month'], @params['day'], @params['time']
|
|
2159 return nil
|
|
2160 end
|
|
2161 [time, timedir, tmstr]
|
|
2162 end
|
|
2163
|
0
|
2164 #
|
|
2165 # add or remove a schedule
|
|
2166 #
|
|
2167 def add_remove(remove = nil)
|
|
2168 if !checkauth
|
|
2169 return nil
|
|
2170 end
|
|
2171 user = registerer = @params['user']
|
|
2172 as = @params['registas']
|
|
2173 if as && as > '' && /^no$/ !~ as && @sc.ismember(user, as)
|
3
|
2174 if (gr=grepgroup(as))
|
|
2175 registerer = gr
|
|
2176 end
|
0
|
2177 end
|
|
2178 now = Time.now
|
2
|
2179 #y, m, d, h, min = now.year, now.month, now.day, now.hour, now.min
|
0
|
2180
|
|
2181 $KCODE='e' if $DEBUG
|
|
2182 @O.print @params.inspect if $DEBUG
|
|
2183 #
|
|
2184 # Check the validity of specified time
|
|
2185 sy = @params['year'].to_i
|
|
2186 sm = @params['month'].to_i
|
|
2187 sd = @params['day'].to_i
|
|
2188 tm = @params['time'].to_i
|
14
|
2189
|
|
2190 time, timedir, tmstr = regulate_time(sy, sm, sd, tm)
|
2
|
2191
|
|
2192 #
|
|
2193 # Check continuous schedule registration
|
|
2194 wwday = @params['whichday'].to_i
|
|
2195 if @params['endyear'] && @params['endmonth'] && @params['endday'] &&
|
|
2196 (ey=@params['endyear'].to_i) > 0 &&
|
|
2197 (em=@params['endmonth'].to_i) > 0 &&
|
|
2198 (ed=@params['endday'].to_i) > 0
|
|
2199 daylist = []
|
|
2200 endtime = Time.mktime(ey, em, ed, 23, 59)
|
|
2201 ti = time
|
|
2202 begin
|
|
2203 if wwday==7 || wwday==ti.wday
|
|
2204 daylist << [ti.year, ti.month, ti.day]
|
|
2205 end
|
9
|
2206 end while (ti=Time.at(ti+3600*24)) <= endtime
|
2
|
2207 else
|
|
2208 daylist = [[sy, sm, sd]]
|
|
2209 end
|
|
2210
|
|
2211 if !remove && !(@params['schedule'] && @params['schedule'].strip > '')
|
0
|
2212 outputError msg('putsomething')
|
|
2213 return nil
|
|
2214 end
|
|
2215
|
2
|
2216
|
|
2217 for y, m, d in daylist
|
|
2218 # do remove or addition
|
|
2219 if remove
|
|
2220 cancel_notify(registerer, y, m, d, timedir)
|
|
2221 begin
|
|
2222 @sc.remove(registerer, y, m, d, timedir)
|
|
2223 #########@O.print @H.p(msg('remove')+msg('done'))
|
|
2224 rescue
|
|
2225 outputError("Failed"+$!)
|
|
2226 end
|
|
2227 else
|
|
2228 if time < now
|
|
2229 outputError(msg('past'))
|
|
2230 return nil
|
|
2231 end
|
|
2232 begin
|
17
|
2233 (text = decode(@params['schedule']).strip.gsub(/\r+\n/, $/)) << "\n"
|
14
|
2234 text = purify(text)
|
2
|
2235 replace = (/modify/i =~ @params['editmode'])
|
|
2236 rc = @sc.register(registerer, y, m, d, timedir, text, replace)
|
|
2237 if @params['pub'] && /yes/ =~ @params['pub']
|
|
2238 @sc.putfile(registerer, y, m, d, timedir, 'pub', "1\n")
|
|
2239 else
|
|
2240 @sc.removefile(registerer, y, m, d, timedir, 'pub')
|
|
2241 end
|
|
2242 ######## @O.print @H.p(msg('appended')) if rc == 1
|
|
2243 rescue
|
|
2244 outputError("Failed"+$!)
|
|
2245 end
|
17
|
2246 text = @sc.getschedule(registerer, y, m, d, timedir)
|
2
|
2247 reg_notify(registerer, y, m, d, timedir, text)
|
|
2248
|
0
|
2249 end
|
2
|
2250
|
|
2251 end
|
|
2252
|
|
2253 if !remove && @params['rightnow'] && /yes/i =~ @params['rightnow']
|
|
2254 header = sprintf("%s\n%s/%s/%s%s %s %s\n%s%s%s\n%s\n",
|
|
2255 @opt['url'],
|
|
2256 sy, sm, sd,
|
|
2257 if daylist.length > 1
|
|
2258 "-%s/%s/%s" % daylist[-1]
|
|
2259 end,
|
|
2260 tmstr, msg('immediatenote'),
|
|
2261 msg('registerer_is'), nickname(registerer),
|
|
2262 if user!=registerer
|
|
2263 sprintf(" (%s%s)",
|
|
2264 msg('registerer'), nickname(user))
|
|
2265 else
|
|
2266 ""
|
|
2267 end,
|
|
2268 "-"*70)
|
|
2269 sendnotify(registerer, "Registration completed", header+text)
|
0
|
2270 end
|
14
|
2271 unless @mailmode
|
|
2272 show(sprintf("%04d/%02d/%02d", sy, sm, sd))
|
|
2273 @O.print "add_remove" if user == @author
|
|
2274 end
|
0
|
2275 end
|
|
2276
|
|
2277 # add
|
|
2278 def addsched()
|
14
|
2279 if "move" == @params['editmode']
|
|
2280 add_remove(:remove)
|
|
2281 for p in %w(year month day time) do
|
|
2282 @params[p] = @params["new"+p]
|
|
2283 end
|
|
2284 end
|
|
2285 add_remove(/^remove/i =~ @params['editmode'])
|
0
|
2286 end
|
|
2287
|
|
2288 #
|
|
2289 # Display remove or modify screen
|
14
|
2290 def remove_modify(datetime, editmode)
|
0
|
2291 if !checkauth
|
|
2292 return nil
|
|
2293 end
|
|
2294
|
|
2295 user = @params['user']
|
|
2296 y, m, d, time, dummy, as =
|
|
2297 datetime.scan(%r,(\d\d\d\d+)/(\d+)/(\d+)/(\d+)(/(.+))?,)[0]
|
|
2298 # datetime always contains trailing slash generated by parsedate
|
|
2299 # but if the trailing part is a user(not a group), it is removed
|
|
2300 # because it filtered out by grepgroup() function
|
|
2301 if ! (y && m && d && time)
|
|
2302 outputError "Invalid time specification"
|
|
2303 return nil
|
|
2304 elsif as && as > ''
|
|
2305 unless @sc.ismember(user, as)
|
|
2306 outputError "You have no permission to edit group %s's schedule", as
|
|
2307 return nil
|
|
2308 end
|
|
2309 user = as
|
|
2310 end
|
|
2311 unless text=@sc.getschedule(user, y, m, d, time)
|
|
2312 outputError "%s %s", datetime, msg('noplan')
|
|
2313 return nil
|
|
2314 end
|
15
|
2315 text = decode(text)
|
0
|
2316 @O.print @H.elementln("h1"){
|
14
|
2317 sprintf "%s %s", datetime, msg(editmode)
|
0
|
2318 }
|
|
2319 @O.print @H.elementln("form", {'action'=>@myname+"?-addsched", 'method'=>'POST'}){
|
|
2320 pubp=(@sc.getfile(user, y, m, d, time, 'pub').to_i > 0)
|
|
2321 if as
|
|
2322 @H.hidden("registas", as)
|
|
2323 end.to_s + \
|
|
2324 "<input type=\"hidden\" name=\"year\" value=\"%04d\">\n" % y.to_i + \
|
|
2325 "<input type=\"hidden\" name=\"month\" value=\"%02d\">\n" % m.to_i + \
|
|
2326 "<input type=\"hidden\" name=\"day\" value=\"%02d\">\n" % d.to_i + \
|
|
2327 "<input type=\"hidden\" name=\"time\" value=\"%04d\">\n" % time.to_i + \
|
14
|
2328 if editmode=="move"
|
|
2329 @H.elementln("table") {
|
|
2330 @H.elementln("tr", {"colspan" => "2"}) {msg('newdate')} + \
|
|
2331 @H.elementln("tr") {
|
|
2332 @H.element("th"){"Year"} + \
|
|
2333 @H.element("td"){@H.select("newyear", y.to_i..y.to_i+5, y)}
|
|
2334 } + \
|
|
2335 @H.elementln("tr") {
|
|
2336 @H.element("th"){"Month"} + \
|
|
2337 @H.element("td"){@H.select("newmonth", 1..12, m)}
|
|
2338 } + \
|
|
2339 @H.elementln("tr") {
|
|
2340 @H.element("th"){"Day"} + \
|
|
2341 @H.element("td"){@H.select("newday", 1..31, d)}
|
|
2342 } + \
|
|
2343 @H.elementln("tr") {
|
|
2344 @H.element("th"){"Time"} + \
|
|
2345 @H.element("td"){
|
|
2346 "<input type=text name=\"newtime\" value=\"#{time}\" " + \
|
|
2347 "size=\"8\" maxlength=\"4\">"
|
|
2348 }
|
|
2349 }
|
|
2350 }
|
|
2351 end.to_s + \
|
|
2352 @H.elementln("div", {"style" =>
|
|
2353 "visibility: " +
|
|
2354 (editmode=="move" ? "hidden" : "show") + "\""}) {
|
|
2355 msg('reqnotify') + "<br>\n" + \
|
|
2356 @ntlist.collect{|nt, v|
|
|
2357 cronp = @sc.getfile(user, y, m, d, time, nt)
|
|
2358 sprintf "<input type=\"checkbox\" name=\"%s\"%s>%s \n",
|
|
2359 nt, (cronp ? " checked" : ""), v
|
|
2360 }.join + "<br>"
|
|
2361 } + \
|
0
|
2362 @H.element("textarea", @schedulearea) {text} + "<br>" + \
|
|
2363 @H.radio("editmode", "append", msg('append')) + ' / ' + \
|
14
|
2364 @H.radio("editmode", "modify", msg('modify'), editmode=="modify")+' / '+\
|
|
2365 @H.radio("editmode", "remove", msg('remove'), editmode=="remove")+' / '+\
|
|
2366 @H.radio("editmode", "move", msg('move'), editmode=="move") + ' / ' + \
|
0
|
2367 "<br>\n" + \
|
|
2368 msg('publicok') + \
|
|
2369 @H.radio("pub", "yes", msg('yes'), pubp) + \
|
|
2370 @H.radio("pub", "no", msg('no'), !pubp) + \
|
|
2371 '<br>' + \
|
|
2372 @H.submit_reset("GO")
|
|
2373 }
|
|
2374 @O.print "remove_modify" if user == @author
|
|
2375 end
|
|
2376 def remove(datetime)
|
14
|
2377 remove_modify(datetime, "remove")
|
0
|
2378 end
|
|
2379 def modify(datetime)
|
14
|
2380 remove_modify(datetime, "modify")
|
|
2381 end
|
|
2382 def move(datetime)
|
|
2383 remove_modify(datetime, "move")
|
0
|
2384 end
|
|
2385
|
|
2386 def prohibitviahttp()
|
|
2387 %w[REMOTE_ADDR REMOTE_HOST SERVER_NAME].each{|v|
|
|
2388 if ENV[v]
|
|
2389 print "Content-type: text/plain\n\n"
|
|
2390 print "Do not call this via CGI"
|
|
2391 exit 0
|
|
2392 end
|
|
2393 }
|
|
2394 end
|
|
2395 #
|
|
2396 # notify: call via cron
|
|
2397 def notify()
|
|
2398 prohibitviahttp()
|
|
2399 unless @opt['maintainer']
|
|
2400 STDERR.printf "Set maintainer(email-address) in %s\n", @opt['conf']
|
|
2401 STDERR.print "(ex) maintainer=yuuji@gentei.org\n"
|
|
2402 exit 0
|
|
2403 end
|
|
2404 Dir.chdir @mydir
|
|
2405 line = "-"*25
|
|
2406 indent = " "
|
|
2407 now = Time.now
|
|
2408 p "notifylist", @sc.notify_list(now) if $DEBUG
|
|
2409 @sc.notify_list(now).each{|u, datehash|
|
|
2410 dellist = []
|
|
2411 content = datehash.sort.collect{|date, filehash|
|
|
2412 next unless /(\d\d\d\d+)-(\d+)-(\d+)-(\d\d\d\d)/ =~ date
|
|
2413 y, m, d, t = $1.to_i, $2.to_i, $3.to_i, $4.to_i
|
11
|
2414 ddiff=(Time.mktime(y, m, d) \
|
|
2415 - Time.mktime(now.year, now.month, now.day))/3600/24
|
0
|
2416 if t > 2359
|
|
2417 hhmm = msg('allday')
|
11
|
2418 if ddiff > 1
|
|
2419 comment = "%d%s" % [ddiff, msg('days', 'before')]
|
|
2420 else
|
|
2421 comment = msg(now.hour > 18 ? 'precedingday' : 'theday')
|
|
2422 end
|
0
|
2423 else
|
|
2424 hhmm = sprintf "%02d:%02d", t/100, t%100
|
2
|
2425 diff = Time.mktime(y, m, d, t/100, t%100) - now
|
0
|
2426 if diff < 7200
|
|
2427 comment = "%d%s" % [diff/60, msg('minutes', 'before')]
|
11
|
2428 elsif (ddiff == 0)
|
0
|
2429 comment = "%s%d%s" %
|
|
2430 [msg('about'), diff/3600, msg('hours', 'before')]
|
|
2431 else
|
|
2432 comment = "%d%s" % [ddiff, msg('days', 'before')]
|
|
2433 end
|
|
2434 end
|
|
2435 dellist << filehash['file']
|
|
2436 sprintf("%s[[[%d/%d/%d %s]]]%s\n", line, y, m, d, hhmm, line) + \
|
|
2437 sprintf("(%s %s)\n", comment, msg('notification')) + \
|
15
|
2438 indent+decode(filehash['text'].join(indent)) + "\n\n"
|
0
|
2439 }
|
|
2440 # content.delete(nil)
|
|
2441 if content
|
|
2442 if $DEBUG
|
|
2443 print content
|
|
2444 else
|
|
2445 content.unshift(msg('introduce')+"\n"+msg('notifymail')+"\n")
|
|
2446 content.unshift(@opt['url'].to_s+"\n")
|
|
2447 if sendnotify(u, msg('notifysubj'), content.join)
|
|
2448 # send mail completed
|
|
2449 begin
|
|
2450 @sc.cleanup_files(dellist)
|
|
2451 rescue
|
|
2452 end
|
|
2453 end
|
|
2454 end
|
|
2455 end
|
|
2456 }
|
|
2457 if !(list=@sc.notify_list(now)).empty?
|
|
2458 subj = @mybase+": Undeleted old cron files detected"
|
|
2459 files = list.collect{|who, whash|
|
|
2460 whash.sort.collect{|date, fhash| fhash['file']}.join("\n")
|
|
2461 }.join("\n")
|
|
2462 sendMail(@opt['maintainer'], subj,
|
|
2463 "This is `#{@mybase}' in #{@mydir}\n" +
|
|
2464 "You'd better check and remove these files.\n\n"+files)
|
|
2465 end
|
|
2466
|
|
2467 exit 0
|
|
2468 end
|
|
2469
|
|
2470 #
|
|
2471 # user management
|
|
2472 def userman()
|
|
2473 if !checkauth
|
|
2474 return nil
|
|
2475 end
|
|
2476 user=@params['user']
|
|
2477 nickname = @sc.nickname(user)
|
|
2478 tdclass = {}
|
|
2479 tdclass["width"] = "80px" if @oldagent # workaround for NN4
|
|
2480
|
|
2481 @O.print @H.elementln("h1"){
|
|
2482 @mybase+' '+msg('user', 'management')
|
|
2483 }
|
|
2484 @O.print @H.p(@sc.mkusermap.inspect) if $DEBUG
|
|
2485 @O.print @H.p(msg('usermodwarn'))
|
|
2486 @O.print \
|
|
2487 @H.elementln("form", {'action'=>@myname+"?-usermod", 'method'=>'POST'}){
|
|
2488 @H.elementln("table"){
|
|
2489 @H.elementln("tr"){
|
|
2490 @H.element("td", tdclass) {msg('regaddress')} + \
|
|
2491 @H.element("td") {
|
|
2492 @H.element("code"){user}
|
|
2493 }
|
|
2494 } + \
|
|
2495 @H.elementln("tr"){
|
|
2496 @H.element("td", tdclass) {msg('mailaddress')} + \
|
|
2497 @H.element("td") {
|
|
2498 @H.text("newmail", mailaddress(user), @opt['size'], 80)
|
|
2499 }
|
|
2500 } + \
|
|
2501 @H.elementln("tr"){
|
|
2502 @H.element("td", tdclass) {msg('weburl')} + \
|
|
2503 @H.element("td") {
|
|
2504 @H.text("webpage", webpage(user), @opt['size'], 80)
|
|
2505 }
|
|
2506 } + \
|
|
2507 @H.elementln("tr"){
|
|
2508 @H.element("td") {msg('nickname')} + \
|
|
2509 @H.element("td") {
|
|
2510 @H.text("nickname", nickname, @opt['size'], 10)
|
|
2511 }
|
|
2512 }
|
|
2513 } + \
|
|
2514 @H.elementln("p"){
|
|
2515 msg('shortnameplz') + "<br>\n" + \
|
|
2516 @H.a(@after5url+"multiplenotify.html", msg('multiplemail'))
|
|
2517 } + \
|
|
2518 '<br>' + \
|
|
2519 @H.submit_reset("GO")
|
|
2520 } # form
|
|
2521
|
|
2522 #
|
|
2523 # Next section, REMOVE USER!
|
|
2524 @O.print @H.elementln("h2"){
|
|
2525 sprintf "%s %s %s", msg('user'), user, msg('deletion')
|
|
2526 }
|
|
2527 @O.print @H.p(msg('deletionwarn'))+"\n"
|
|
2528 @O.print @H.elementln("form", {'action'=>@myname+"?-delusersub+#{user}", 'method'=>'POST'}){
|
|
2529 @H.hidden("user", user) + "\n" + \
|
|
2530 @H.elementln("table"){
|
|
2531 @H.elementln("tr"){
|
|
2532 @H.elementln("td"){
|
|
2533 sprintf msg('deluser'), user
|
|
2534 } + \
|
|
2535 @H.elementln("td"){
|
|
2536 @H.radio("delete", "yes", msg('yes')) + ' ' + \
|
|
2537 @H.radio("delete", "no", msg('no'), true)
|
|
2538 }
|
|
2539 } + \
|
|
2540 @H.elementln("tr"){
|
|
2541 @H.elementln("td"){
|
|
2542 sprintf msg('really?'), user
|
|
2543 } + \
|
|
2544 @H.elementln("td"){
|
|
2545 @H.radio("delete2", "yes", msg('yes')) + ' ' + \
|
|
2546 @H.radio("delete2", "no", msg('no'), true)
|
|
2547 }
|
|
2548 }
|
|
2549 } + \
|
|
2550 "<br>\n" + @H.submit_reset("GO")
|
|
2551 }
|
|
2552
|
|
2553
|
|
2554 end
|
|
2555 def usermod()
|
|
2556 if !checkauth
|
|
2557 return nil
|
|
2558 end
|
|
2559 @O.print @H.elementln("h1"){
|
|
2560 msg('user', 'management')+" "+msg('done')
|
|
2561 }
|
|
2562 user=@params['user']
|
|
2563 email = mailaddress(user)
|
|
2564 newmail = @params['newmail']
|
|
2565 nickname = @sc.nickname(user)
|
|
2566 newnn = @params['nickname'].to_s.strip
|
|
2567 webpage = webpage(user)
|
|
2568 newweb = @params['webpage']
|
|
2569 if email != newmail
|
|
2570 # change user's address
|
|
2571 if newmail == user
|
|
2572 newvalue = nil
|
|
2573 elsif checkmail(newmail)
|
|
2574 newvalue = newmail
|
|
2575 else
|
|
2576 @O.print @H.elementln("pre"){"Invalid mail address"}
|
|
2577 end
|
|
2578 @O.print @H.elementln("pre"){
|
|
2579 if @sc.putuserattr(user, 'email', newvalue)
|
|
2580 sprintf "new mail address=\"%s\"", mailaddress(user)
|
|
2581 else
|
|
2582 sprintf "Setting new mail address to \"%s\" failed", newvalue
|
|
2583 end
|
|
2584 }
|
|
2585 end
|
|
2586 if nickname != newnn
|
|
2587 if @sc.setnickname(user, newnn)
|
|
2588 @O.print @H.p(msg('success'))
|
|
2589 @O.print @H.elementln("pre"){
|
|
2590 sprintf "user=\"%s\"\nnickname=\"%s\"", user, @sc.nickname(user)
|
|
2591 }
|
|
2592 @O.print @H.p(msg('nicknamenote')) if newnn == ''
|
|
2593 else
|
|
2594 @O.print @H.p(msg('failure'))
|
|
2595 end
|
|
2596 end
|
|
2597 if newweb > '' && webpage != newweb
|
|
2598 if @sc.putuserattr(user, "webpage", newweb)
|
|
2599 @O.print @H.p(msg('success'))
|
|
2600 @O.print @H.elementln("pre"){
|
|
2601 sprintf "user=\"%s\"\nwebpage=\"%s\"", user, webpage(user)
|
|
2602 }
|
|
2603 else
|
|
2604 @O.print @H.p("Update webpage"+msg('failure'))
|
|
2605 end
|
|
2606 end
|
|
2607 end
|
|
2608 #
|
|
2609 # Display form of group management
|
|
2610 def groupman()
|
|
2611 if !checkauth
|
|
2612 return nil
|
|
2613 end
|
|
2614 user=@params['user']
|
|
2615 nickname = @sc.nickname(user)
|
|
2616 tdclass = {}
|
|
2617 tdclass["width"] = "80px" if @oldagent # workaround for NN4
|
|
2618 admclass = {'class'=>'admin'}
|
|
2619 grmap = @sc.groupmap
|
|
2620
|
|
2621 @O.print @H.elementln("h1"){
|
|
2622 @mybase+' '+msg('group', 'management')
|
|
2623 }
|
|
2624 $KCODE='e' if $DEBUG
|
|
2625 @O.print grmap.inspect if $DEBUG
|
|
2626 @O.print @H.p(msg('joinmyself')+
|
|
2627 @H.a(@myname+"?-newgroup", msg('newgroup')))
|
|
2628 @O.print @H.p(msg('usermodwarn'))
|
|
2629 @O.print \
|
|
2630 @H.elementln("form", {'action'=>@myname+"?-groupmod", 'method'=>'POST'}){
|
|
2631 @H.elementln("table", {'border'=>'1', 'vertical-align'=>'top'}){
|
|
2632 grmap.collect{|g, ghash|
|
|
2633 @H.elementln("tr"){
|
|
2634 @H.element("td", @sc.isadmin(user, g) ? admclass : nil){
|
|
2635 g
|
|
2636 } + \
|
|
2637 @H.element("td"){
|
|
2638 @H.element("div", {'class'=>'c'}) {
|
|
2639 if @sc.isadmin(user, g)
|
|
2640 @H.a(@myname+"?-admgroup+#{g}", msg('adminop'))
|
|
2641 else
|
|
2642 '--'
|
|
2643 end
|
|
2644 }
|
|
2645 } + \
|
|
2646 @H.element("td"){
|
|
2647 memberp = @sc.ismember(user, g)
|
|
2648 if ghash['admin'].grep(user)[0]
|
|
2649 @H.text("groupname-#{g}", ghash['name'], nil, 20)
|
|
2650 else
|
|
2651 ghash['name']
|
|
2652 end + '<br>' + \
|
|
2653 @H.radio("groupadd-#{g}", "yes", "IN", memberp) + " / " + \
|
|
2654 @H.radio("groupadd-#{g}", "no", "OUT", !memberp)
|
|
2655 } + \
|
|
2656 @H.element("td"){
|
|
2657 ghash['members'].collect{|u|
|
|
2658 @sc.nickname(u)
|
|
2659 }.join(", ")
|
|
2660 }
|
|
2661 }
|
|
2662 }
|
|
2663 } + \
|
|
2664 '' + \
|
|
2665 @H.p(msg('groupwarn', 'shortnameplz')) + \
|
|
2666 @H.submit_reset("GO")
|
|
2667 } # form
|
|
2668 end
|
2
|
2669 def groupnamesString()
|
|
2670 @H.elementln("p", {'class'=>'listup'}){
|
|
2671 @sc.groups().collect{|g|@sc.groupname(g)}.join(", ")
|
|
2672 }
|
|
2673 end
|
0
|
2674 def groupmod()
|
|
2675 if !checkauth
|
|
2676 return nil
|
|
2677 end
|
|
2678 @O.print @H.elementln("h1"){
|
|
2679 msg('group', 'management')+" "+msg('done')
|
|
2680 }
|
|
2681 user=@params['user']
|
|
2682 @O.print @params.inspect if $DEBUG
|
|
2683
|
|
2684 for grp in @sc.groups()
|
|
2685 #
|
|
2686 # as a member, participate or retire
|
|
2687 key = "groupadd-#{grp}"
|
|
2688 removep = (/no/i =~ @params[key])
|
|
2689 memberp = @sc.ismember(user, grp)
|
|
2690 if @params[key]
|
|
2691 if (!removep) ^ memberp
|
|
2692 @sc.addgroup(grp, [user], removep)
|
|
2693 @O.print @H.elementln("p"){
|
|
2694 sprintf "%s [%s] %s %s", msg('user'), user,
|
|
2695 removep ? msg('removedfromgp') : msg('addedtogroup'), grp
|
|
2696 }
|
|
2697 end
|
|
2698 end
|
|
2699 #
|
|
2700 # as a owner, change the name of group
|
|
2701 if @sc.isadmin(user, grp) &&
|
|
2702 (newname = @params["groupname-#{grp}"]) &&
|
|
2703 @sc.groupname(grp) != newname
|
2
|
2704 @O.printf "@sc.name2group=%s<br>\n", @sc.name2group(newname)
|
|
2705 if dupl=@sc.name2group(newname)
|
|
2706 @O.print @H.p(sprintf(msg('dupname'), newname))
|
|
2707 @O.print groupnamesString()
|
|
2708
|
|
2709 else
|
|
2710 @sc.setgroupname(grp, newname)
|
|
2711 @O.print @H.elementln("p"){
|
|
2712 sprintf "%s %s%s %s",
|
|
2713 msg('group'), grp, msg('of', 'name', 'setto'), newname
|
|
2714 }
|
|
2715 end
|
0
|
2716 end
|
|
2717 end
|
|
2718 end
|
|
2719 def users()
|
|
2720 unless pm=open_pm()
|
|
2721 outputError(msg('autherror'))
|
|
2722 return nil
|
|
2723 end
|
|
2724 pm.users
|
|
2725 end
|
|
2726 def grepgroup(gname)
|
|
2727 gr = @sc.groups.grep(gname)[0]
|
|
2728 end
|
|
2729 def admgroup(group = nil)
|
|
2730 # if group==nil, create new
|
|
2731 if !checkauth
|
|
2732 return nil
|
|
2733 end
|
|
2734 @O.print @H.elementln("h1"){
|
|
2735 msg('group', 'management')
|
|
2736 }
|
|
2737 user=@params['user']
|
|
2738
|
|
2739 # Check the existent group's validity
|
|
2740 if group
|
|
2741 unless (gr=grepgroup(group))
|
|
2742 @O.print @H.p("No such group #{group}")
|
|
2743 return nil
|
|
2744 end
|
|
2745 group = gr
|
|
2746 unless @sc.isadmin(user, group)
|
|
2747 @O.print @H.p("You are not administrator of #{group}.")
|
|
2748 return nil
|
|
2749 end
|
|
2750 @O.print @H.elementln("h2"){
|
|
2751 msg('group')+" #{group}" +
|
|
2752 if group != @sc.groupname(group)
|
|
2753 " (#{@sc.groupname(group)})"
|
|
2754 end.to_s
|
|
2755 }
|
|
2756 actionmethod={'action'=>@myname+"?-admgroupsub", 'method'=>'POST'}
|
|
2757 else
|
|
2758 # New group creation
|
|
2759 @O.print @H.elementln("h2"){
|
|
2760 msg('newgroup')
|
|
2761 }
|
|
2762 actionmethod={'action'=>@myname+"?-newgroupsub", 'method'=>'POST'}
|
|
2763 end
|
|
2764
|
|
2765 userlist = ([user] + users()).uniq
|
|
2766 myselfclass = {'class'=>'admin'}
|
|
2767 colspan2 = {'colspan'=>'2'}
|
|
2768 warnclass = {'class'=>'warn'}
|
|
2769 warnp = nil
|
|
2770
|
|
2771 @O.print @H.elementln("form", actionmethod){
|
|
2772 @H.hidden('group', group) + "\n" + \
|
|
2773 if group
|
|
2774 ""
|
|
2775 else
|
|
2776 # new group creation
|
|
2777 grps = @sc.groups()
|
|
2778 i=1
|
|
2779 defname = "group%03d"%i
|
|
2780 while grps.grep(defname)[0]
|
|
2781 defname = "group%03d"%(i+=1)
|
|
2782 end
|
|
2783 @H.element("pre"){
|
|
2784 msg('group', 'of', 'id')+"\n"+@H.text("group", defname) + "\n" + \
|
|
2785 msg('group', 'of', 'name', 'anystring')+"\n"+ \
|
|
2786 @H.text("gname", '') + "\n"
|
|
2787 }
|
|
2788 end + \
|
|
2789 @H.elementln("table", {'border'=>'1'}){
|
|
2790 @H.elementln("tr"){
|
|
2791 @H.element("th"){msg('join')} + \
|
|
2792 @H.element("th"){msg('administrator')} + \
|
|
2793 @H.element("th"){msg('member')}
|
|
2794 } + \
|
|
2795 userlist.collect{|u|
|
|
2796 recursememp = nil
|
|
2797 if group
|
|
2798 memberp = (@sc.ismember(u, group) && true)
|
|
2799 adminp = (@sc.isadmin(u, group) && true)
|
|
2800 if !memberp && @sc.members(group).grep(u)[0]
|
|
2801 recursememp = true
|
|
2802 end
|
|
2803 else
|
|
2804 memberp = adminp = (u == user)
|
|
2805 end
|
|
2806 @H.elementln("tr", (u==user ? myselfclass : nil)){
|
|
2807 @H.element("td"){
|
|
2808 @H.radio('mem-'+u, 'yes', 'YES / ', memberp) + \
|
|
2809 @H.radio('mem-'+u, 'no', 'NO', !memberp)
|
|
2810 } + \
|
|
2811 @H.element("td"){
|
|
2812 @H.radio('adm-'+u, 'yes', 'YES / ', adminp) + \
|
|
2813 @H.radio('adm-'+u, 'no', 'NO', !adminp)
|
|
2814 } + \
|
|
2815 @H.element("td"){
|
|
2816 @sc.nickname(u) + \
|
|
2817 if recursememp
|
|
2818 warnp = true
|
|
2819 @H.element("span", warnclass){"(*)"}
|
|
2820 end.to_s
|
|
2821 }
|
|
2822 }
|
|
2823 }.join + \
|
|
2824 # group names
|
|
2825 @H.elementln("tr"){
|
|
2826 @H.element("th", colspan2){msg('join')} + \
|
|
2827 @H.element("th"){msg('group')}
|
|
2828 } + \
|
|
2829 @sc.groups().collect{|g|
|
|
2830 next if group == g
|
|
2831 memberp = @sc.ismember(g, group)
|
|
2832 @H.element("tr"){
|
|
2833 @H.element("td", colspan2){
|
|
2834 @H.radio('mem-'+g, 'yes', 'YES / ', memberp) + \
|
|
2835 @H.radio('mem-'+g, 'no', 'NO', !memberp)
|
|
2836 } + \
|
|
2837 @H.element("td"){
|
|
2838 if @sc.isadmin(user, g)
|
|
2839 @H.a(@myname+"?-admgroup+#{g}", @sc.groupname(g))
|
|
2840 else
|
|
2841 @sc.groupname(g)
|
|
2842 end
|
|
2843 }
|
|
2844 }
|
|
2845 }.join
|
|
2846 } + "<br>\n" + \
|
|
2847 @H.submit_reset("GO")
|
|
2848 } # form
|
|
2849 @O.print @H.p(@H.element("span", warnclass){"(*)"}+
|
|
2850 msg('recursewarn')) if warnp
|
2
|
2851 if group && (members = @sc.members(group))[0]
|
0
|
2852 @O.print @H.p(sprintf(msg('wholemembers'), group))
|
|
2853 @O.print @H.elementln("p", {'class'=>'listup'}){
|
2
|
2854 members.collect{|u|@sc.nickname(u)}.join(", ")}
|
0
|
2855 end
|
|
2856
|
|
2857 #
|
|
2858 # Next section, REMOVE GROUP!
|
|
2859 return nil unless group
|
|
2860 @O.print @H.elementln("h2"){
|
|
2861 sprintf "%s %s %s", msg('group'), group, msg('deletion')
|
|
2862 }
|
|
2863 @O.print @H.p(msg('deletionwarn'))+"\n"
|
|
2864 @O.print @H.elementln("form", {'action'=>@myname+"?-delgroupsub+#{group}", 'method'=>'POST'}){
|
|
2865 @H.hidden("group", group) + "\n" + \
|
|
2866 @H.elementln("table"){
|
|
2867 @H.elementln("tr"){
|
|
2868 @H.elementln("td"){
|
|
2869 sprintf msg('delgroup'), group
|
|
2870 } + \
|
|
2871 @H.elementln("td"){
|
|
2872 @H.radio("delete", "yes", msg('yes')) + ' ' + \
|
|
2873 @H.radio("delete", "no", msg('no'), true)
|
|
2874 }
|
|
2875 } + \
|
|
2876 @H.elementln("tr"){
|
|
2877 @H.elementln("td"){
|
|
2878 sprintf msg('really?'), group
|
|
2879 } + \
|
|
2880 @H.elementln("td"){
|
|
2881 @H.radio("delete2", "yes", msg('yes')) + ' ' + \
|
|
2882 @H.radio("delete2", "no", msg('no'), true)
|
|
2883 }
|
|
2884 }
|
|
2885 } + \
|
|
2886 "<br>\n" + @H.submit_reset("GO")
|
|
2887 }
|
|
2888
|
|
2889 @O.print footer()
|
|
2890 end
|
|
2891 def newgroup()
|
|
2892 admgroup(nil)
|
|
2893 end
|
|
2894
|
|
2895 def delgroupsub(group)
|
|
2896 if !checkauth
|
|
2897 return nil
|
|
2898 end
|
|
2899 user = @params['user']
|
|
2900 if group != @params['group']
|
|
2901 @O.print @H.p("Group mismatch")
|
|
2902 return nil
|
|
2903 end
|
|
2904 unless (gr=grepgroup(group))
|
|
2905 @O.print @H.p("No such group #{group}")
|
|
2906 return nil
|
|
2907 end
|
|
2908 group = gr
|
|
2909 unless @sc.isadmin(user, group)
|
|
2910 @O.print @H.p("You are not administrator of #{group}.")
|
|
2911 return nil
|
|
2912 end
|
|
2913 unless @params['delete'] && /yes/i =~ @params['delete'] \
|
|
2914 && @params['delete2'] && /yes/i =~ @params['delete2']
|
|
2915 @O.print @H.p(msg('chicken'))
|
|
2916 return nil
|
|
2917 end
|
|
2918 @O.print @H.elementln("h1"){
|
|
2919 msg('group')+" #{group} "+msg('deletion')
|
|
2920 }
|
|
2921 @O.print @H.p(@sc.destroygroup(group) ? msg("done") : msg("failure"))
|
|
2922
|
|
2923 @O.print footer()
|
|
2924 end
|
|
2925
|
|
2926 def deleteuser(user)
|
|
2927 @sc.deleteuser(user) &&
|
|
2928 begin
|
|
2929 pm = open_pm
|
|
2930 pm.delete(user)
|
|
2931 pm.close()
|
|
2932 true
|
|
2933 rescue
|
|
2934 nil
|
|
2935 end
|
|
2936 end
|
|
2937 def delusersub(user)
|
|
2938 if !checkauth
|
|
2939 return nil
|
|
2940 end
|
|
2941 user = @params['user']
|
|
2942 if user != @params['user']
|
|
2943 @O.print @H.p("User mismatch")
|
|
2944 return nil
|
|
2945 end
|
|
2946 unless (us=users().grep(user)[0])
|
|
2947 @O.print @H.p("No such user #{user}")
|
|
2948 return nil
|
|
2949 end
|
|
2950 user = us
|
|
2951 unless @params['delete'] && /yes/i =~ @params['delete'] \
|
|
2952 && @params['delete2'] && /yes/i =~ @params['delete2']
|
|
2953 @O.print @H.p(msg('chicken'))
|
|
2954 return nil
|
|
2955 end
|
|
2956 @O.print @H.elementln("h1"){
|
|
2957 msg('user')+" #{user} "+msg('deletion')
|
|
2958 }
|
|
2959 @O.print @H.p(deleteuser(user) ? msg("done") : msg("failure"))
|
|
2960
|
7
|
2961 @O.print @H.p(@H.a(@myname, msg('login')))
|
0
|
2962 end
|
|
2963
|
|
2964 def admgroupsub()
|
|
2965 if !checkauth
|
|
2966 return nil
|
|
2967 end
|
|
2968 user = @params['user']
|
|
2969 group = @params['group']
|
|
2970 unless (gr=grepgroup(group))
|
|
2971 @O.print @H.element("pre"){"No such group #{group.inspect}"}
|
|
2972 return nil
|
|
2973 end
|
|
2974 unless @sc.isadmin(user, group)
|
|
2975 @O.print @H.p("You are not administrator of #{group}.")
|
|
2976 return nil
|
|
2977 end
|
|
2978 gorup = gr
|
|
2979 @O.print @H.elementln("h1"){
|
|
2980 msg('group', 'management', 'done')
|
|
2981 }
|
|
2982 @O.print @H.elementln("h2"){
|
|
2983 msg('group')+" #{group}" +
|
|
2984 if group != @sc.groupname(group)
|
|
2985 " (#{@sc.groupname(group)})"
|
|
2986 end.to_s
|
|
2987 }
|
|
2988 somethingdone = nil
|
|
2989 for u in users()
|
2
|
2990 u = @sc.isuser(u) # users() value is considered tainted.
|
|
2991 next unless u # Use registered value in @sc.
|
0
|
2992 for var, kind in {
|
|
2993 "mem"=>['members', 'member'], 'adm'=>['admin', 'administrator']}
|
|
2994 memv = "#{var}-#{u}"
|
|
2995 if @params[memv]
|
|
2996 joinp = ((/^yes/i =~ @params[memv]) && true)
|
|
2997 membp = if var=='mem'
|
|
2998 @sc.ismember(u, group)
|
|
2999 else # admin
|
|
3000 @sc.isadmin(u, group)
|
|
3001 end && true
|
|
3002 if var=='adm' && @sc.admins(group).length == 1 && membp && !joinp
|
|
3003 @O.print @H.p(sprintf(msg('soleadmin'), u, group))
|
|
3004 elsif joinp ^ membp
|
|
3005 somethingdone = true
|
|
3006 @sc.addgroup(group, [u], !joinp, kind[0])
|
|
3007 @O.print @H.elementln("p"){
|
|
3008 sprintf "%s [%s](%s) %s %s", msg('user'), u,
|
|
3009 msg(kind[1]),
|
|
3010 joinp ? msg('addedtogroup'): msg('removedfromgp'), group
|
|
3011 }
|
|
3012 end
|
|
3013 end
|
|
3014 end
|
|
3015 end # users()
|
|
3016
|
|
3017 # add or remove for group in groups
|
|
3018 for g in @sc.groups()
|
|
3019 next if g == group
|
|
3020 memv = "mem-#{g}"
|
|
3021 if @params[memv]
|
|
3022 joinp = ((/^yes/i =~ @params[memv]) && true)
|
|
3023 membp = (@sc.ismember(g, group) && true)
|
|
3024 if joinp ^ membp
|
|
3025 somethingdone = true
|
|
3026 @sc.addgroup(group, [g], !joinp)
|
|
3027 @O.print @H.elementln("p"){
|
|
3028 sprintf "%s [%s] %s %s", msg('group'), g,
|
|
3029 joinp ? msg('addedtogroup'): msg('removedfromgp'), group
|
|
3030 }
|
|
3031 end
|
|
3032 end
|
|
3033 end # groups
|
|
3034 unless somethingdone
|
|
3035 # @O.print @H.p(msg('nothingtodo'))
|
|
3036 end
|
|
3037 @O.print footer()
|
|
3038 end
|
|
3039 def newgroupsub()
|
|
3040 if !checkauth
|
|
3041 nil
|
|
3042 end
|
|
3043 user = @params['user']
|
|
3044 newgroup = @params['group']
|
|
3045 newgname = @params['gname']
|
|
3046
|
|
3047
|
|
3048 if @sc.groups.grep(newgroup)[0]
|
|
3049 @O.print @H.p(msg('existent')+newgroup)
|
|
3050 return nil
|
|
3051 end
|
2
|
3052 if dupl=@sc.name2group(newgname)
|
|
3053 @O.print @H.p(sprintf(msg('dupname'), newgname))
|
|
3054 @O.print groupnamesString()
|
|
3055 return nil
|
|
3056 end
|
0
|
3057 @sc.creategroup(newgroup, newgname, [user])
|
|
3058 admgroup(newgroup)
|
|
3059 end
|
|
3060
|
14
|
3061 #
|
|
3062 # Methods Related to viaMail functions
|
|
3063 def gen_sessionpswd()
|
|
3064
|
|
3065 end
|
|
3066 def viamail_registform()
|
|
3067 c = "# "
|
|
3068 nl = "\n"
|
|
3069 user = @params['user']
|
|
3070 msg('addsched') + "-" * 20 + nl*2 + \
|
|
3071 c + msg('user') + nl + \
|
|
3072 "user=" + user + nl*2 + \
|
|
3073 c + msg('sessionpswd') + nl + \
|
|
3074 "sp=hoge" + nl*2 + \
|
|
3075 c + msg('date') + nl + \
|
|
3076 "date="+Time.now.strftime("%Y/%m/%d") + nl*2 + \
|
|
3077 c + msg('time') + sprintf(msg('24hourtxt'), @opt['alldaydir']) + nl + \
|
|
3078 "time=3000"+nl*2 + \
|
|
3079 c + msg('publicp') + nl + \
|
|
3080 "public=yes" + nl*2 + \
|
|
3081 c + msg('neednotify') + nl + \
|
|
3082 "nt10m=yes (%s)
|
|
3083 nttoday=yes (%s)
|
|
3084 nt1d=yes (%s)
|
|
3085 nt7d=yes (%s)" % ["10"+msg('minutes')+msg('before'),
|
|
3086 msg('theday'), msg('precedingday'),
|
|
3087 "7"+msg('days')+msg('before')] + nl*2 + \
|
|
3088
|
|
3089 c + msg('schedulehere')
|
|
3090 end
|
|
3091 def viamail_footer()
|
|
3092 viamail_registform()
|
|
3093 end
|
|
3094 def show_by_text(date, days)
|
|
3095 user = @params['user']
|
|
3096 personal = true
|
|
3097 sched = dayTextString(user, date, days, personal)
|
|
3098 # @O.print outstr
|
|
3099
|
|
3100 sendMail(mailaddress(user),
|
|
3101 "After5 Schedule",
|
|
3102 @opt['url'] + "\n" + \
|
|
3103 Time.now.strftime("%Y/%m/%d") + \
|
|
3104 sprintf(msg('schedlist'), days) + "\n\n" + \
|
|
3105 if sched > ''
|
|
3106 sched
|
|
3107 else
|
|
3108 msg('noplan')+"\n"
|
|
3109 end + \
|
|
3110 viamail_footer
|
|
3111 )
|
|
3112
|
|
3113 end
|
|
3114 def parseHeader
|
|
3115 contline=nil
|
|
3116 header=Hash.new
|
|
3117 text=Array.new
|
|
3118
|
|
3119 field=nil
|
|
3120 # header
|
|
3121 while line=STDIN.gets
|
|
3122 text << line
|
|
3123 break if /^$/ =~ line
|
|
3124
|
|
3125 if /^\s+/ =~ line
|
|
3126 if field
|
|
3127 header[field][-1] << line
|
|
3128 end
|
|
3129 else
|
|
3130 if /^([^:]+):\s*(.*)/ =~ line
|
|
3131 field=$1.downcase
|
|
3132 header[field] or header[field] = []
|
|
3133 header[field] << $2
|
|
3134 end
|
|
3135 end
|
|
3136 end
|
|
3137 header
|
|
3138 end
|
|
3139 def mail_regsched()
|
|
3140 @params = Hash.new # Reset
|
|
3141
|
|
3142 reqparams = %w[user sp date time public]
|
|
3143 otherparams = %w[nt10m nttoday nt1d nt7d]
|
|
3144 setall = lambda{
|
|
3145 reqparams.each{|key| return false unless @params.has_key?(key)}
|
|
3146 return true
|
|
3147 }
|
|
3148 stack = ""
|
|
3149 while line=gets # !setall.call && line=gets
|
|
3150 if /^(\S+)=(.*)/ =~ line
|
|
3151 next unless reqparams.index($1) || otherparams.index($1)
|
|
3152 @params[$1] = $2
|
|
3153 #if reqparams.index($1)
|
|
3154 STDERR.print "Set #{$1} to #{$2}\n"
|
|
3155 #end
|
|
3156 buf = ""
|
|
3157 elsif /^\s*\#|^$/ =~ line
|
|
3158 # skip comments
|
|
3159 else
|
|
3160 buf += line
|
|
3161 end
|
|
3162 end
|
|
3163 unless setall.call
|
|
3164 STDERR.print "Insufficient variables\n"
|
|
3165 exit 1
|
|
3166 end
|
|
3167 p buf
|
|
3168
|
|
3169 y, m, d = date2ymd(@params["date"])
|
|
3170 @params["year"] = y
|
|
3171 @params["month"] = m
|
|
3172 @params["day"] = d
|
|
3173 @params["schedule"] = buf
|
|
3174 @params["editmode"] = "modify"
|
|
3175 @params["sessionpw"] = @params["sp"]
|
|
3176 p @params
|
|
3177 add_remove()
|
|
3178 end
|
|
3179 def mail_getsched()
|
|
3180 user = nil
|
|
3181 while bline=gets
|
|
3182 if /(\S+@\S+)/ =~ bline
|
|
3183 break if user=@sc.isuser($1)
|
|
3184 end
|
|
3185 end
|
|
3186 unless user
|
|
3187 sendMail(@opt['maintainer'], "viaMail Request Error",
|
|
3188 "This is `#{@mybase}' in #{@mydir}\n" +
|
|
3189 "Invalid schedule request from #{ENV['SENDER']}.\n\n")
|
|
3190 exit 1
|
|
3191 end
|
|
3192 today = Time.now.strftime("%Y/%m/%d")
|
|
3193 days = 7
|
|
3194 if bline=gets
|
|
3195 if /\d+/ =~ bline
|
|
3196 days = bline.to_i
|
|
3197 end
|
|
3198 end
|
|
3199 # Send user to schedules of today and near future
|
|
3200 @params['user'] = user
|
|
3201 show_by_text(today, days)
|
|
3202 end
|
|
3203 def doMail()
|
|
3204 days = 7
|
|
3205 # Confirm `via Mail'
|
|
3206 prohibitviahttp()
|
|
3207 @H = TEXTout.new
|
|
3208 unless ENV['RECIPIENT'] && ENV['SENDER']
|
|
3209 STDERR.print "Call me via qmail\n"
|
|
3210 exit 1
|
|
3211 end
|
|
3212 @mailmode = true
|
|
3213 header = parseHeader # is this necessary?
|
|
3214 if /regist/ =~ ENV["EXT"]
|
|
3215 mail_regsched()
|
|
3216 else
|
|
3217 mail_getsched()
|
|
3218 end
|
|
3219 end
|
|
3220
|
|
3221 #
|
|
3222 # Password related Methos
|
0
|
3223 def setpasswd(user)
|
|
3224 prohibitviahttp()
|
|
3225 pm = open_pm()
|
|
3226 exit 1 unless pm
|
|
3227 if pm.userexist?(user) then
|
|
3228 begin
|
|
3229 system "stty -echo"
|
|
3230 STDERR.print "New passwd: "
|
|
3231 p1 = STDIN.gets
|
|
3232 STDERR.print "\nAgain: "
|
|
3233 p2 = STDIN.gets
|
|
3234 ensure
|
|
3235 system "stty echo"
|
|
3236 end
|
|
3237 if (p1 == p2) then
|
|
3238 pm.setpasswd(user, p1.chop!)
|
|
3239 end
|
|
3240 STDERR.print "New password for #{user} set successfully\n"
|
|
3241 else
|
|
3242 STDERR.print "User #{user} not found\n"
|
|
3243 end
|
|
3244 pm.close()
|
|
3245 exit 0
|
|
3246 end
|
|
3247 def adduser(user)
|
|
3248 prohibitviahttp()
|
|
3249 pm = open_pm()
|
|
3250 exit 1 unless pm
|
|
3251 newpwd = pm.setnewpasswd(user, 4)
|
|
3252 print "#{user}'s password is #{newpwd}\n"
|
|
3253 pm.close()
|
|
3254 exit 0
|
|
3255 end
|
|
3256 def deluser(user)
|
|
3257 prohibitviahttp()
|
|
3258 pm = open_pm()
|
|
3259 exit 1 unless pm
|
|
3260 pm.delete(user)
|
|
3261 pm.close()
|
|
3262 exit 0
|
|
3263 end
|
|
3264
|
|
3265 # read configuratoin file
|
|
3266 def readconf(conf)
|
|
3267 cf = "after5.cf" #conf # || @opt['conf']
|
|
3268 cf = File.join(@mydir, cf) unless test(?s, cf)
|
|
3269 cf = File.join(ENV["HOME"], cf) unless test(?s, cf)
|
|
3270 return unless test(?s, cf)
|
|
3271 begin
|
|
3272 IO.foreach(cf){|line|
|
|
3273 next if /^\s *#/ =~ line
|
|
3274 line.chop!
|
|
3275 line.sub!(/^\s*#.*/, '')
|
|
3276 next if /^$/ =~ line
|
|
3277 case line
|
|
3278 # title, type = line.split(/\t+/)
|
|
3279 when /^([a-z]+)=(.*)/oi
|
|
3280 key, value = $1, $2
|
|
3281 case value
|
6
|
3282 when /^(no|none|null|nil|false|0|off)$/io
|
0
|
3283 @opt[key] = nil
|
|
3284 else
|
|
3285 @opt[key] = value
|
|
3286 end
|
|
3287 print "#{key} set to #{value}\n" if $DEBUG
|
|
3288 end
|
|
3289 }
|
|
3290 rescue
|
|
3291 STDERR.print "Configuration file %s not readable\n", cf
|
|
3292 end
|
|
3293 end
|
|
3294
|
|
3295 def parsedate(string)
|
|
3296 if %r,^(\d\d\d\d+)/(\d+)/(\d+)/(\d+)/([^/]+)$, =~ string
|
|
3297 sprintf "%04d/%02d/%02d/%04d/%s", $1.to_i, $2.to_i, $3.to_i, $4.to_i,
|
|
3298 grepgroup($5)
|
|
3299 elsif %r,^(\d\d\d\d+)/(\d+)/(\d+)/(\d+), =~ string
|
|
3300 sprintf "%04d/%02d/%02d/%04d", $1.to_i, $2.to_i, $3.to_i, $4.to_i
|
|
3301 elsif %r,^(\d\d\d\d+)/(\d+)/(\d+), =~ string
|
|
3302 sprintf "%04d/%02d/%02d", $1.to_i, $2.to_i, $3.to_i
|
|
3303 elsif %r,^(\d\d\d\d+)/(\d+), =~ string
|
|
3304 sprintf "%04d/%02d", $1.to_i, $2.to_i
|
|
3305 elsif %r,^(\d\d\d\d+)/(\d+), =~ string
|
|
3306 sprintf "%04d", $1.to_i
|
|
3307 end
|
|
3308 end
|
|
3309
|
|
3310 def getarg()
|
|
3311 argument = {}
|
|
3312
|
|
3313 while /^-/ =~ ARGV[0]
|
|
3314 case ARGV[0]
|
|
3315 when '-f'
|
|
3316 conf = ARGV[1]
|
|
3317 ARGV.shift
|
|
3318 when "-d"
|
|
3319 $DEBUG = true
|
|
3320 when "-install"
|
14
|
3321 when "-stream"
|
|
3322 # ARGV.shift
|
|
3323 # @job = 'show_by_text "2005/1/18"'
|
|
3324 @job = 'doMail'
|
0
|
3325 when "-addsched"
|
|
3326 @job = "addsched"
|
|
3327 when "-today"
|
|
3328 @job = "today"
|
2
|
3329 when "-today_p"
|
|
3330 argument['displaymode'] = 'personal'
|
|
3331 @job = "today"
|
|
3332 when "-today_n"
|
|
3333 argument['displaymode'] = 'normal'
|
|
3334 @job = "today"
|
0
|
3335 when "-remove"
|
|
3336 ARGV.shift
|
|
3337 @job = 'remove "'+parsedate(ARGV[0])+'"'
|
14
|
3338 when "-move"
|
|
3339 ARGV.shift
|
|
3340 @job = 'move "'+parsedate(ARGV[0])+'"'
|
0
|
3341 when "-modify"
|
|
3342 ARGV.shift
|
|
3343 @job = 'modify "'+parsedate(ARGV[0])+'"'
|
|
3344 when "-month"
|
|
3345 ARGV.shift
|
|
3346 @job = 'month "'+parsedate(ARGV[0])+'"'
|
|
3347 when "-show"
|
|
3348 ARGV.shift
|
|
3349 # @job = "show '"+ARGV[0]+"'"
|
|
3350 @job = "show '"+parsedate(ARGV[0])+"'"
|
|
3351 when "-login"
|
|
3352 @job = "login"
|
|
3353 when "-userman"
|
|
3354 @job = "userman"
|
|
3355 when "-usermod"
|
|
3356 @job = "usermod"
|
|
3357 when "-groupinout"
|
|
3358 @job = "groupinout"
|
|
3359 when "-groupsubmit"
|
|
3360 @job = "groupsubmit"
|
|
3361 when "-groupman"
|
|
3362 @job = "groupman"
|
|
3363 when "-groupmod"
|
|
3364 @job = "groupmod"
|
|
3365 when "-notify"
|
|
3366 @job = 'notify' # + exit
|
|
3367 when "-newgroup"
|
|
3368 @job = 'newgroup'
|
|
3369 when "-admgroup"
|
|
3370 ARGV.shift
|
|
3371 gr = safecopy(grepgroup(ARGV[0]))
|
|
3372 ##gr.untaint
|
|
3373 @job = 'admgroup "'+gr+'"'
|
|
3374 when "-admgroupsub"
|
|
3375 @job = 'admgroupsub'
|
|
3376 when "-newgroupsub"
|
|
3377 @job = 'newgroupsub'
|
|
3378 when "-delusersub"
|
|
3379 ARGV.shift
|
6
|
3380 usr = safecopy(users().grep(ARGV[0])[0])
|
0
|
3381 @job = 'delusersub "'+usr+'"'
|
|
3382 when "-delgroupsub"
|
|
3383 ARGV.shift
|
|
3384 gr = grepgroup(ARGV[0])
|
|
3385 @job = 'delgroupsub "'+gr+'"'
|
|
3386 when /-(setpasswd|deluser|adduser)$/
|
|
3387 ARGV.shift
|
|
3388 @job = $1+ " '#{ARGV[0]}'" # + exit
|
|
3389 when ""
|
|
3390 end
|
|
3391 ARGV.shift
|
|
3392 end
|
|
3393
|
|
3394 readconf(@conf)
|
|
3395
|
|
3396 query = ''
|
|
3397 method = ENV["REQUEST_METHOD"]
|
|
3398 if /POST/i =~ method then
|
|
3399 length = ENV["CONTENT_LENGTH"].to_i
|
|
3400 query = STDIN.read(length)
|
|
3401 elsif /GET/i =~ method then
|
|
3402 query = ENV["QUERY_STRING"]
|
|
3403 else # executed from command line
|
|
3404 query = ARGV.join("&")
|
|
3405 end
|
|
3406
|
|
3407 for unit in query.split(/\&/)
|
|
3408 if /^([a-z][-_0-9@%a-z.]*)=(.*)/i =~ unit
|
|
3409 key, value = $1, $2
|
|
3410 #value.gsub!(/%(..)/){[$1.hex].pack("c")} # これでURLデコードが一発
|
|
3411 decode!(value)
|
|
3412 decode!(key)
|
|
3413 value = Kconv::toeuc(value) # EUCに変換
|
|
3414 printf "[%s] = %s\n", key, value if $DEBUG
|
|
3415 argument[key] = value
|
|
3416 end
|
|
3417 end
|
|
3418 argument
|
|
3419 end
|
|
3420 def getcookie()
|
|
3421 cookie = {}
|
7
|
3422 return cookie unless ENV['HTTP_COOKIE']
|
|
3423 #if /value=(.*)/ =~ ENV['HTTP_COOKIE']
|
|
3424 for cv in ENV['HTTP_COOKIE'].split(/[\; ]+/).grep(/(value|prefs)=(.*)/)
|
0
|
3425 # value=$1.gsub!(/%(..)/){[$1.hex].pack("c")}
|
7
|
3426 next unless /\w+=(.*)/ =~ cv
|
0
|
3427 value=decode!($1)
|
7
|
3428 next unless value
|
0
|
3429 for line in value.split("&")
|
|
3430 if /(\w+)=(.*)/ =~ line
|
|
3431 key, value = $1, $2
|
|
3432 #value.gsub!(/%(..)/){[$1.hex].pack("c")} # これでURLデコードが一発
|
|
3433 decode!(value)
|
|
3434 value = Kconv::toeuc(value) # EUCに変換
|
|
3435 printf "cookie[%s] = %s\n", key, value if $DEBUG
|
|
3436 cookie[key] = value
|
|
3437 end
|
|
3438 end
|
|
3439 end
|
|
3440 cookie
|
|
3441 end
|
|
3442 end
|
|
3443
|
17
|
3444 $KCODE='e' if RUBY_VERSION < "1.9"
|
0
|
3445 After5.new.doit
|
|
3446
|
|
3447 if __FILE__ == $0
|
|
3448 end
|
|
3449
|
|
3450
|
|
3451 # Local variables:
|
|
3452 # buffer-file-coding-system: euc-jp
|
|
3453 # End:
|