changeset 14:9aa45b698d56 draft

RCS-revision 1.15 date: 2007/04/28 01:21:33; author: yuuji; state: Exp; lines: +425 -44 decode schedule text
author HIROSE Yuuji <yuuji@gentei.org>
date Sat, 28 Apr 2007 01:21:33 +0859
parents d2c36cb4206a
children 580c1b0fa27e
files after5.rb
diffstat 1 files changed, 425 insertions(+), 44 deletions(-) [+]
line wrap: on
line diff
--- a/after5.rb	Sat Apr 10 17:07:31 2004 +0859
+++ b/after5.rb	Sat Apr 28 01:21:33 2007 +0859
@@ -1,9 +1,9 @@
 #!/usr/local/bin/ruby
 #
 # Associative Scheduling Table - after5
-# (C)2003, 2004 by HIROSE Yuuji [yuuji@gentei.org]
-# $Id: after5.rb,v 1.14 2004/04/10 17:07:31 yuuji Exp $
-# Last modified Sun Apr 11 02:07:17 2004 on firestorm
+# (C)2003, 2004, 2006 by HIROSE Yuuji [yuuji@gentei.org]
+# $Id: after5.rb,v 1.15 2007/04/28 01:21:33 yuuji Exp $
+# Last modified Sat Apr 28 10:19:45 2007 on firestorm
 # See http://www.gentei.org/~yuuji/software/after5/
 # このスクリプトはEUCで保存してください。
 
@@ -121,6 +121,96 @@
     "\n</select>\n"
   end
 end
+class TEXTout
+  def isBlock(elt)
+    /\b(tr|[udo]l|p|div)\b/i =~ elt
+  end
+  def isEOC(elt)
+    /\bt[dh]\b/i =~ elt
+  end
+  def eoelem(elt)
+    r = ""
+    r << "\n" if isBlock(elt)
+    r << " " if isEOC(elt)
+    r
+  end
+  def contenttype(type = "text/plain", charset = $charset)
+    ### sprintf "Content-type: %s; charset=%s\n\n", type, charset
+    ""
+  end
+  def initialize(title = "Document")
+    @title = title
+    @eltstack = []
+  end
+  def resetstack()
+    @eltstack = []
+  end
+  def head(title = @title, css = "style.css")
+    sprintf <<__EOS__, title, css
+===== [[[ %s  ]]] =====
+__EOS__
+  end
+
+  def startelement(elt, attrs = {}, nl = true)
+    attr = ""
+    x = sprintf "%s", " "*@eltstack.length
+    @eltstack.push(elt)
+    x
+  end
+  def endelement(elt = nil, nl = true)
+    if elt
+      x = elt
+      @eltstack.pop
+    else
+      x = @eltstack.pop
+    end
+    eoelem(x)
+  end
+  def element(elt, attrs = nil, nl = nil)
+    attr = ""
+    lf = nl ? "\n" : ""
+    body = yield
+    #sprintf "<%s%s>%s%s%s</%s>%s", elt, attr, lf, body, lf, elt, lf
+    sprintf "%s%s", body, eoelem(elt)
+  end
+  def elementln(elt, attr=nil)
+    body = yield
+    sprintf "%s\n", body
+  end
+  def a(href, anchor = nil, attrs = {})
+    attr = attrs
+    attr['href'] = href
+    # sprintf "%s\n", href
+    anchor
+  end
+  def p(msg, attrs=nil)
+    element("p", attrs){msg}
+  end
+  def text(name, value='', size=nil, maxlength=nil)
+    ""
+  end
+  def hidden(name, value='')
+    ""
+  end
+  def radio(name, value, text='', checked=nil)
+    ""
+  end
+  def checkbox(name, value, text='', checked=nil)
+    ""
+  end
+  def submit(name, value, text='')
+    ""
+  end
+  def reset(name, value, text='')
+    ""
+  end
+  def submit_reset(name)
+    ""
+  end
+  def select(name, range, selected=nil)
+    ""
+  end
+end
 
 class PasswdMgr
   def initialize(name, mode=0640)
@@ -924,6 +1014,7 @@
     @schedulearea = {'rows'=>'4', 'cols'=>'60', 'name'=>'schedule'}
     @oldagent = (%r,Mozilla/4, =~ ENV['HTTP_USER_AGENT'])
     @lang = 0
+    @mailmode = nil
     @saveprefsregexp = /^(display(mode|days)$|nt|headline)/
     @opt = {
       'conf'		=> @mybase+".cf",
@@ -1007,7 +1098,7 @@
     # @job is here
     @O.print @H.startelement("body", bodyclass, true)
     @O.print @H.endelement(nil, true) # body
-    @O.print "</html>\n"	# html
+    @O.print @H.endelement("html", true)	# html
     setcookie()
 
     print @O.readlines
@@ -1032,6 +1123,7 @@
 	'addsched'	=> ['新規予定項目の登録', 'Register new schedule'],
 	'defthisday'	=> ['デフォルトの日付はこの日になってま', ''],
 	'24hour'	=> ['24時間制4桁でね<br>(0000〜2359)<br>%sは時刻指定なし', 'in 24-hour<br>(0000-2359)<br>%s for whole day'],
+	'24hourtxt'	=> ['24時間制4桁でね(0000〜2359), %sは時刻指定なし', 'in 24-hour(0000-2359), %s for whole day'],
 	'reqnotify'	=> ['通知メイルいるけ?', 'Previous notification'],
 	'rightnow'	=> ['登録時にすぐ', 'Right now on registration'],
 	'immediatenote'	=> ['に以下の予定を登録しました',
@@ -1068,6 +1160,8 @@
 	'join'		=> ['参加', 'join'],
 	'regist'	=> ['登録', 'register'],
 	'remove'	=> ['削除', 'remove'],
+	'move'		=> ['移動', 'move'],
+	'newdate'	=> ['移動先時刻', 'New date'],
 	'deletion'	=> ['完全消去', 'deletion'],
 	'deletionwarn'	=> ['OK押したら即消去。確認とらないぞ',
 	  'Hitting OK immediately delets this group, be carefully!'],
@@ -1150,7 +1244,18 @@
 	'nicknamenote'	=> ['ニックネームを消去するとデフォルト名になりんす.',
 	  'Default name is displayed if you remove nickname.'],
 	'nothingtodo'	=> ['って何もやることあらへんかったで',
-	  'Nothing to do for this transaction.']
+	  'Nothing to do for this transaction.'],
+	'schedlist'	=> [' and %d days Schedule list',
+	  'から%d日間の予定一覧'],
+	'nothing'	=> ['なんもないす', 'Nothing'],
+	'sessionpswd'	=> ['セッションパスワード(これはいじらないでね)',
+	  'Session Password(Do not modify this)'],
+	'date'		=> ['日付', 'Date'],
+	'time'		=> ['時刻指定', 'Time'],
+	'publicp'	=> ['公開=yes、非公開=no', 'Public?'],
+	'neednotify'	=> ['通知メイル(要らないのは消してね)',
+	  'Leave lines for notification timing'],
+	'schedulehere'	=> ['以下登録内容', 'Your Schedule below']
       }
     end
     keyword.collect{|k|
@@ -1193,10 +1298,17 @@
       '%' + $1.unpack('H2' * $1.size).join('%').upcase
     end.tr(' ', '+')
   end
+  def purify(string)
+    string.gsub(/[\040-\177]/) {encode($&)}
+  end
   def decode!(string)
     string.gsub!(/\+/, ' ')
     string.gsub!(/%(..)/){[$1.hex].pack("c")}
   end
+  def decode(string)
+    string.gsub(/\+/, ' ')
+    string.gsub(/%(..)/){[$1.hex].pack("c")}
+  end
 
   def gencookie(name, a, expire)
     x = a.collect{|k, v|
@@ -1250,8 +1362,14 @@
   def webpage(user)
     @sc.getuserattr(user, "webpage")
   end
+  def checkauth_mail()
+    return true			# temporary
+  end
   def checkauth()
-    auth = catch (:auth) {
+    if @mailmode && @params['sessionpw']
+      return checkauth_mail
+    end
+    auth = catch(:auth) {
       unless @params['user']
 	outputError(@H.a(@myname, msg('loginfirst')))
 	throw :auth, nil 
@@ -1542,7 +1660,7 @@
 		if !s.empty?
 		  s.keys.sort.collect{|time|
 		    s[time].keys.sort.collect{|who|
-		      text = s[time][who]['sched']
+		      text = decode(s[time][who]['sched'])
 		      topic = sprintf "%s%s",
 			time == @opt['alldaydir'] ? '' : time+":",
 			if personal
@@ -1702,6 +1820,14 @@
 		    @opt['tdskip']
 		  end
 		} + \
+		@H.element("td"){
+		  if editable
+		    @H.a(@myname+"?-move+#{date}/#{time}/#{who}",
+			 msg('move'))
+		  else
+		    @opt['tdskip']
+		  end
+		} + \
 		@H.element("td"){s[time][who]['sched']}
 	      }
 	    }.join("\n")
@@ -1717,6 +1843,45 @@
       ''
     end
   end
+  def dayTextString(user, datestr, range, personal = nil)
+    r = ''
+    cols = 20
+    header = "-" * cols + "\n"
+
+    day = Time.mktime(*date2ymd(datestr))
+    i = -1
+    while (i+=1) < range
+      d = Time.at(day+i*3600*24)
+      date = sprintf("%04d/%02d/%02d", d.year, d.month, d.day)
+      datewn = sprintf("%s(%s)", date, @msg['wnames'][@lang][d.wday])
+      s = @sc.day_all(date, user, personal)
+      next if s.empty?
+
+      r << sprintf("TIME Who %s - What\n", datewn)
+
+      for time in s.keys.sort
+	tstr = case time
+	       when @opt['alldaydir']
+		 msg('allday')
+	       else
+		 sprintf "%02d:%02d", time.to_i/100, time.to_i%100
+	       end
+	r << s[time].keys.collect{|who|
+	  editable = (user==who || @sc.ismember(user, who))
+	  groupp   = grepgroup(who)
+	  sprintf("%-5s %-10s %s", tstr, nickname(who), s[time][who]['sched'])
+	}.join("\n") + "\n"
+      end
+      r << "-" * cols + "\n"
+    end
+    footer = "That's all\n"
+    if r > ''
+      header + r + footer
+    else
+      ''
+    end
+
+  end
   #
   # new form
   def displayRegistForm(date, multiple = true)
@@ -1920,9 +2085,9 @@
       return Time.at(base-rate*num)
     elsif /nt(\d+)d/ =~ symbol
       seconds = $1.to_i*3600*24
-      targetday= Time.at(base-seconds).to_a
-      targetnight =
-	Time.mktime(*(targetday.indexes(5,4,3)+[@opt['night'].to_i]))
+      tday= Time.at(base-seconds)
+      target = [tday.year, tday.month, tday.day, @opt['night'].to_i]
+      targetnight = Time.mktime(*target)
     elsif "nttoday" == symbol
       Time.mktime(year.to_i, month.to_i, day.to_i, @opt['morning'])
     end
@@ -1967,6 +2132,29 @@
 
   end
 
+  def regulate_time(y, m, d, tm)
+    if tm > 2399
+      sh, smin = 23, 59
+      timedir=@opt['alldaydir']
+      tmstr = msg('allday')
+    else
+      sh = (tm/100).to_i
+      smin = (tm%100).to_i
+      timedir = sprintf("%04d", tm)
+      tmstr = sprintf("%d:%02d", sh, smin)
+    end
+    time = nil
+    begin
+      time = Time.mktime(y, m, d, sh, smin)
+    rescue
+      outputError "%s<br>\nyear=%s<br>month=%s<br>day=%s<br>time=%s\n",
+	msg('invaliddate'),
+	@params['year'], @params['month'], @params['day'], @params['time']
+      return nil
+    end
+    [time, timedir, tmstr]
+  end
+
   #
   # add or remove a schedule
   #
@@ -1992,25 +2180,8 @@
     sm = @params['month'].to_i
     sd = @params['day'].to_i
     tm = @params['time'].to_i
-    if tm > 2399
-      timedir=@opt['alldaydir']
-      sh, smin = 23, 59
-      tmstr = msg('allday')
-    else
-      sh = (tm/100).to_i
-      smin = (tm%100).to_i
-      timedir = sprintf("%04d", tm)
-      tmstr = sprintf("%d:%02d", sh, smin)
-    end
-    time = nil
-    begin
-      time = Time.mktime(sy, sm, sd, sh, smin)
-    rescue
-      outputError "%s<br>\nyear=%s<br>month=%s<br>day=%s<br>time=%s\n",
-	msg('invaliddate'),
-	@params['year'], @params['month'], @params['day'], @params['time']
-      return nil
-    end
+
+    time, timedir, tmstr = regulate_time(sy, sm, sd, tm)
 
     #
     # Check continuous schedule registration
@@ -2054,6 +2225,7 @@
 	end
 	begin
 	  (text = @params['schedule'].strip.gsub(/\r+\n/, $/)) << "\n"
+	  text = purify(text)
 	  replace = (/modify/i =~ @params['editmode'])
 	  rc = @sc.register(registerer, y, m, d, timedir, text, replace)
 	  if @params['pub'] && /yes/ =~ @params['pub']
@@ -2090,18 +2262,26 @@
 		       "-"*70)
       sendnotify(registerer, "Registration completed", header+text)
     end
-    show(sprintf("%04d/%02d/%02d", sy, sm, sd))
-    @O.print "add_remove" if user == @author
+    unless @mailmode
+      show(sprintf("%04d/%02d/%02d", sy, sm, sd))
+      @O.print "add_remove" if user == @author
+    end
   end
 
   # add
   def addsched()
-    add_remove(/remove/i =~ @params['editmode'])
+    if "move" == @params['editmode']
+      add_remove(:remove)
+      for p in %w(year month day time) do
+	@params[p] = @params["new"+p]
+      end
+    end
+    add_remove(/^remove/i =~ @params['editmode'])
   end
 
   #
   # Display remove or modify screen
-  def remove_modify(datetime, remove)
+  def remove_modify(datetime, editmode)
     if !checkauth
       return nil
     end
@@ -2127,7 +2307,7 @@
       return nil
     end
     @O.print @H.elementln("h1"){
-      sprintf "%s %s", datetime, remove ? msg('remove') : msg('modify')
+      sprintf "%s %s", datetime, msg(editmode)
     }
     @O.print @H.elementln("form", {'action'=>@myname+"?-addsched", 'method'=>'POST'}){
       pubp=(@sc.getfile(user, y, m, d, time, 'pub').to_i > 0)
@@ -2138,16 +2318,45 @@
       "<input type=\"hidden\" name=\"month\" value=\"%02d\">\n" % m.to_i + \
       "<input type=\"hidden\" name=\"day\" value=\"%02d\">\n" % d.to_i + \
       "<input type=\"hidden\" name=\"time\" value=\"%04d\">\n" % time.to_i + \
-      msg('reqnotify') + "<br>\n" + \
-      @ntlist.collect{|nt, v|
-	cronp = @sc.getfile(user, y, m, d, time, nt)
-	sprintf "<input type=\"checkbox\" name=\"%s\"%s>%s \n",
-	  nt, (cronp ? " checked" : ""), v
-      }.join + "<br>" + \
+      if editmode=="move"
+	@H.elementln("table") {
+	  @H.elementln("tr", {"colspan" => "2"}) {msg('newdate')} + \
+	  @H.elementln("tr") {
+	    @H.element("th"){"Year"} + \
+	    @H.element("td"){@H.select("newyear", y.to_i..y.to_i+5, y)}
+	  } + \
+	  @H.elementln("tr") {
+	    @H.element("th"){"Month"} + \
+	    @H.element("td"){@H.select("newmonth", 1..12, m)}
+	  } + \
+	  @H.elementln("tr") {
+	    @H.element("th"){"Day"} + \
+	    @H.element("td"){@H.select("newday", 1..31, d)}
+	  } + \
+	  @H.elementln("tr") {
+	    @H.element("th"){"Time"} + \
+	    @H.element("td"){
+	      "<input type=text name=\"newtime\" value=\"#{time}\" " + \
+	      "size=\"8\" maxlength=\"4\">"
+	    }
+	  }
+	}
+      end.to_s + \
+      @H.elementln("div", {"style" =>
+		     "visibility: " +
+		     (editmode=="move" ? "hidden" : "show") + "\""}) {
+	msg('reqnotify') + "<br>\n" + \
+	@ntlist.collect{|nt, v|
+	  cronp = @sc.getfile(user, y, m, d, time, nt)
+	  sprintf "<input type=\"checkbox\" name=\"%s\"%s>%s \n",
+	    nt, (cronp ? " checked" : ""), v
+	}.join + "<br>"
+      } + \
       @H.element("textarea", @schedulearea) {text} + "<br>" + \
       @H.radio("editmode", "append", msg('append')) + ' / ' + \
-      @H.radio("editmode", "modify", msg('modify'), !remove) + ' / ' + \
-      @H.radio("editmode", "remove", msg('remove'), remove) + ' / ' + \
+      @H.radio("editmode", "modify", msg('modify'), editmode=="modify")+' / '+\
+      @H.radio("editmode", "remove", msg('remove'), editmode=="remove")+' / '+\
+      @H.radio("editmode", "move", msg('move'), editmode=="move") + ' / ' + \
       "<br>\n" + \
       msg('publicok') + \
       @H.radio("pub", "yes", msg('yes'), pubp) + \
@@ -2158,10 +2367,13 @@
     @O.print "remove_modify" if user == @author
   end
   def remove(datetime)
-    remove_modify(datetime, true)
+    remove_modify(datetime, "remove")
   end
   def modify(datetime)
-    remove_modify(datetime, false)
+    remove_modify(datetime, "modify")
+  end
+  def move(datetime)
+    remove_modify(datetime, "move")
   end
 
   def prohibitviahttp()
@@ -2839,6 +3051,168 @@
     admgroup(newgroup)
   end
 
+  #
+  # Methods Related to viaMail functions
+  def gen_sessionpswd()
+    
+  end
+  def viamail_registform()
+    c = "# "
+    nl = "\n"
+    user = @params['user']
+    msg('addsched') + "-" * 20 + nl*2 + \
+    c + msg('user') + nl + \
+    "user=" + user + nl*2 + \
+    c + msg('sessionpswd') + nl + \
+    "sp=hoge" + nl*2 + \
+    c + msg('date') + nl + \
+    "date="+Time.now.strftime("%Y/%m/%d") + nl*2 + \
+    c + msg('time') + sprintf(msg('24hourtxt'), @opt['alldaydir']) + nl + \
+    "time=3000"+nl*2 + \
+    c + msg('publicp') + nl + \
+    "public=yes" + nl*2 + \
+    c + msg('neednotify') + nl + \
+    "nt10m=yes (%s)
+nttoday=yes (%s)
+nt1d=yes (%s)
+nt7d=yes (%s)" % ["10"+msg('minutes')+msg('before'),
+      msg('theday'), msg('precedingday'),
+      "7"+msg('days')+msg('before')] + nl*2 + \
+
+    c + msg('schedulehere')
+  end
+  def viamail_footer()
+    viamail_registform()
+  end
+  def show_by_text(date, days)
+    user = @params['user']
+    personal = true
+    sched = dayTextString(user, date, days, personal)
+    # @O.print outstr
+
+    sendMail(mailaddress(user),
+	     "After5 Schedule",
+	     @opt['url'] + "\n" + \
+	     Time.now.strftime("%Y/%m/%d") + \
+	     sprintf(msg('schedlist'), days) + "\n\n" + \
+	     if sched > ''
+	       sched
+	     else
+	       msg('noplan')+"\n"
+	     end + \
+	     viamail_footer
+	     )
+    
+  end
+  def parseHeader
+    contline=nil
+    header=Hash.new
+    text=Array.new
+
+    field=nil
+    # header
+    while line=STDIN.gets
+      text << line
+      break if /^$/ =~ line
+      
+      if /^\s+/ =~ line
+	if field
+	  header[field][-1] << line
+	end
+      else
+	if /^([^:]+):\s*(.*)/ =~ line
+	  field=$1.downcase
+	  header[field] or header[field] = []
+	  header[field] << $2
+	end
+      end
+    end
+    header
+  end
+  def mail_regsched()
+    @params = Hash.new		# Reset
+
+    reqparams = %w[user sp date time public]
+    otherparams = %w[nt10m nttoday nt1d nt7d]
+    setall = lambda{
+      reqparams.each{|key| return false unless @params.has_key?(key)}
+      return true
+    }
+    stack = ""
+    while line=gets # !setall.call && line=gets
+      if /^(\S+)=(.*)/ =~ line
+	next unless reqparams.index($1) || otherparams.index($1)
+	@params[$1] = $2
+	#if reqparams.index($1)
+	STDERR.print "Set #{$1} to #{$2}\n"
+	#end
+	buf = ""
+      elsif /^\s*\#|^$/ =~ line
+	# skip comments
+      else
+	buf += line
+      end
+    end
+    unless setall.call
+      STDERR.print "Insufficient variables\n"
+      exit 1
+    end
+    p buf
+    
+    y, m, d = date2ymd(@params["date"])
+    @params["year"] = y
+    @params["month"] = m
+    @params["day"] = d
+    @params["schedule"] = buf
+    @params["editmode"] = "modify"
+    @params["sessionpw"] = @params["sp"]
+    p @params
+    add_remove()
+  end
+  def mail_getsched()
+    user = nil
+    while bline=gets
+      if /(\S+@\S+)/ =~ bline
+	break if user=@sc.isuser($1)
+      end
+    end
+    unless user
+      sendMail(@opt['maintainer'], "viaMail Request Error",
+	       "This is `#{@mybase}' in #{@mydir}\n" +
+	       "Invalid schedule request from #{ENV['SENDER']}.\n\n")
+      exit 1
+    end
+    today = Time.now.strftime("%Y/%m/%d")
+    days = 7
+    if bline=gets
+      if /\d+/ =~ bline
+	days = bline.to_i
+      end
+    end
+    # Send user to schedules of today and near future
+    @params['user'] = user
+    show_by_text(today, days)
+  end
+  def doMail()
+    days = 7
+    # Confirm `via Mail'
+    prohibitviahttp()
+    @H = TEXTout.new
+    unless ENV['RECIPIENT'] && ENV['SENDER']
+      STDERR.print "Call me via qmail\n"
+      exit 1
+    end
+    @mailmode = true
+    header = parseHeader	# is this necessary?
+    if /regist/ =~ ENV["EXT"]
+      mail_regsched()
+    else
+      mail_getsched()
+    end
+  end
+
+  #
+  # Password related Methos
   def setpasswd(user)
     prohibitviahttp()
     pm = open_pm()
@@ -2937,6 +3311,10 @@
       when "-d"
 	$DEBUG = true
       when "-install"
+      when "-stream"
+	# ARGV.shift
+	# @job = 'show_by_text "2005/1/18"'
+	@job = 'doMail'
       when "-addsched"
 	@job = "addsched"
       when "-today"
@@ -2950,6 +3328,9 @@
       when "-remove"
 	ARGV.shift
 	@job = 'remove "'+parsedate(ARGV[0])+'"'
+      when "-move"
+	ARGV.shift
+	@job = 'move "'+parsedate(ARGV[0])+'"'
       when "-modify"
 	ARGV.shift
 	@job = 'modify "'+parsedate(ARGV[0])+'"'

yatex.org