Mercurial > hgrepos > hgweb.cgi > after5
comparison after5.rb @ 87:1f99367752fb draft
Link to home in groupman()
author | HIROSE Yuuji <yuuji@gentei.org> |
---|---|
date | Thu, 19 Dec 2013 11:33:53 +0900 |
parents | 26c81703a80c |
children | c4ea79816b2d |
comparison
equal
deleted
inserted
replaced
86:26c81703a80c | 87:1f99367752fb |
---|---|
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, 2012, 2013 by HIROSE Yuuji [yuuji<at>gentei.org] | 5 # (C)2003, 2004, 2006, 2008, 2012, 2013 by HIROSE Yuuji [yuuji<at>gentei.org] |
6 # $Id: after5.rb,v 1.20 2012/12/03 15:54:20 yuuji Exp $ | 6 # $Id: after5.rb,v 1.20 2012/12/03 15:54:20 yuuji Exp $ |
7 # Last modified Mon Dec 16 10:56:24 2013 on firestorm | 7 # Last modified Thu Dec 19 11:33:07 2013 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 $hgid = <<_HGID_.split[1..-2].join(" ") | 10 $hgid = <<_HGID_.split[1..-2].join(" ") |
11 $HGid$ | 11 $HGid$ |
12 _HGID_ | 12 _HGID_ |
301 map[u][attr] = IO.readlines(file).join.toeuc.strip | 301 map[u][attr] = IO.readlines(file).join.toeuc.strip |
302 } | 302 } |
303 } | 303 } |
304 map | 304 map |
305 end | 305 end |
306 def ismembersemail(email) | 306 def ismembersemail(email, grp = nil) |
307 @usermap.keys.each {|u| | 307 @usermap.keys.each {|u| |
308 return u if u==email | 308 return u if u==email |
309 return u if mailaddress(u).split(/,\s*|\s+/).grep(email)[0] | 309 return u if mailaddress(u, grp).split(/,\s*|\s+/).collect{|m| |
310 m.sub(/^(skip|off):/i, "") | |
311 }.grep(email)[0] | |
310 } | 312 } |
311 nil | 313 nil |
312 end | 314 end |
313 def putuserattr(user, attr, text) | 315 def putuserattr(user, attr, text) |
314 # if text==nil, remove it | 316 # if text==nil, remove it |
348 else | 350 else |
349 return user.sub(/@.*/, '') | 351 return user.sub(/@.*/, '') |
350 end | 352 end |
351 end | 353 end |
352 def mailaddress(user, grp = nil) | 354 def mailaddress(user, grp = nil) |
353 grp ? mail4grp(user, grp) : \ | 355 grp ? \ |
356 mail4grp(user, grp) : \ | |
354 (getuserattr(user, 'email') || user) | 357 (getuserattr(user, 'email') || user) |
355 end | 358 end |
356 def setnickname(user, nickname) | 359 def setnickname(user, nickname) |
357 putuserattr(user, 'name', nickname) | 360 putuserattr(user, 'name', nickname) |
358 end | 361 end |
577 else | 580 else |
578 ! @groupmap.select{|k, v| k==instance}.empty? | 581 ! @groupmap.select{|k, v| k==instance}.empty? |
579 end | 582 end |
580 end | 583 end |
581 def mail4grp(usr, group) | 584 def mail4grp(usr, group) |
585 # If members/user file contains only "skip:" keyword, | |
586 # return "skip:email@add.re.ss" | |
587 default = mailaddress(usr) | |
582 file = File.expand_path((group+"/members/"+usr).untaint, @groupmapdir) | 588 file = File.expand_path((group+"/members/"+usr).untaint, @groupmapdir) |
583 if test(?s, file.untaint) | 589 if test(?s, file.untaint) |
584 open(file, "r"){|f|f.gets.chomp}.untaint | 590 rcpt = open(file, "r"){|f|f.gets.chomp}.untaint |
585 else | 591 if /^(off|skip):/ =~ rcpt && /@/ !~ rcpt |
586 mailaddress(usr) | 592 rcpt = "skip:"+default |
587 end | 593 end |
594 return rcpt | |
595 end | |
596 default | |
597 end | |
598 def delivergrpmail(user, grp) | |
599 | |
588 end | 600 end |
589 def ismember(user, grouporuser) | 601 def ismember(user, grouporuser) |
590 return user if user==grouporuser | 602 return user if user==grouporuser |
591 if @groupmap[grouporuser] | 603 if @groupmap[grouporuser] |
592 @groupmap[grouporuser]['members'].grep(user)[0] && | 604 @groupmap[grouporuser]['members'].grep(user)[0] && |
1352 maildomain=gentei.org | 1364 maildomain=gentei.org |
1353 | 1365 |
1354 And then prepare .qmail-$mailprefix-default file as below. | 1366 And then prepare .qmail-$mailprefix-default file as below. |
1355 | ./#{@myname} -list"], | 1367 | ./#{@myname} -list"], |
1356 'sendall_head' => ['「%s」宛のメイル送信', "Send message to `%s'"], | 1368 'sendall_head' => ['「%s」宛のメイル送信', "Send message to `%s'"], |
1369 'sendmem_head' => ['「%s」さん宛のメイル送信', "Send message to `%s'"], | |
1357 'sendall_note' => ['メンバーへの連絡だけでなく、グループ非加入者がこれから加入する旨の通知などにも有用。', | 1370 'sendall_note' => ['メンバーへの連絡だけでなく、グループ非加入者がこれから加入する旨の通知などにも有用。', |
1358 "Send this message to all of group."], | 1371 "Send this message to all of group."], |
1359 'sendall_done' => ['送信完了', "sending message done"], | 1372 'sendall_done' => ['送信完了', "sending message done"], |
1360 'body' => ['本文', 'Body'], | 1373 'body' => ['本文', 'Body'], |
1361 'rcptto' => ['宛先', 'Recipients'], | 1374 'rcptto' => ['宛先', 'Recipients'], |
1387 'aboutgroup' => ['グループ %s の操作', "Operations on group `%s'"], | 1400 'aboutgroup' => ['グループ %s の操作', "Operations on group `%s'"], |
1388 'groupwarn' => ['自分が参加してないグループAに、自分が参加しているグループBが含まれている場合、グループAにも加入していると見なされるので気をつけよう。管理者はグループのニックネームを変えられるよ。', | 1401 'groupwarn' => ['自分が参加してないグループAに、自分が参加しているグループBが含まれている場合、グループAにも加入していると見なされるので気をつけよう。管理者はグループのニックネームを変えられるよ。', |
1389 '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.'], | 1402 '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.'], |
1390 'address2send' => ['自分が参加しているグループのメンバーリストの先頭が自分。その直後にある入力欄には、そのML宛メッセージをどの宛先に配送するかを入れられる。そう、MLごとに自分への配送先を変えられるよ。', | 1403 'address2send' => ['自分が参加しているグループのメンバーリストの先頭が自分。その直後にある入力欄には、そのML宛メッセージをどの宛先に配送するかを入れられる。そう、MLごとに自分への配送先を変えられるよ。', |
1391 'The first entry of member list of a group to which you belongs, is you. Entry box just after your name is for address list you want to deliver messages to that ML. Thus, you can define different addresses for each ML.'], | 1404 'The first entry of member list of a group to which you belongs, is you. Entry box just after your name is for address list you want to deliver messages to that ML. Thus, you can define different addresses for each ML.'], |
1405 'skip:' => ['MLへの送信専用メイルアドレスは、アドレスの前に空白入れずに skip: を付けて登録できるよ(例: skip:hoge@example.com。ML登録メンバーのみの投稿を許すMLに書いてエラーを食らったときには、投稿アドレスを skip: つきで登録しとくとええよ。', "You can prefix `skip:' without any blanks to email address to register POST-ONLY address for the ML(eg. skip:you@example.com). When you get rejecting message from ML which allows only members to post, try to add POST-ONLY address to your email addresses entry of that group."], | |
1392 'wholemembers' => ['グループ内グループを考慮した上で、現在グループ %s への通知は以下のメンバーに送られる。', | 1406 'wholemembers' => ['グループ内グループを考慮した上で、現在グループ %s への通知は以下のメンバーに送られる。', |
1393 "Consiering the groups registered in another group, notification to the group `%s' is send to members as follows."], | 1407 "Consiering the groups registered in another group, notification to the group `%s' is send to members as follows."], |
1394 'noadmingroup' => ['管理できるグループはないっす', | 1408 'noadmingroup' => ['管理できるグループはないっす', |
1395 "'There's no groups under your administration."], | 1409 "'There's no groups under your administration."], |
1396 'nickname' => ['ニックネーム', 'nickname'], | 1410 'nickname' => ['ニックネーム', 'nickname'], |
1681 open(seqfile, "r"){|s|s.gets.to_i+1} | 1695 open(seqfile, "r"){|s|s.gets.to_i+1} |
1682 : 1 | 1696 : 1 |
1683 end | 1697 end |
1684 def sendMail(to, subject, body, from=nil, rcptto=nil, header={}, | 1698 def sendMail(to, subject, body, from=nil, rcptto=nil, header={}, |
1685 thru=nil, spoolto=false) | 1699 thru=nil, spoolto=false) |
1686 # rcptto should be an Array | 1700 # rcptto should be an Array or nil |
1687 body = NKF.nkf("-j", body) unless thru | 1701 body = NKF.nkf("-j", body) unless thru |
1688 subject = NKF.nkf("-jM", (subject||"No subject").strip) | 1702 subject = NKF.nkf("-jM", (subject||"No subject").strip) |
1689 to = safecopy(to) # cleanup tainted address | 1703 to = safecopy(to) # cleanup tainted address |
1690 subject.gsub!(/\n/, '') | 1704 subject.gsub!(/\n/, '') |
1705 rcptto.reject!{|i| /^(skip|off):/i =~ i} if rcptto.is_a?(Array) | |
1691 begin | 1706 begin |
1692 if (m=open("|-", "w")) | 1707 if (m=open("|-", "w")) |
1693 header.each do |h, v| | 1708 header.each do |h, v| |
1694 m.printf("%s: %s\n", h.strip, v.strip) | 1709 m.printf("%s: %s\n", h.strip, v.strip) |
1695 end | 1710 end |
2774 ret + hold + body | 2789 ret + hold + body |
2775 end | 2790 end |
2776 def extract_attachment(attachment) | 2791 def extract_attachment(attachment) |
2777 # Must return [text, href] strings to attached files | 2792 # Must return [text, href] strings to attached files |
2778 href = ""; text = "" | 2793 href = ""; text = "" |
2779 dir = @attachmentdir | 2794 dir = @attachmentdir + Time.now.strftime("/%Y%m") |
2780 if %r,(https?://[^/]+), =~ @opt['url'] | 2795 if %r,(https?://[^/]+), =~ @opt['url'] |
2781 server = $1 | 2796 server = $1 |
2782 else | 2797 else |
2783 msg = "`url' not set in after5.cf" | 2798 msg = "`url' not set in after5.cf" |
2784 return [msg, msg] | 2799 return [msg, msg] |
2785 end | 2800 end |
2786 | 2801 kakasi = @opt['kakasi'] && @opt['kakasi']+" -Ha -Ka -Ja -Ea -ka" |
2787 urlbase = sprintf("%s%s/%s", | 2802 urlbase = sprintf("%s%s/%s", |
2788 server, File.dirname(ENV['SCRIPT_NAME']), dir) | 2803 server, File.dirname(ENV['SCRIPT_NAME']), dir) |
2789 count=0 | 2804 count=0 |
2790 attachment.each {|a| | 2805 attachment.each {|a| |
2791 basename = safecopy(File.basename(a['filename'])) | 2806 basename = safecopy(File.basename(a['filename'])) |
2792 filename = safecopy(dir+"/"+basename) | 2807 encname = (kakasi ? |
2808 IO.popen(kakasi, "r+") do |k| | |
2809 k.puts basename | |
2810 k.close_write # force flush | |
2811 k.gets.chomp.downcase | |
2812 end | |
2813 : | |
2814 basename | |
2815 ).gsub(/([^-_0-9a-z=,.@])/){"~"+$1.unpack("H*")[0].to_s} | |
2816 filename = safecopy(dir+"/"+encname) | |
2793 umask = File.umask(022) | 2817 umask = File.umask(022) |
2794 sz = a['value'].bytesize | 2818 sz = a['value'].bytesize |
2795 next if sz == 0 | 2819 next if sz == 0 |
2796 count += 1 | 2820 count += 1 |
2797 if sz > @attachmentmax | 2821 if sz > @attachmentmax |
2799 count, basename, sz/1024**2) | 2823 count, basename, sz/1024**2) |
2800 text += msg; href += msg | 2824 text += msg; href += msg |
2801 next | 2825 next |
2802 end | 2826 end |
2803 begin | 2827 begin |
2804 (test(?d, dir) && test(?w, dir)) or Dir.mkdir(dir) | 2828 require 'fileutils' |
2829 (test(?d, dir) && test(?w, dir)) or FileUtils.mkdir_p(dir) | |
2805 open(filename, "w") {|x| x.write a['value']} | 2830 open(filename, "w") {|x| x.write a['value']} |
2806 File.chmod(0664, filename) | 2831 File.chmod(0664, filename) |
2807 text += sprintf("%d: %s/%s\n", count, urlbase, basename) | 2832 text += sprintf("%d: %s/%s\n", count, urlbase, encname) |
2808 href += sprintf("%d: <a href=\"%s\">%s/%s</a>\n", | 2833 href += sprintf("%d: <a href=\"%s\">%s/%s</a>\n", |
2809 count, filename, urlbase, basename) | 2834 count, filename, urlbase, encname) |
2810 rescue | 2835 rescue |
2811 ensure | 2836 ensure |
2812 File.umask(umask) | 2837 File.umask(umask) |
2813 end | 2838 end |
2814 } | 2839 } |
2839 end | 2864 end |
2840 end | 2865 end |
2841 if viamail then | 2866 if viamail then |
2842 prohibitviahttp() | 2867 prohibitviahttp() |
2843 name = unquoted(ENV['DEFAULT']) | 2868 name = unquoted(ENV['DEFAULT']) |
2844 user = @sc.ismembersemail(ENV['SENDER']) | 2869 user = @sc.ismembersemail(ENV['SENDER']) # should here be (,name)?? |
2845 if Regexp.new("(.*)("+Regexp.quote(@mailadmsuffix)+")") =~ name | 2870 if Regexp.new("(.*)("+Regexp.quote(@mailadmsuffix)+")") =~ name |
2846 # To: GROUP/adm*@domain | 2871 # To: GROUP/adm*@domain |
2847 # -> Forward to group administrator(s) | 2872 # -> Forward to group administrator(s) |
2848 name, toadmin = $1, $2 | 2873 name, toadmin = $1, $2 |
2849 sendMail("dummy", 'dummy', # Original To: and Subject: go through | 2874 sendMail("dummy", 'dummy', # Original To: and Subject: go through |
2881 @O.print @H.p("No such group: #{name}") | 2906 @O.print @H.p("No such group: #{name}") |
2882 return true | 2907 return true |
2883 end | 2908 end |
2884 nick = @sc.nickname(user) | 2909 nick = @sc.nickname(user) |
2885 from = sprintf("%s <%s>", nick, user) | 2910 from = sprintf("%s <%s>", nick, user) |
2886 subj = @params['subject'][0]['value'] || "Message from "+@myname | 2911 subj = @params['subject'][0]['value'].toeuc || "Message from "+@myname |
2887 body = @params['body'][0]['value'].gsub("\r", "").untaint | 2912 body = @params['body'][0]['value'].gsub("\r", "").untaint |
2888 # Extract attachment file | 2913 # Extract attachment file |
2889 if @params['attachment'].is_a?(Array) | 2914 if @params['attachment'].is_a?(Array) |
2890 body += (extract_report = extract_attachment(@params['attachment']))[0] | 2915 body += (extract_report = extract_attachment(@params['attachment']))[0] |
2891 end | 2916 end |
2983 # On mail mode, check if sender can send message to list. | 3008 # On mail mode, check if sender can send message to list. |
2984 if viamail && @sc.getgroupattr(name, 'limitsender') | 3009 if viamail && @sc.getgroupattr(name, 'limitsender') |
2985 s = ENV['SENDER'] | 3010 s = ENV['SENDER'] |
2986 if !catch(:senderok) { | 3011 if !catch(:senderok) { |
2987 throw :senderok, true if rcpts.grep(s)[0] | 3012 throw :senderok, true if rcpts.grep(s)[0] |
2988 throw :senderok, true if @sc.ismembersemail(s) | 3013 throw :senderok, true if @sc.ismembersemail(s, name) |
2989 } | 3014 } |
2990 # sender is not allowed to send to ML | 3015 # sender is not allowed to send to ML |
2991 sendMail(s, "You are not allowed to send to this ML", | 3016 sendMail(s, "You are not allowed to send to this ML", |
2992 ("Before posting to this list(%s),\n"+ | 3017 ("Before posting to this list(%s),\n"+ |
2993 "subscribe to %s") % [to, @opt['url']], | 3018 "subscribe to %s") % [to, @opt['url']], |
3001 header, | 3026 header, |
3002 ENV['SENDER'], | 3027 ENV['SENDER'], |
3003 spooling ? mldir : nil) | 3028 spooling ? mldir : nil) |
3004 if !viamail then | 3029 if !viamail then |
3005 @O.print @H.elementln("h1"){msg('sendall_done')} | 3030 @O.print @H.elementln("h1"){msg('sendall_done')} |
3006 @O.print @H.p(sprintf(msg('sendall_head'), | 3031 @O.print @H.p(sprintf(msg(groupmode ? 'sendall_head' : 'sendmem_head'), |
3007 nickname(name))+" "+msg('done')) | 3032 nickname(name))+" "+msg('done')) |
3008 @O.print @H.elementln("pre"){extract_report[1]} | 3033 @O.print @H.elementln("pre"){extract_report[1].toeuc} |
3009 link2home() | 3034 link2home() |
3010 @O.print footer() | 3035 @O.print footer() |
3011 return true | 3036 return true |
3012 end | 3037 end |
3013 exit 0 | 3038 exit 0 |
3310 } | 3335 } |
3311 }.join("\n") | 3336 }.join("\n") |
3312 } + \ | 3337 } + \ |
3313 '' + \ | 3338 '' + \ |
3314 @H.p(msg('address2send')) + \ | 3339 @H.p(msg('address2send')) + \ |
3340 @H.p(msg('skip:')) + \ | |
3315 @H.p(msg('groupwarn', 'shortnameplz')) + \ | 3341 @H.p(msg('groupwarn', 'shortnameplz')) + \ |
3316 @H.submit_reset("GO") | 3342 @H.submit_reset("GO") |
3317 } # form | 3343 } # form |
3344 link2home() | |
3345 @O.print footer() | |
3318 end | 3346 end |
3319 def groupnamesString() | 3347 def groupnamesString() |
3320 @H.elementln("p", {'class'=>'listup'}){ | 3348 @H.elementln("p", {'class'=>'listup'}){ |
3321 @sc.groups().collect{|g|@sc.groupname(g)}.join(", ") | 3349 @sc.groups().collect{|g|@sc.groupname(g)}.join(", ") |
3322 } | 3350 } |
4226 argument.has_key?(key=$2) or argument[key]=[] | 4254 argument.has_key?(key=$2) or argument[key]=[] |
4227 newvalue = Hash.new | 4255 newvalue = Hash.new |
4228 if /^Content.*filename=([\'\"])?(\S*)\1/i =~ unit | 4256 if /^Content.*filename=([\'\"])?(\S*)\1/i =~ unit |
4229 newvalue['filename'] = $2 | 4257 newvalue['filename'] = $2 |
4230 end | 4258 end |
4231 newvalue['value'] = unit.sub(/.*\r\n\r\n/m, "") | 4259 newvalue['value'] = unit.sub(/.*?\r\n\r\n/m, "") # Shortest match |
4232 if /^Content-type:\s*(\S*)/i =~ unit | 4260 if /^Content-type:\s*(\S*)/i =~ unit |
4233 newvalue['content-type'] = $1 | 4261 newvalue['content-type'] = $1 |
4234 else | 4262 else |
4235 newvalue['value'].gsub!("\r\n", "\n") | 4263 newvalue['value'].gsub!("\r\n", "\n") |
4236 end | 4264 end |