changeset 45:1b16890d61d6 draft

ML: digited subject, ML-specific email addresses, spooling
author HIROSE Yuuji <yuuji@gentei.org>
date Mon, 11 Jun 2012 00:14:40 +0900
parents 1c0505ce5d6a
children b491a43bd5fe
files after5.rb
diffstat 1 files changed, 125 insertions(+), 35 deletions(-) [+]
line wrap: on
line diff
--- a/after5.rb	Wed May 30 11:49:20 2012 +0900
+++ b/after5.rb	Mon Jun 11 00:14:40 2012 +0900
@@ -4,7 +4,7 @@
 # Associative Scheduling Table - after5
 # (C)2003, 2004, 2006, 2008, 2012 by HIROSE Yuuji [yuuji<at>gentei.org]
 # $Id: after5.rb,v 1.19 2012/04/01 11:52:25 yuuji Exp yuuji $
-# Last modified Wed May 30 11:47:39 2012 on firestorm
+# Last modified Mon Jun 11 00:12:27 2012 on firestorm
 # See http://www.gentei.org/~yuuji/software/after5/
 # このスクリプトはEUCで保存してください。
 $hgid = <<_HGID_.split[1..-2].join(" ")
@@ -340,6 +340,10 @@
       return user.sub(/@.*/, '')
     end
   end
+  def mailaddress(user, grp = nil)
+    grp ? mail4grp(user, grp) : \
+    (getuserattr(user, 'email') || user)
+  end
   def setnickname(user, nickname)
     putuserattr(user, 'name', nickname)
   end
@@ -407,7 +411,7 @@
       if test(?d, memd)
 	Dir.foreach(memd){|a|
 	  next if /^\./ =~ a
-	  map[g]['members'] << a
+	  map[g]['members'] << a.untaint
 	}
       end
     }
@@ -423,6 +427,9 @@
     grp = groups.grep(group)[0]	# group may be tainted, using kept name
     return nil unless grp
     for u in users
+      m = nil
+      u, m = u if u.is_a?(Array) # ["user", "mailto"]
+      m = nil if mailaddress(u)==m || /@/ !~ m
       next unless account_exists(u)
       mdir = File.join(@groupmapdir, grp, role).untaint
       file = File.join(mdir, u).untaint
@@ -433,7 +440,7 @@
 	@groupmap[grp][role] << u
 	@groupmap[grp][role].uniq
 	Dir.mkdir(file) unless test(?d, mdir)
-	open(file, "w"){|x|}	# Touch it
+	open(file, "w"){|x|x.puts m if m}
       end
     end
     grp
@@ -479,7 +486,8 @@
     return nil if %r@[\/()\;|,$\%^!\#&\'\"]@ =~ user
     email = email || user
     @usermap[user] = {}
-    Dir.mkdir(File.join(@usermapdir, user))
+    dir = File.join(@usermapdir, user).untaint
+    test(?d, dir) || Dir.mkdir(dir)
     putuserattr(user, 'email', email)
   end
   def deleteuser(user)
@@ -523,10 +531,19 @@
       ! @groupmap.select{|k, v| k==instance}.empty?
     end
   end
+  def mail4grp(usr, group)
+    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)
+    end
+  end
   def ismember(user, grouporuser)
-    return true if user==grouporuser
+    return user if user==grouporuser
     if @groupmap[grouporuser]
-      @groupmap[grouporuser]['members'].grep(user)[0]
+      @groupmap[grouporuser]['members'].grep(user)[0] &&
+        mail4grp(user, grouporuser)
     end
   end
   def isuser(user)
@@ -1055,7 +1072,7 @@
       'pswddb'		=> 's/a5pswd',
       'lang'		=> 'j',
       'notifymail'	=> true,
-      'mailbracket'	=> '[%s-ML]',
+      'mailbracket'	=> '[%n-ML]',
     }
     @ntlist = [
       ['nt10m', "10"+msg('minutes', 'before')],
@@ -1403,9 +1420,8 @@
   def outputError(*msg)
     @O.print @H.p(msg('error')+sprintf(*msg))
   end
-  def mailaddress(user)
-    email = @sc.getuserattr(user, "email")
-    email || user
+  def mailaddress(user, grp=nil)
+    @sc.mailaddress(user, grp)
   end
   def webpage(user)
     @sc.getuserattr(user, "webpage")
@@ -1450,6 +1466,7 @@
 	  throw :auth, nil
 	end
       elsif passwd == ''
+        # Create new user from Web-UI
 	newp = pm.setnewpasswd(user, @opt['pswdlen'])
 	@sc.createuser(user, user)
 	sendMail(email, "#{@mybase} new account",
@@ -1532,7 +1549,33 @@
     end
   end
 
-  def sendMail(to, subject, body, from=nil, rcptto=nil, header={}, thru=nil)
+  def dospool(dir, outhandle)
+    seq=1
+    seqfile=File.expand_path("seq", dir).untaint
+    spooldir=File.expand_path("spool", dir).untaint
+    test(?d, spooldir) or Dir.mkdir(spooldir)
+    if test(?s, seqfile)
+      seq=open(seqfile, "r"){|s|s.gets.to_i}
+    end
+    seq+=1 while test(?s, (newfile=sprintf("%s/%d", spooldir, seq)))
+    open(newfile, "w") do |spoolfile|
+      countdone = nil
+      while line=STDIN.gets
+        if !countdone && /^X-ML-Name: / =~ line
+          line += sprintf("X-Mail-Count: %d\n", seq) 
+          coutndone=true
+        end
+        spoolfile.print line
+        outhandle.print line
+      end
+    end
+    open(seqfile, "w"){|s| s.puts seq.to_s} # update `seq' file
+  end
+  def mlseq(dir)
+    open(dir+"/seq", "r"){|s|s.gets.to_i+1}
+  end
+  def sendMail(to, subject, body, from=nil, rcptto=nil, header={},
+               thru=nil, spoolto=false)
     body = NKF.nkf("-j", body) unless thru
     subject = NKF.nkf("-jM", subject.strip)
     to = safecopy(to)		# cleanup tainted address
@@ -1557,16 +1600,29 @@
 	# exec(@attr['mail'], "-s", subject, to)
         recipient = rcptto || [to]
         #p recipient
-        if ENV['MAILCMD']
-          #exec("qmail-inject", "yuuji@gentei.org", "yuuji@koeki-u.ac.jp")
-          open("/tmp/body", "w") {|w| w.print STDIN.readlines.join
-            w.puts "---"
-            w.puts recipient.join(",\n")
-          }
-          exit 0
-        else
-          #recipient.unshift "-f"+header['return-path'] if header['return-path']
-          exec(ENV['MAILCMD'] || @opt['sendmail'], *recipient)
+        if spoolto && spoolto.is_a?(String) &&
+            proc {
+            require 'fileutils'
+            begin
+              test(?d, spoolto) or FileUtils.mkdir_p(spoolto)
+              test(?w, spoolto)
+            rescue
+              nil
+            end}.call &&
+            (tee=open("|-", "w")) # popen should be done in if-condition
+          dospool(spoolto, tee)
+        else  
+          if ENV['MAILCMD']
+            #exec("qmail-inject", "yuuji@gentei.org", "yuuji@koeki-u.ac.jp")
+            open("/tmp/body", "w") {|w| w.print STDIN.readlines.join
+              w.puts "---"
+              w.puts recipient.join(",\n")
+            }
+            exit 0
+          else
+            #recipient.unshift "-f"+header['return-path'] if header['return-path']
+            exec(ENV['MAILCMD'] || @opt['sendmail'], *recipient)
+          end
         end
 	exit 0;
       end
@@ -2529,7 +2585,7 @@
     exit 0
   end
   # ML functions
-  def tagify_subj(body, tag)
+  def tagify_subj(body, tag, removeregexp)
     # This method should be generic for other headers than `Subject'?
     hold = []
     ret = []
@@ -2549,6 +2605,7 @@
       else
         if skip then
           sj = hold.join.toeuc.sub("Subject: ", "").gsub(tag, "").strip
+          sj.gsub!(removeregexp, "")
           sj = sj.sub(/^(re: *)+/i, "Re: ").gsub("\n", "")
           ret << "Subject: "+NKF.nkf('-jM', tag+" "+sj).strip+"\n"
         else
@@ -2580,22 +2637,30 @@
       name = ENV['DEFAULT']
     else                        # via http
       return nil unless checkauth
-      name = @params['name']
+      name = @params['name'].untaint
       nick = @sc.nickname(@params['user'])
       from = sprintf("%s <%s>", nick, @params['user'])
       body = @params['body'].gsub("\r", "").untaint
     end
-    to = sprintf("%s-%s@%s", @opt['mailprefix'], name, @opt['maildomain'])
+    mldir = "ml/"+name
+    prefix = (@opt['mailprefix'] || "")
+    dash = prefix > '' ? "-" : ""
+    to = sprintf("%s%s%s@%s", prefix, dash, name, @opt['maildomain'])
     subj = @params['subject'] || "Message from "+@myname
-    sjtag = sprintf(@opt['mailbracket'], nickname(name))
-    subj = sjtag.strip+" "+subj.gsub(sjtag, "")
+    sjtag = @opt['mailbracket'].gsub("%n", nickname(name)).
+      gsub("%i", name).
+      gsub(/%(\d*)c/){("%0"+$1+"d") % [mlseq(mldir)]}
+    tagpt = Regexp.quote(@opt['mailbracket']). # compute bracket pattern
+      gsub("%n", Regexp.quote(nickname(name))).
+      gsub("%i", Regexp.quote(name)).
+      gsub(/%(\d*)c/, '\d+')
+    subj = sjtag.strip+" "+subj.gsub(Regexp.new(tagpt), "")
     if viamail then
-      body = tagify_subj(STDIN.readlines, sjtag).join
-      # body = STDIN.readlines.join
+      body = tagify_subj(STDIN.readlines, sjtag, Regexp.new(tagpt)).join
     end
     header = {
       "Reply-to" => to,
-      "X-ML-Driver" => $hgid,
+      "X-ML-Driver" => ($hgid || @myname),
       "X-ML-Driver-URI" => $myurl,
       "X-ML-Name" => name,
       "Errors-to" => @opt['maintainer'],
@@ -2605,12 +2670,13 @@
               @sc.members(name)
             else
               [name]
-            end.collect {|u| mailaddress(u)}
+            end.collect {|u| mailaddress(u, name)}
     # p rcpts
     # p to
     sendMail(to, subj, body, from, rcpts,
              header,
-             ENV['SENDER'])
+             ENV['SENDER'],
+             @opt['mlspooling'] ? mldir : nil)
     if !viamail then
       @O.print @H.elementln("h1"){msg('sendall_done')}
       @O.print @H.p(sprintf(msg('sendall_head'),
@@ -2833,6 +2899,7 @@
     @H.elementln("form", {'action'=>@myname+"?-groupmod", 'method'=>'POST'}){
       @H.elementln("table", {'border'=>'1', 'vertical-align'=>'top'}){
 	grmap.collect{|g, ghash|
+          memberp = @sc.ismember(user, g)
 	  @H.elementln("tr"){
 	    @H.element("td", @sc.isadmin(user, g) ? admclass : nil){
 	      g
@@ -2847,7 +2914,6 @@
 	      }
 	    } + \
 	    @H.element("td"){
-	      memberp = @sc.ismember(user, g)
 	      if ghash['admin'].grep(user)[0]
 		@H.text("groupname-#{g}", ghash['name'], nil, 20)
 	      else
@@ -2857,8 +2923,14 @@
 	      @H.radio("groupadd-#{g}", "no", "OUT", !memberp)
 	    } + \
 	    @H.element("td"){
-	      ghash['members'].collect{|u|
-		@sc.nickname(u)
+              memlist = ghash['members']
+              if memberp        # move this user to the beginning of list
+                memlist.delete(user)
+                memlist.unshift(user)
+              end
+              memlist.collect{|u|
+                @sc.nickname(u) + \
+                ((u == user) ? ("("+@H.text("mail4-#{g}", memberp, 30, 80)+")") : "")
 	      }.join(", ")
 	    } + \
             @H.element("td"){
@@ -2903,6 +2975,18 @@
 	end
       end
       #
+      # as a member, change group-specific mailto address.
+      key = "mail4-#{grp}"
+      if memberp && @params[key] && memberp != @params[key]
+        @sc.addgroup(grp, [[user, @params[key]]])
+        newmemp = @sc.ismember(user, grp)
+        @O.print @H.elementln("p") {
+          sprintf("%s `%s' %s =&gt; %s%s",
+                  msg('group'), grp, msg('mailaddress'), @params[key],
+                  @params[key]==mailaddress(user) ? "(same)" : "")
+        }
+      end
+      #
       # as a owner, change the name of group
       if @sc.isadmin(user, grp) &&
 	  (newname = @params["groupname-#{grp}"]) &&
@@ -3462,7 +3546,12 @@
     prohibitviahttp()
     pm = open_pm()
     exit 1 unless pm
+    email = nil
+    if /(.*@.*)=(.*@.*)/ =~ user
+      user, email = $1, $2
+    end
     newpwd = pm.setnewpasswd(user, 4)
+    @sc.createuser(user, email)
     print "#{user}'s password is #{newpwd}\n"
     pm.close()
     exit 0
@@ -3472,6 +3561,7 @@
     pm = open_pm()
     exit 1 unless pm
     pm.delete(user)
+    @sc.deleteuser(user)
     pm.close()
     exit 0
   end
@@ -3497,7 +3587,7 @@
 	  when /^(no|none|null|nil|false|0|off)$/io
 	    @opt[key] = nil
 	  else
-	    @opt[key] = value
+	    @opt[key] = value.untaint
 	  end
 	  print "#{key} set to #{value}\n" if $DEBUG
 	end

yatex.org