comparison after5.rb @ 17:904bbce89e71 draft

RCS-revision 1.18 date: 2012/04/01 05:18:57; author: yuuji; state: Exp; lines: +37 -36 Boring hack for ruby19 encoding issue Guidance message little bit informative
author HIROSE Yuuji <yuuji@gentei.org>
date Sun, 01 Apr 2012 05:18:57 +0859
parents 1ff30d4c58ce
children 399f24a71eb9
comparison
equal deleted inserted replaced
16:1ff30d4c58ce 17:904bbce89e71
1 #!/usr/local/bin/ruby 1 #!/usr/local/bin/ruby19
2 # -*- coding: euc-jp -*- 2 # -*- coding: euc-jp -*-
3 # 3 #
4 # Associative Scheduling Table - after5 4 # Associative Scheduling Table - after5
5 # (C)2003, 2004, 2006, 2008 by HIROSE Yuuji [yuuji@gentei.org] 5 # (C)2003, 2004, 2006, 2008 by HIROSE Yuuji [yuuji@gentei.org]
6 # $Id: after5.rb,v 1.17 2009/09/17 09:09:23 yuuji Exp $ 6 # $Id: after5.rb,v 1.18 2012/04/01 05:18:57 yuuji Exp $
7 # Last modified Thu Sep 17 18:08:23 2009 on spada 7 # Last modified Sun Apr 1 14:17:05 2012 on firestorm
8 # See http://www.gentei.org/~yuuji/software/after5/ 8 # See http://www.gentei.org/~yuuji/software/after5/
9 # このスクリプトはEUCで保存してください。 9 # このスクリプトはEUCで保存してください。
10 10
11 require 'kconv' 11 require 'kconv'
12 require 'nkf'
12 13
13 $charset = 'EUC-JP' 14 $charset = 'EUC-JP'
14 15
15 class HTMLout 16 class HTMLout
16 def contenttype(type = "text/html", charset = $charset) 17 def contenttype(type = "text/html", charset = $charset)
282 u.split('').each{|c| # for security wrapping 283 u.split('').each{|c| # for security wrapping
283 newu << c[0].chr if %r,[-A-Z0-9/+_.@],i =~ c 284 newu << c[0].chr if %r,[-A-Z0-9/+_.@],i =~ c
284 } 285 }
285 u = newu 286 u = newu
286 map[u] = {} 287 map[u] = {}
287 d = File.join(@usermapdir, u) 288 d = File.join(@usermapdir, u).untaint
288 next unless test(?d, d) 289 next unless test(?d, d)
289 Dir.foreach(d){|attr| 290 Dir.foreach(d){|attr|
290 next if /^\./ =~ attr 291 next if /^\./ =~ attr
291 attr.untaint if /^[A-Z_][-A-Z_0-9]*$/i =~ attr 292 attr.untaint if /^[A-Z_][-A-Z_0-9]*$/i =~ attr
292 file = File.join(@usermapdir, u, attr) 293 file = File.join(@usermapdir, u, attr).untaint
293 next unless test(?s, file) && test(?r, file) 294 next unless test(?s, file) && test(?r, file)
294 map[u][attr] = IO.readlines(file).join().strip 295 map[u][attr] = IO.readlines(file).join.toeuc.strip
295 } 296 }
296 } 297 }
297 map 298 map
298 end 299 end
299 def putuserattr(user, attr, text) 300 def putuserattr(user, attr, text)
372 #g.untaint ## untaintじゃだめだ。map{g} のkeyがtaintedになっちゃうよ 373 #g.untaint ## untaintじゃだめだ。map{g} のkeyがtaintedになっちゃうよ
373 gg = '' # for security wrapping 374 gg = '' # for security wrapping
374 g.split('').each{|c| gg << c[0].chr if c != '`'} 375 g.split('').each{|c| gg << c[0].chr if c != '`'}
375 g = gg 376 g = gg
376 map[gg] = {} 377 map[gg] = {}
377 d = File.join(@groupmapdir, g) 378 d = File.join(@groupmapdir, g).untaint
378 next unless test(?d, d) 379 next unless test(?d, d)
379 # get group name 380 # get group name
380 gnf = File.join(d, 'name') 381 gnf = File.join(d, 'name').untaint
381 if test(?r, gnf) && test(?s, gnf) 382 if test(?r, gnf) && test(?s, gnf)
382 n = IO.readlines(gnf)[0].to_s.strip 383 n = IO.readlines(gnf)[0].to_s.toeuc.strip
383 map[g]['name'] = if n > '' then n else g end 384 map[g]['name'] = if n > '' then n else g end
384 else 385 else
385 map[g]['name'] = g 386 map[g]['name'] = g
386 end 387 end
387 # get administrators 388 # get administrators
388 # 389 #
389 gad = File.join(d, 'admin') 390 gad = File.join(d, 'admin').untaint
390 map[g]['admin'] = [] 391 map[g]['admin'] = []
391 if test(?d, gad) 392 if test(?d, gad)
392 Dir.foreach(gad){|a| 393 Dir.foreach(gad){|a|
393 # administrator should be a person (not group) 394 # administrator should be a person (not group)
394 next unless /@/ =~ a 395 next unless /@/ =~ a
395 map[g]['admin'] << a 396 map[g]['admin'] << a
396 } 397 }
397 end 398 end
398 # collect members 399 # collect members
399 #map[g]['members'] = collectmembers(g) 400 #map[g]['members'] = collectmembers(g)
400 memd = File.join(d, 'members') 401 memd = File.join(d, 'members').untaint
401 map[g]['members'] = [] 402 map[g]['members'] = []
402 if test(?d, memd) 403 if test(?d, memd)
403 Dir.foreach(memd){|a| 404 Dir.foreach(memd){|a|
404 next if /^\./ =~ a 405 next if /^\./ =~ a
405 map[g]['members'] << a 406 map[g]['members'] << a
417 def addgroup(group, users, remove=nil, role='members') 418 def addgroup(group, users, remove=nil, role='members')
418 grp = groups.grep(group)[0] # group may be tainted, using kept name 419 grp = groups.grep(group)[0] # group may be tainted, using kept name
419 return nil unless grp 420 return nil unless grp
420 for u in users 421 for u in users
421 next unless account_exists(u) 422 next unless account_exists(u)
422 mdir = File.join(@groupmapdir, grp, role) 423 mdir = File.join(@groupmapdir, grp, role).untaint
423 file = File.join(mdir, u) 424 file = File.join(mdir, u).untaint
424 if remove 425 if remove
425 @groupmap[grp][role].delete(u) 426 @groupmap[grp][role].delete(u)
426 File.unlink(file) if test(?e, file) 427 File.unlink(file) if test(?e, file)
427 else 428 else
428 @groupmap[grp][role] << u 429 @groupmap[grp][role] << u
433 end 434 end
434 grp 435 grp
435 end 436 end
436 def setgroupname(grp, name) 437 def setgroupname(grp, name)
437 return nil unless @groupmap[grp] 438 return nil unless @groupmap[grp]
438 mdir = File.join(@groupmapdir, grp) 439 mdir = File.join(@groupmapdir, grp).untaint
439 nfile = File.join(mdir, 'name') 440 nfile = File.join(mdir, 'name').untaint
440 @groupmap[grp]['name'] = name 441 @groupmap[grp]['name'] = name
441 if grp == name 442 if grp == name
442 # remove the name file because it is default name 443 # remove the name file because it is default name
443 File.unlink(nfile) if test(?e, nfile) 444 File.unlink(nfile) if test(?e, nfile)
444 else 445 else
580 581
581 if ismember(user, who) || visible 582 if ismember(user, who) || visible
582 sched[time][who] = {} 583 sched[time][who] = {}
583 file = File.join(dir, @schedulefile) 584 file = File.join(dir, @schedulefile)
584 if test(?s, file) && test(?r, file) && test(?s, file) 585 if test(?s, file) && test(?r, file) && test(?s, file)
585 sched[time][who]['sched'] = IO.readlines(file).join().chomp! 586 sched[time][who]['sched'] = IO.readlines(file).join.toeuc.chomp!
586 sched[time][who]['regtime'] = File.stat(file).mtime 587 sched[time][who]['regtime'] = File.stat(file).mtime
587 end 588 end
588 sched[time][who]['pub'] = visible 589 sched[time][who]['pub'] = visible
589 end 590 end
590 } #|who| 591 } #|who|
642 return ret 643 return ret
643 end 644 end
644 def getschedule(user, year, month, day, time) 645 def getschedule(user, year, month, day, time)
645 file = schedulefile(user, year, month, day, time) 646 file = schedulefile(user, year, month, day, time)
646 if test(?r, file) && test(?s, file) 647 if test(?r, file) && test(?s, file)
647 return IO.readlines(file).join 648 return IO.readlines(file).join.toeuc
648 end 649 end
649 return nil 650 return nil
650 end 651 end
651 def remove(user, year, month, day, time) 652 def remove(user, year, month, day, time)
652 file = schedulefile(user, year, month, day, time) 653 file = schedulefile(user, year, month, day, time)
777 date.untaint 778 date.untaint
778 f = File.join(ud, date) 779 f = File.join(ud, date)
779 if test(?s, f) 780 if test(?s, f)
780 ntl[user][date] = {} 781 ntl[user][date] = {}
781 ntl[user][date]['file'] = f 782 ntl[user][date]['file'] = f
782 ntl[user][date]['text'] = IO.readlines(f) 783 ntl[user][date]['text'] = IO.readlines(f).toeuc
783 else 784 else
784 File.unlink(f) # symlink points to nonexistent file 785 File.unlink(f) # symlink points to nonexistent file
785 end 786 end
786 } 787 }
787 if ntl[user].empty? 788 if ntl[user].empty?
965 end 966 end
966 def setupHoliday(file = "holiday") 967 def setupHoliday(file = "holiday")
967 @@holiday = {} 968 @@holiday = {}
968 return unless test(?f, file) && test(?s, file) 969 return unless test(?f, file) && test(?s, file)
969 IO.foreach(file){|line| 970 IO.foreach(file){|line|
970 line.strip 971 line = line.toeuc.strip
971 next if /^#/ =~ line 972 next if /^#/ =~ line
972 date, what = line.scan(/(\S+)\s+(.*)/)[0] 973 date, what = line.scan(/(\S+)\s+(.*)/)[0]
973 if %r,(\d+)/(\d+)/(\d+), =~ date 974 if %r,(\d+)/(\d+)/(\d+), =~ date
974 cdate = sprintf("%d/%d/%d", $1.to_i, $2.to_i, $3.to_i) 975 cdate = sprintf("%d/%d/%d", $1.to_i, $2.to_i, $3.to_i)
975 @@holiday[cdate] || @@holiday[cdate] = [] 976 @@holiday[cdate] || @@holiday[cdate] = []
1145 'visible from other members?'], 1146 'visible from other members?'],
1146 'public' => ['公', 'pub'], 1147 'public' => ['公', 'pub'],
1147 'nonpublic' => ['非', 'sec'], 1148 'nonpublic' => ['非', 'sec'],
1148 'through' => ['〜', '=&gt;'], 1149 'through' => ['〜', '=&gt;'],
1149 'yes' => ['はいな', 'yes'], 1150 'yes' => ['はいな', 'yes'],
1150 'no' => ['やだ', 'nope'], 1151 'no' => ['やだ(非公開)', 'nope'],
1151 'wnames' => [%w[日 月 火 水 木 金 土], 1152 'wnames' => [%w[日 月 火 水 木 金 土],
1152 %w[sun mon tue wed thu fri sat]], 1153 %w[sun mon tue wed thu fri sat]],
1153 'whichday' => ['<small>(まとめ登録の場合)</small><br>期間中のどの日に?', 1154 'whichday' => ['<small>(まとめ登録の場合)</small><br>期間中のどの日に?',
1154 '<small>(On multiple registration)</small><br>Which days in the term?'], 1155 '<small>(On multiple registration)</small><br>Which days in the term?'],
1155 'singleday' => ['一日分だけ登録', '1day regist'], 1156 'singleday' => ['一日分だけ登録', '1day regist'],
1194 'If you have no idea for getting this message, '+ 1195 'If you have no idea for getting this message, '+
1195 'it is mischief by someone else'], 1196 'it is mischief by someone else'],
1196 'user' => ['ユーザ', 'user'], 1197 'user' => ['ユーザ', 'user'],
1197 'group' => ['グループ', 'group'], 1198 'group' => ['グループ', 'group'],
1198 'personal' => ['個人で', 'personal'], 1199 'personal' => ['個人で', 'personal'],
1199 'registas' => ['グループ予定として登録', 'Register as group'], 1200 'registas' => ['グループ予定として登録?', 'Register as group?'],
1201 'headsched' => ['下の枠内に予定を記入: 1行以内で短めに。
1202 長くなるときは2行目以降に詳細を。',
1203 'Put shortest sentence as possible within 1 line.
1204 Or, put short subject in the first line, details in latter lines.'],
1200 'joinquit' => ['入退', 'joining/quiting'], 1205 'joinquit' => ['入退', 'joining/quiting'],
1201 'of' => ['の', "'s"], 1206 'of' => ['の', "'s"],
1202 'id' => ['ID(ローマ字1単語空白なしで)', 'ID(without spaces)'], 1207 'id' => ['ID(ローマ字1単語空白なしで)', 'ID(without spaces)'],
1203 'name' => ['名前', 'name'], 1208 'name' => ['名前', 'name'],
1204 'anystring' => ['(日本語OK)', '(any length, any characters)'], 1209 'anystring' => ['(日本語OK)', '(any length, any characters)'],
1306 def decode!(string) 1311 def decode!(string)
1307 string.gsub!(/\+/, ' ') 1312 string.gsub!(/\+/, ' ')
1308 string.gsub!(/%(..)/){[$1.hex].pack("c")} 1313 string.gsub!(/%(..)/){[$1.hex].pack("c")}
1309 end 1314 end
1310 def decode(string) 1315 def decode(string)
1311 string.gsub(/\+/, ' ') 1316 string.gsub(/\+/, ' ').gsub(/%(..)/){[$1.hex].pack("c")}
1312 string.gsub(/%(..)/){[$1.hex].pack("c")}
1313 end 1317 end
1314 1318
1315 def gencookie(name, a, expire) 1319 def gencookie(name, a, expire)
1316 x = a.collect{|k, v| 1320 x = a.collect{|k, v|
1317 sprintf("%s=%s", k, encode(v)) if v 1321 sprintf("%s=%s", k, encode(v)) if v
1432 cpy << c[0].chr if c[0] != ?` # ` 1436 cpy << c[0].chr if c[0] != ?` # `
1433 } 1437 }
1434 cpy 1438 cpy
1435 else 1439 else
1436 string 1440 string
1437 end 1441 end.untaint
1438 end 1442 end
1439 def checkmail(mail) 1443 def checkmail(mail)
1440 account, domain = mail.scan(/(.*)@(.*)/)[0] 1444 account, domain = mail.scan(/(.*)@(.*)/)[0]
1441 return false unless account != nil && domain != nil 1445 return false unless account != nil && domain != nil
1442 return false unless /^[-0-9a-z_.]+$/oi =~ domain 1446 return false unless /^[-0-9a-z_.]+$/oi =~ domain.toeuc
1443 domain = safecopy(domain) 1447 domain = safecopy(domain)
1444 require 'socket' 1448 require 'socket'
1445 begin 1449 begin
1446 TCPSocket.gethostbyname(domain) 1450 TCPSocket.gethostbyname(domain)
1447 return true 1451 return true
1483 end 1487 end
1484 end 1488 end
1485 end 1489 end
1486 1490
1487 def sendMail(to, subject, body) 1491 def sendMail(to, subject, body)
1488 body = Kconv::tojis(body) 1492 body = NKF.nkf("-j", body)
1489 subject = Kconv.tojis(subject) 1493 subject = NKF.nkf("-jM", subject)
1490 to = safecopy(to) # cleanup tainted address 1494 to = safecopy(to) # cleanup tainted address
1491 if /\e/ =~ subject # If contains JIS chars...
1492 subject = subject.split(//,1).pack('m')
1493 subject = "=?iso-2022-jp?B?#{subject}?="
1494 end
1495 subject.gsub!(/\n/, '') 1495 subject.gsub!(/\n/, '')
1496 begin 1496 begin
1497 if (m=open("|-", "w")) 1497 if (m=open("|-", "w"))
1498 m.print "To: #{to}\n" 1498 m.print "To: #{to}\n"
1499 m.print "Subject: #{subject}\n" 1499 m.print "Subject: #{subject}\n"
1596 # show specified month's calendar 1596 # show specified month's calendar
1597 def showtable(day) 1597 def showtable(day)
1598 if !checkauth 1598 if !checkauth
1599 return nil 1599 return nil
1600 end 1600 end
1601 1601
1602 month = day.month.to_s 1602 month = day.month.to_s
1603 first = Time.mktime(day.year, day.month, 1) 1603 first = Time.mktime(day.year, day.month, 1)
1604 last = daysofmonth(day.year, day.month) 1604 last = daysofmonth(day.year, day.month)
1605 wday1 = first.wday 1605 wday1 = first.wday
1606 start = 1-wday1 1606 start = 1-wday1
2003 } 2003 }
2004 end.to_s + "\n" + \ 2004 end.to_s + "\n" + \
2005 @H.radio('editmode', 'remove', 'Delete?') + " / " + \ 2005 @H.radio('editmode', 'remove', 'Delete?') + " / " + \
2006 @H.radio('editmode', 'modify', 'Overwrite?') + " / " + \ 2006 @H.radio('editmode', 'modify', 'Overwrite?') + " / " + \
2007 @H.radio('editmode', 'append', 'Append?', true) + "<br>\n" + \ 2007 @H.radio('editmode', 'append', 'Append?', true) + "<br>\n" + \
2008 @H.element("textarea", @schedulearea){} + "<br>\n" + \ 2008 @H.element("p"){msg('headsched') + \
2009 @H.element("textarea", @schedulearea){}} + # textarea
2009 @H.submit_reset("GO") 2010 @H.submit_reset("GO")
2010 } #form 2011 } #form
2011 end 2012 end
2012 # 2013 #
2013 # show the schedule list of specified date 2014 # show the schedule list of specified date
2224 if time < now 2225 if time < now
2225 outputError(msg('past')) 2226 outputError(msg('past'))
2226 return nil 2227 return nil
2227 end 2228 end
2228 begin 2229 begin
2229 (text = @params['schedule'].strip.gsub(/\r+\n/, $/)) << "\n" 2230 (text = decode(@params['schedule']).strip.gsub(/\r+\n/, $/)) << "\n"
2230 text = purify(text) 2231 text = purify(text)
2231 replace = (/modify/i =~ @params['editmode']) 2232 replace = (/modify/i =~ @params['editmode'])
2232 rc = @sc.register(registerer, y, m, d, timedir, text, replace) 2233 rc = @sc.register(registerer, y, m, d, timedir, text, replace)
2233 if @params['pub'] && /yes/ =~ @params['pub'] 2234 if @params['pub'] && /yes/ =~ @params['pub']
2234 @sc.putfile(registerer, y, m, d, timedir, 'pub', "1\n") 2235 @sc.putfile(registerer, y, m, d, timedir, 'pub', "1\n")
2237 end 2238 end
2238 ######## @O.print @H.p(msg('appended')) if rc == 1 2239 ######## @O.print @H.p(msg('appended')) if rc == 1
2239 rescue 2240 rescue
2240 outputError("Failed"+$!) 2241 outputError("Failed"+$!)
2241 end 2242 end
2242 text = decode(@sc.getschedule(registerer, y, m, d, timedir)) 2243 text = @sc.getschedule(registerer, y, m, d, timedir)
2243 reg_notify(registerer, y, m, d, timedir, text) 2244 reg_notify(registerer, y, m, d, timedir, text)
2244 2245
2245 end 2246 end
2246 2247
2247 end 2248 end
3435 end 3436 end
3436 cookie 3437 cookie
3437 end 3438 end
3438 end 3439 end
3439 3440
3440 $KCODE='e' 3441 $KCODE='e' if RUBY_VERSION < "1.9"
3441 After5.new.doit 3442 After5.new.doit
3442 3443
3443 if __FILE__ == $0 3444 if __FILE__ == $0
3444 end 3445 end
3445 3446

yatex.org