# HG changeset patch # User HIROSE Yuuji # Date 1387420433 -32400 # Node ID 1f99367752fb36fc6ccaa70893571fd0e504ce44 # Parent 26c81703a80c675a0cf943af4a632dc3653faf0b Link to home in groupman() diff -r 26c81703a80c -r 1f99367752fb after5.rb --- a/after5.rb Mon Dec 16 10:57:45 2013 +0900 +++ b/after5.rb Thu Dec 19 11:33:53 2013 +0900 @@ -4,7 +4,7 @@ # Associative Scheduling Table - after5 # (C)2003, 2004, 2006, 2008, 2012, 2013 by HIROSE Yuuji [yuujigentei.org] # $Id: after5.rb,v 1.20 2012/12/03 15:54:20 yuuji Exp $ -# Last modified Mon Dec 16 10:56:24 2013 on firestorm +# Last modified Thu Dec 19 11:33:07 2013 on firestorm # See http://www.gentei.org/~yuuji/software/after5/ # このスクリプトはEUCで保存してください。 $hgid = <<_HGID_.split[1..-2].join(" ") @@ -303,10 +303,12 @@ } map end - def ismembersemail(email) + def ismembersemail(email, grp = nil) @usermap.keys.each {|u| return u if u==email - return u if mailaddress(u).split(/,\s*|\s+/).grep(email)[0] + return u if mailaddress(u, grp).split(/,\s*|\s+/).collect{|m| + m.sub(/^(skip|off):/i, "") + }.grep(email)[0] } nil end @@ -350,7 +352,8 @@ end end def mailaddress(user, grp = nil) - grp ? mail4grp(user, grp) : \ + grp ? \ + mail4grp(user, grp) : \ (getuserattr(user, 'email') || user) end def setnickname(user, nickname) @@ -579,12 +582,21 @@ end end def mail4grp(usr, group) + # If members/user file contains only "skip:" keyword, + # return "skip:email@add.re.ss" + default = mailaddress(usr) file = File.expand_path((group+"/members/"+usr).untaint, @groupmapdir) if test(?s, file.untaint) - open(file, "r"){|f|f.gets.chomp}.untaint - else - mailaddress(usr) + rcpt = open(file, "r"){|f|f.gets.chomp}.untaint + if /^(off|skip):/ =~ rcpt && /@/ !~ rcpt + rcpt = "skip:"+default + end + return rcpt end + default + end + def delivergrpmail(user, grp) + end def ismember(user, grouporuser) return user if user==grouporuser @@ -1354,6 +1366,7 @@ And then prepare .qmail-$mailprefix-default file as below. | ./#{@myname} -list"], 'sendall_head' => ['「%s」宛のメイル送信', "Send message to `%s'"], + 'sendmem_head' => ['「%s」さん宛のメイル送信', "Send message to `%s'"], 'sendall_note' => ['メンバーへの連絡だけでなく、グループ非加入者がこれから加入する旨の通知などにも有用。', "Send this message to all of group."], 'sendall_done' => ['送信完了', "sending message done"], @@ -1389,6 +1402,7 @@ '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.'], 'address2send' => ['自分が参加しているグループのメンバーリストの先頭が自分。その直後にある入力欄には、そのML宛メッセージをどの宛先に配送するかを入れられる。そう、MLごとに自分への配送先を変えられるよ。', '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.'], + '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."], 'wholemembers' => ['グループ内グループを考慮した上で、現在グループ %s への通知は以下のメンバーに送られる。', "Consiering the groups registered in another group, notification to the group `%s' is send to members as follows."], 'noadmingroup' => ['管理できるグループはないっす', @@ -1683,11 +1697,12 @@ end def sendMail(to, subject, body, from=nil, rcptto=nil, header={}, thru=nil, spoolto=false) - # rcptto should be an Array + # rcptto should be an Array or nil body = NKF.nkf("-j", body) unless thru subject = NKF.nkf("-jM", (subject||"No subject").strip) to = safecopy(to) # cleanup tainted address subject.gsub!(/\n/, '') + rcptto.reject!{|i| /^(skip|off):/i =~ i} if rcptto.is_a?(Array) begin if (m=open("|-", "w")) header.each do |h, v| @@ -2776,20 +2791,29 @@ def extract_attachment(attachment) # Must return [text, href] strings to attached files href = ""; text = "" - dir = @attachmentdir + dir = @attachmentdir + Time.now.strftime("/%Y%m") if %r,(https?://[^/]+), =~ @opt['url'] server = $1 else msg = "`url' not set in after5.cf" return [msg, msg] end - + kakasi = @opt['kakasi'] && @opt['kakasi']+" -Ha -Ka -Ja -Ea -ka" urlbase = sprintf("%s%s/%s", server, File.dirname(ENV['SCRIPT_NAME']), dir) count=0 attachment.each {|a| basename = safecopy(File.basename(a['filename'])) - filename = safecopy(dir+"/"+basename) + encname = (kakasi ? + IO.popen(kakasi, "r+") do |k| + k.puts basename + k.close_write # force flush + k.gets.chomp.downcase + end + : + basename + ).gsub(/([^-_0-9a-z=,.@])/){"~"+$1.unpack("H*")[0].to_s} + filename = safecopy(dir+"/"+encname) umask = File.umask(022) sz = a['value'].bytesize next if sz == 0 @@ -2801,12 +2825,13 @@ next end begin - (test(?d, dir) && test(?w, dir)) or Dir.mkdir(dir) + require 'fileutils' + (test(?d, dir) && test(?w, dir)) or FileUtils.mkdir_p(dir) open(filename, "w") {|x| x.write a['value']} File.chmod(0664, filename) - text += sprintf("%d: %s/%s\n", count, urlbase, basename) + text += sprintf("%d: %s/%s\n", count, urlbase, encname) href += sprintf("%d: %s/%s\n", - count, filename, urlbase, basename) + count, filename, urlbase, encname) rescue ensure File.umask(umask) @@ -2841,7 +2866,7 @@ if viamail then prohibitviahttp() name = unquoted(ENV['DEFAULT']) - user = @sc.ismembersemail(ENV['SENDER']) + user = @sc.ismembersemail(ENV['SENDER']) # should here be (,name)?? if Regexp.new("(.*)("+Regexp.quote(@mailadmsuffix)+")") =~ name # To: GROUP/adm*@domain # -> Forward to group administrator(s) @@ -2883,7 +2908,7 @@ end nick = @sc.nickname(user) from = sprintf("%s <%s>", nick, user) - subj = @params['subject'][0]['value'] || "Message from "+@myname + subj = @params['subject'][0]['value'].toeuc || "Message from "+@myname body = @params['body'][0]['value'].gsub("\r", "").untaint # Extract attachment file if @params['attachment'].is_a?(Array) @@ -2985,7 +3010,7 @@ s = ENV['SENDER'] if !catch(:senderok) { throw :senderok, true if rcpts.grep(s)[0] - throw :senderok, true if @sc.ismembersemail(s) + throw :senderok, true if @sc.ismembersemail(s, name) } # sender is not allowed to send to ML sendMail(s, "You are not allowed to send to this ML", @@ -3003,9 +3028,9 @@ spooling ? mldir : nil) if !viamail then @O.print @H.elementln("h1"){msg('sendall_done')} - @O.print @H.p(sprintf(msg('sendall_head'), + @O.print @H.p(sprintf(msg(groupmode ? 'sendall_head' : 'sendmem_head'), nickname(name))+" "+msg('done')) - @O.print @H.elementln("pre"){extract_report[1]} + @O.print @H.elementln("pre"){extract_report[1].toeuc} link2home() @O.print footer() return true @@ -3312,9 +3337,12 @@ } + \ '' + \ @H.p(msg('address2send')) + \ + @H.p(msg('skip:')) + \ @H.p(msg('groupwarn', 'shortnameplz')) + \ @H.submit_reset("GO") } # form + link2home() + @O.print footer() end def groupnamesString() @H.elementln("p", {'class'=>'listup'}){ @@ -4228,7 +4256,7 @@ if /^Content.*filename=([\'\"])?(\S*)\1/i =~ unit newvalue['filename'] = $2 end - newvalue['value'] = unit.sub(/.*\r\n\r\n/m, "") + newvalue['value'] = unit.sub(/.*?\r\n\r\n/m, "") # Shortest match if /^Content-type:\s*(\S*)/i =~ unit newvalue['content-type'] = $1 else