Mercurial > hgrepos > hgweb.cgi > after5
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' => ['〜', '=>'], | 1149 'through' => ['〜', '=>'], |
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 |