Patch title: Release 87 bulk changes
Abstract:
File: /pliant/appli/mail.pli
Key:
    Removed line
    Added line
   
module "/pliant/language/unsafe.pli"
module "/pliant/language/context.pli"
module "/pliant/language/stream.pli"
module "/pliant/admin/file.pli"
module "/pliant/fullpliant/this_computer.pli"
module "/pliant/fullpliant/user.pli"
module "/pliant/appli/mail/database.pli"
module "/pliant/protocol/smtp/mail.pli"
module "/pliant/protocol/smtp/meta.pli"
module "/pliant/protocol/smtp/forward.pli"
module "/pliant/protocol/smtp/spam.pli"
module "/pliant/protocol/http/server.pli"
module "/pliant/protocol/http/style/default.style"
module "/pliant/util/encoding/base64.pli"
module "/pliant/util/encoding/date.pli"
module "/pliant/util/encoding/http.pli"
module "/pliant/language/unsafe.pli"
module "/pliant/language/context.pli"
module "/pliant/language/stream.pli"
module "/pliant/admin/file.pli"
module "/pliant/fullpliant/this_computer.pli"
module "/pliant/fullpliant/user.pli"
module "/pliant/appli/mail/database.pli"
module "/pliant/protocol/smtp/mail.pli"
module "/pliant/protocol/smtp/meta.pli"
module "/pliant/protocol/smtp/forward.pli"
module "/pliant/protocol/smtp/spam.pli"
module "/pliant/protocol/http/server.pli"
module "/pliant/protocol/http/style/default.style"
module "/pliant/util/encoding/base64.pli"
module "/pliant/util/encoding/date.pli"
module "/pliant/util/encoding/http.pli"
module "/pliant/util/encoding/qp.pli"
module "/pliant/util/crypto/random.pli"
module "/pliant/language/schedule/resourcesem.pli"
module "/pliant/protocol/smtp/mime.pli"
module "/pliant/util/crypto/random.pli"
module "/pliant/language/schedule/resourcesem.pli"
module "/pliant/protocol/smtp/mime.pli"
module "/pliant/protocol/common/mime.pli"


constant emil_is_available (file_query "embedded:/usr/bin/em
constant emil_is_available false # (file_query "embedded:/usr/bin/emil" standard)=success
if emil_is_available
  module "/pliant/language/stream/pipe.pli"
  module "/pliant/admin/execute.pli"


method page mail_preview user
  arg_rw HtmlPage page ; arg Str user
  mail_database2:data:current create user
  var Data:MailCurrent current :> mail_database2:data:curren
  implicit page
    table columns 1
      cell color (color hsl 50 5 75)
        table columns 2 border 0
          cell [From:]
          cell
             text current:from
          each t current:target
            if t:box<>""
              cell
                text (shunt t:mode<>"cc" "To:" "Cc:")
              cell
                text t:box
          cell [Subject:]
          cell
            bold
              text current:subject
    fixed
      text current:body
    var Array:FileInfo files := file_list mail_path+"attach/
    if files:size>0
      para
        var Intn total := 0
        table columns 2
          cell header [Attached file]
          cell header [Size in bytes]
          for (var Int i) 0 files:size-1
            cell
              text files:i:name
            cell
              text (string files:i:size)
            total += files:i:size
          cell header [Total]
          cell
            text string:total+" ("+(string (total+2^19)\2^20
    para
      var Str area
      button "Send it" noeol
        mail_send user area
        mail_reset user
        goto_backward 2
      var Data:MailBox m :> mailbox current:from
      var Array:FileInfo areas := file_list m:area_path stan
      if areas:size<>0     
        select "and store in in area " area noeol
          option "" ""
          for (var Int i) 0 areas:size-1
            var Str area := areas:i:name
            area := area 0 (area search "/" area:len)
if emil_is_available
  module "/pliant/language/stream/pipe.pli"
  module "/pliant/admin/execute.pli"


method page mail_preview user
  arg_rw HtmlPage page ; arg Str user
  mail_database2:data:current create user
  var Data:MailCurrent current :> mail_database2:data:curren
  implicit page
    table columns 1
      cell color (color hsl 50 5 75)
        table columns 2 border 0
          cell [From:]
          cell
             text current:from
          each t current:target
            if t:box<>""
              cell
                text (shunt t:mode<>"cc" "To:" "Cc:")
              cell
                text t:box
          cell [Subject:]
          cell
            bold
              text current:subject
    fixed
      text current:body
    var Array:FileInfo files := file_list mail_path+"attach/
    if files:size>0
      para
        var Intn total := 0
        table columns 2
          cell header [Attached file]
          cell header [Size in bytes]
          for (var Int i) 0 files:size-1
            cell
              text files:i:name
            cell
              text (string files:i:size)
            total += files:i:size
          cell header [Total]
          cell
            text string:total+" ("+(string (total+2^19)\2^20
    para
      var Str area
      button "Send it" noeol
        mail_send user area
        mail_reset user
        goto_backward 2
      var Data:MailBox m :> mailbox current:from
      var Array:FileInfo areas := file_list m:area_path stan
      if areas:size<>0     
        select "and store in in area " area noeol
          option "" ""
          for (var Int i) 0 areas:size-1
            var Str area := areas:i:name
            area := area 0 (area search "/" area:len)
            option http_decode:area area
            option area area
      eol
      button "Edit again"
        goto_backward



      eol
      button "Edit again"
        goto_backward



method page send_mime_part filename part filter emil -> stat
  arg_rw HtmlPage page ; arg Str filename part filter ; arg 
method page send_mime_part filename part http_options emil -> status
  arg_rw HtmlPage page ; arg Str filename part http_options ; arg CBool emil ; arg Status status
  var List:Str boundaries
  var Stream s
  if emil_is_available and emil
    stream_pipe (var Str in_stream) (var Str out_stream)
    execute "emil -F MIME -B BA" root "embedded:/" input fil
    s open in_stream in+safe+anyeol
  else 
    s open filename in+safe+anyeol
  (var MimeStream ms) bind s true
  while (ms header_line (var Str l))
    void
  if ms:multipart
    while (ms body_line l)
     void
    while not s:atend
      ms bind s false
      while (ms header_line l)
        void
  var List:Str boundaries
  var Stream s
  if emil_is_available and emil
    stream_pipe (var Str in_stream) (var Str out_stream)
    execute "emil -F MIME -B BA" root "embedded:/" input fil
    s open in_stream in+safe+anyeol
  else 
    s open filename in+safe+anyeol
  (var MimeStream ms) bind s true
  while (ms header_line (var Str l))
    void
  if ms:multipart
    while (ms body_line l)
     void
    while not s:atend
      ms bind s false
      while (ms header_line l)
        void
      if ms:name=part and (filter<>"html" or ms:mime="text/h
      if ms:name=part and (http_options<>"html" or ms:mime="text/html") and ms:mime<>"application/applefile"
        if emil_is_available and ms:encoding_model=undefined
        if emil_is_available and ms:encoding_model=undefined
           page send_mime_part filename part filter true
          page send_mime_part filename part http_options true
          return          
        var Str temp := file_temporary
        (var Stream t) open temp out+safe
        while (ms body_line l)
          t writechars l
        t close
        var Str ext := lower:part (part search_last "." part
        if ext=".htm"
          ext := ".html"
        page reset_http_answer
          return          
        var Str temp := file_temporary
        (var Stream t) open temp out+safe
        while (ms body_line l)
          t writechars l
        t close
        var Str ext := lower:part (part search_last "." part
        if ext=".htm"
          ext := ".html"
        page reset_http_answer
        page:http_request send_static_file temp "filter_"+(s
        page:http_request send_static_file temp "mime [dq]"+(shunt http_options="binary" "binary/*" http_options="text" "text/plain" query_mime_type:ext)+"[dq]"
        file_delete temp
        return success
      else
        while (ms body_line l)
          void
  status := failure


        file_delete temp
        return success
      else
        while (ms body_line l)
          void
  status := failure


method page mail_display user box filename buttons back_leve
  arg_rw HtmlPage page ; arg Str user ; arg Data:MailBox box
method page mail_display user box filename buttons back_level http_options
  arg_rw HtmlPage page ; arg Str user ; arg Data:MailBox box ; arg Str filename ; arg Str buttons ; arg Int back_level ; arg Str http_options
  implicit page
  implicit page
    var CBool detailed := options="detailed"
    var CBool detailed := http_options="detailed"
    var Str subject
    var Str from
    var List:Str tos
    var List:Str ccs
    var Str date
    var List:Str extras
    var List:Str boundaries
    var CBool quoted := false
    var CBool spam := false
    (var Stream s) open filename in+safe+anyeol
    (var MimeStream ms) bind s true
    while (ms header_line (var Str l))
      if (l parse acword:"subject" ":" any:(var Str value))
        ms_decode value
        subject := value
      eif (l parse acword:"from" ":" any:(var Str value))
        ms_decode value
        from := value
      eif (l parse acword:"to" ":" any:(var Str value))
        ms_decode value
        tos += value
      eif (l parse acword:"cc" ":" any:(var Str value))
        ms_decode value
        ccs += value
      eif (l parse acword:"date" ":" any:(var Str value))
        date := value
      eif (l parse acword:"spam" any)
        spam := true
      if detailed
        extras += l
    table columns 1
      cell color (color hsl 60 5 75)
        table columns 2 border 0
          if from<>""
            cell [From:]
            cell
              if (from parse "[dq]" any:(var Str realname) "
                 bold text:realname ; text " <"+remain
              eif (from parse any:(var Str realname) "<" any
                 bold text:realname ; text "<"+remain
              else
                text from
          if (exists tos:first)
            cell [To:]
            cell
              var Pointer:Str to :> tos first
              while exists:to
                text to ; eol
                to :> tos next to
          if (exists ccs:first)
            cell [Cc:]
            cell
              var Pointer:Str cc :> ccs first
              while exists:cc
                text cc ; eol
                cc :> ccs next cc
          if subject<>""
            cell [Subject:]
            cell (bold text:subject)
          if date<>""
            cell [Date:]
            cell text:date
          cell void
          cell
    var Str subject
    var Str from
    var List:Str tos
    var List:Str ccs
    var Str date
    var List:Str extras
    var List:Str boundaries
    var CBool quoted := false
    var CBool spam := false
    (var Stream s) open filename in+safe+anyeol
    (var MimeStream ms) bind s true
    while (ms header_line (var Str l))
      if (l parse acword:"subject" ":" any:(var Str value))
        ms_decode value
        subject := value
      eif (l parse acword:"from" ":" any:(var Str value))
        ms_decode value
        from := value
      eif (l parse acword:"to" ":" any:(var Str value))
        ms_decode value
        tos += value
      eif (l parse acword:"cc" ":" any:(var Str value))
        ms_decode value
        ccs += value
      eif (l parse acword:"date" ":" any:(var Str value))
        date := value
      eif (l parse acword:"spam" any)
        spam := true
      if detailed
        extras += l
    table columns 1
      cell color (color hsl 60 5 75)
        table columns 2 border 0
          if from<>""
            cell [From:]
            cell
              if (from parse "[dq]" any:(var Str realname) "
                 bold text:realname ; text " <"+remain
              eif (from parse any:(var Str realname) "<" any
                 bold text:realname ; text "<"+remain
              else
                text from
          if (exists tos:first)
            cell [To:]
            cell
              var Pointer:Str to :> tos first
              while exists:to
                text to ; eol
                to :> tos next to
          if (exists ccs:first)
            cell [Cc:]
            cell
              var Pointer:Str cc :> ccs first
              while exists:cc
                text cc ; eol
                cc :> ccs next cc
          if subject<>""
            cell [Subject:]
            cell (bold text:subject)
          if date<>""
            cell [Date:]
            cell text:date
          cell void
          cell
            if options<>"detailed"
            if http_options<>"detailed"
              small (link "detailed header" "" options "deta
              small (link "detailed header" "" options "deta
            if options<>"raw"
              fixed [ ] ; small (link "raw text" "" options 
            if http_options<>"text"
              fixed [ ] ; small (link "raw text" "" options "text" no_extension)
            if (exists boundaries:first)
              fixed [ ] ; small [(this is a multipart messag
            fixed [ ]
            small
              if spam
                note "not a spam"
                  set_spam_mark filename false
                  reload_page
              else
                note "a spam"
                  set_spam_mark filename true
                  reload_page
            fixed [ ]
            small
              page note "spam rating"
                spam_load_dictionary (box smart_path "")+"sp
                var Float rating := spam_filter filename fil
                text "Spam probability for this mail is aval
                text "Your current unknown threshold is "+(s
                text "and your current spam threshold is "+(
                text "so this one would be "+(shunt rating>s
                para
                  [Detailed spam filter report:] ; eol
                  fixed text:report
      cell
        if detailed
          small
            var Pointer:Str extra :> extras first
            while exists:extra
              text extra ; eol
              extra :> extras next extra
        if (buttons search "R" -1)<>(-1)
          button "reply" noeol
            mail_reply user keyof:box filename false
            goto_url (repeat back_level "../")+"send" no_ext
          button "reply to all" noeol
            mail_reply user keyof:box filename true
            goto_url (repeat back_level "../")+"send" no_ext
        if (buttons search "D" -1)<>(-1)
          button "delete" noeol
            file_delete filename
            file_hook filename
            goto_backward
        if (buttons search "B" -1)<>(-1)
          var Str mailbox := stripped_name from
          var (Data Set:UserBookmark) bookmark :> user_datab
          var CBool already := false
          each b2 bookmark
            if b2:mailbox=mailbox
              already := true
          if not already 
            page button "Add to bookmarks" noeol
              bookmark create mailbox
              var Data:UserBookmark b :> bookmark mailbox
              b name := smart_name from
              b mailbox := mailbox
              title "New bookmark"
              table columns 2
                cell [Name: ]
                cell (input "" b:name length 40)
                cell [Abstract: ]
                cell (text_input "" b:abstract columns 60 ro
                cell [Mailbox: ]
                cell (input "" b:mailbox length 40)
                cell [Home page / URL: ]
                cell (input "" b:url length 40)
                cell [Contact: ]
                cell (text_input "" b:contact columns 60 row
                cell [Keywords: ]
                cell (input "" b:keywords length 60)
              button "Record" noeol
                goto_backward
              button "Cancel bookmark creation"
                bookmark delete mailbox
                goto_backward
        if (buttons search "M" -1)<>(-1)
          var Array:FileInfo areas := file_list box:area_pat
          if areas:size<>0     
            fixed [  ]
            select "Area: " (var Str area) noeol
              for (var Int i) 0 areas:size-1
                var Str area := areas:i:name
                area := area 0 (area search "/" area:len)
            if (exists boundaries:first)
              fixed [ ] ; small [(this is a multipart messag
            fixed [ ]
            small
              if spam
                note "not a spam"
                  set_spam_mark filename false
                  reload_page
              else
                note "a spam"
                  set_spam_mark filename true
                  reload_page
            fixed [ ]
            small
              page note "spam rating"
                spam_load_dictionary (box smart_path "")+"sp
                var Float rating := spam_filter filename fil
                text "Spam probability for this mail is aval
                text "Your current unknown threshold is "+(s
                text "and your current spam threshold is "+(
                text "so this one would be "+(shunt rating>s
                para
                  [Detailed spam filter report:] ; eol
                  fixed text:report
      cell
        if detailed
          small
            var Pointer:Str extra :> extras first
            while exists:extra
              text extra ; eol
              extra :> extras next extra
        if (buttons search "R" -1)<>(-1)
          button "reply" noeol
            mail_reply user keyof:box filename false
            goto_url (repeat back_level "../")+"send" no_ext
          button "reply to all" noeol
            mail_reply user keyof:box filename true
            goto_url (repeat back_level "../")+"send" no_ext
        if (buttons search "D" -1)<>(-1)
          button "delete" noeol
            file_delete filename
            file_hook filename
            goto_backward
        if (buttons search "B" -1)<>(-1)
          var Str mailbox := stripped_name from
          var (Data Set:UserBookmark) bookmark :> user_datab
          var CBool already := false
          each b2 bookmark
            if b2:mailbox=mailbox
              already := true
          if not already 
            page button "Add to bookmarks" noeol
              bookmark create mailbox
              var Data:UserBookmark b :> bookmark mailbox
              b name := smart_name from
              b mailbox := mailbox
              title "New bookmark"
              table columns 2
                cell [Name: ]
                cell (input "" b:name length 40)
                cell [Abstract: ]
                cell (text_input "" b:abstract columns 60 ro
                cell [Mailbox: ]
                cell (input "" b:mailbox length 40)
                cell [Home page / URL: ]
                cell (input "" b:url length 40)
                cell [Contact: ]
                cell (text_input "" b:contact columns 60 row
                cell [Keywords: ]
                cell (input "" b:keywords length 60)
              button "Record" noeol
                goto_backward
              button "Cancel bookmark creation"
                bookmark delete mailbox
                goto_backward
        if (buttons search "M" -1)<>(-1)
          var Array:FileInfo areas := file_list box:area_pat
          if areas:size<>0     
            fixed [  ]
            select "Area: " (var Str area) noeol
              for (var Int i) 0 areas:size-1
                var Str area := areas:i:name
                area := area 0 (area search "/" area:len)
                option http_decode:area area
                option area area
            button "move to area" noeol
              var Str base := filename (filename search_last
              file_move filename box:area_path+area+"/"+base
              goto_backward
            button "move to area" noeol
              var Str base := filename (filename search_last
              file_move filename box:area_path+area+"/"+base
              goto_backward
    if options="raw" or spam
    if http_options="text" or spam
      fixed
        (var Stream s) open filename in+safe
        while not s:atend
          s read_available (var Address adr) (var Int size) 
          (var Str chars) set adr size false
          text chars
    eif ms:html
      while (ms body_line l)
        html l
    eif  ms:multipart
      while (ms body_line l)
        void
      while not s:atend
        var List:Str extras := var List:Str empty_list
        ms bind s false
        while (ms header_line l)
          if detailed
            extras += l
        if ms:name<>""
          if ms:mime<>"application/applefile"
            table columns (shunt detailed 3 2)
              cell
                if (ms:name (ms:name search_last "." ms:name
      fixed
        (var Stream s) open filename in+safe
        while not s:atend
          s read_available (var Address adr) (var Int size) 
          (var Str chars) set adr size false
          text chars
    eif ms:html
      while (ms body_line l)
        html l
    eif  ms:multipart
      while (ms body_line l)
        void
      while not s:atend
        var List:Str extras := var List:Str empty_list
        ms bind s false
        while (ms header_line l)
          if detailed
            extras += l
        if ms:name<>""
          if ms:mime<>"application/applefile"
            table columns (shunt detailed 3 2)
              cell
                if (ms:name (ms:name search_last "." ms:name
                  link ms:name (http_encode ms:name) options
                  link ms:name ms:name options "html" no_extension
                else
                else
                  link ms:name (http_encode ms:name) no_exte
                  link ms:name ms:name no_extension
              cell
              cell
                small (link "view" (http_encode ms:name) opt
                fixed [ ] ; small (link "download" (http_enc
                small (link "view" ms:name options "text" no_extension)
                fixed [ ] ; small (link "download" ms:name options "binary" no_extension)
              if detailed
                cell
                  small
                    var Pointer:Str extra :> extras first
                    while exists:extra
                      text extra ; eol
                      extra :> extras next extra
            while (ms body_line l)
              void
          else
            while (ms body_line l)
              void
        eif ms:mime="text/html"
          table columns 2 border 0
            cell color (color hsl 0 0 90)
              var CBool body := false ; var CBool nobody := 
              while (ms body_line l)
                if (l parse "<" word:"BODY" any ">" any:(var
                  l := remain ; body := true
                if (reverse:l parse (pattern reverse:"</HTML
                  l := reverse remain
                if (reverse:l parse (pattern reverse:"</BODY
                  l := reverse remain ; nobody := true
                if body
                  html l
                if nobody
                  body := false ; nobody := false
            cell color (color hsl 0 0 90)
              small (link "view" "" options "html" no_extens
        else
          fixed
            while (ms body_line l)
              text l
    else
      fixed
        while (ms body_line l)
          text l



method page mail_create_area user
  arg_rw HtmlPage page ; arg Str user
  implicit page
    title "Create a new mail area"
    select "In which mailbox: " (var Str box)
      each umb user:user:mailbox
        option umb umb
    input "New area name: " (var Str name)
    button "Create it"
      var Data:MailBox b :> mailbox box
      if exists:b
              if detailed
                cell
                  small
                    var Pointer:Str extra :> extras first
                    while exists:extra
                      text extra ; eol
                      extra :> extras next extra
            while (ms body_line l)
              void
          else
            while (ms body_line l)
              void
        eif ms:mime="text/html"
          table columns 2 border 0
            cell color (color hsl 0 0 90)
              var CBool body := false ; var CBool nobody := 
              while (ms body_line l)
                if (l parse "<" word:"BODY" any ">" any:(var
                  l := remain ; body := true
                if (reverse:l parse (pattern reverse:"</HTML
                  l := reverse remain
                if (reverse:l parse (pattern reverse:"</BODY
                  l := reverse remain ; nobody := true
                if body
                  html l
                if nobody
                  body := false ; nobody := false
            cell color (color hsl 0 0 90)
              small (link "view" "" options "html" no_extens
        else
          fixed
            while (ms body_line l)
              text l
    else
      fixed
        while (ms body_line l)
          text l



method page mail_create_area user
  arg_rw HtmlPage page ; arg Str user
  implicit page
    title "Create a new mail area"
    select "In which mailbox: " (var Str box)
      each umb user:user:mailbox
        option umb umb
    input "New area name: " (var Str name)
    button "Create it"
      var Data:MailBox b :> mailbox box
      if exists:b
        file_tree_create b:area_path+http_encode:name+"/"
        file_tree_create b:area_path+name+"/"
      goto_backward

method page mail_delete_area user
  arg_rw HtmlPage page ; arg Str user
  implicit page
    title "Delete a new mail area"
    select "Area: " (var Str what)
      option "" ""
      each umb user:user:mailbox
        var Array:FileInfo areas := file_list mailbox:umb:ar
        for (var Int i) 0 areas:size-1
          if (file_list mailbox:umb:area_path+areas:i:name s
            var Str name := areas:i:name
            name := name 0 (name search_last "/" name:len)
      goto_backward

method page mail_delete_area user
  arg_rw HtmlPage page ; arg Str user
  implicit page
    title "Delete a new mail area"
    select "Area: " (var Str what)
      option "" ""
      each umb user:user:mailbox
        var Array:FileInfo areas := file_list mailbox:umb:ar
        for (var Int i) 0 areas:size-1
          if (file_list mailbox:umb:area_path+areas:i:name s
            var Str name := areas:i:name
            name := name 0 (name search_last "/" name:len)
            option http_decode:name+" in "+umb+" mailbox" st
            option name+" in "+umb+" mailbox" string:umb+" "+(string areas:i:name)
    button "Delete it"
      if (what parse (var Str mailbox) (var Str area))
        each umb user:user:mailbox
          if umb=mailbox
            file_delete mailbox:umb:area_path+area+"/"
      goto_backward
    para
      [You can delete an area only if it is empty.]

method page set_spam_filter user
  arg_rw HtmlPage page ; arg Str user
  implicit page
    title "Set the spam filter"
    var Str box := "all"
    select "Set spam filter for " box
      each umb user:user:mailbox
        option "mailbox "+umb umb
      option "all mailboxes" "all"
    var Int days := 120
    input "studying " days length 3 noeol ; [ days mail arch
    var Float unknown_threshold100 := 50
    input "using an unknown threshold of " unknown_threshold
    var Float spam_threshold100 := 90
    input "and a spam threshold of " spam_threshold100 lengt
    var Int vdays := 120
    input "then test the filter against " vdays length 3 noe
    page button "set spam filter" noeol
      var Array:Str mailboxes paths
      each umb1 user:user:mailbox
        var Data:MailBox m1 :> mailbox umb1
        if exists:m1 and (keyof:m1=box or box="all")
          mailboxes += keyof m1 ; paths += m1 archive_path
      var Str temp := file_temporary
      var DateTime since := datetime ; since seconds -= days
      spam_study paths since unknown_threshold100/100 spam_t
      for (var Int i) 0 mailboxes:size-1
        var Data:MailBox m1 :> mailbox mailboxes:i
        file_copy temp (m1 smart_path "")+"spam_filter.txt"
        file_delete (m1 smart_path "")+"spam_ip.txt" # old o
        file_delete (m1 smart_path "")+"spam_word.txt"
      spam_load_dictionary temp (var (Dictionary Str Float) 
      file_delete temp
      var DateTime since := datetime ; since seconds -= vday
      var Int count := 0
      for (var Int p) 0 paths:size-1
        var Array:FileInfo files := file_list paths:p standa
        for (var Int i) 0 files:size-1
          if files:i:datetime>=since
            count += 1
      var Int spam_rejected := 0 ; var Int spam_unknown := 0
      var Int valid_rejected := 0 ; var Int valid_unknown :=
      table columns 5
        cell header [Date]
        cell header [From]
        cell header [To]
        cell header [Subject]
        cell header [Rating]
        var Int current := 0
        for (var Int p) 0 paths:size-1
          var Array:FileInfo files := file_list paths:p stan
          for (var Int i) 0 files:size-1
            if files:i:datetime>=since
              current += 1
              part test "test mail filter "+string:current+"
                (var Stream s) open paths:p+files:i:name in+
                var CBool spam := s:readline parse acword:"s
                s close
                var Float rating := spam_filter paths:p+file
                var Int level := shunt rating>spam_threshold
                if spam
                  if level>0
                    spam_rejected += 1
                  eif level=0
                    spam_unknown += 1
                  else
                    spam_accepted += 1
                else
                  if level>0
                    valid_rejected += 1
                  eif level=0
                    valid_unknown += 1
                  else
                    valid_accepted += 1
                if (spam and level<0) or (not spam and level
                  var Str from2 := "" ; var Str to2 := "" ; 
                  (var Stream s) open paths:p+files:i:name i
                  (var MimeStream ms) bind s true
                  while (ms header_line (var Str l))
                    if (l parse acword:"from" ":" any:(var S
                      ms_decode value
                      from2 := value
                    eif (l parse acword:"to" ":" any:(var St
                      ms_decode value
                      to2 += (shunt to2<>"" "," "")+value
                    eif (l parse acword:"subject" ":" any:(v
                      ms_decode value
                      subject2 := value
                  cell
                    text (string files:i:datetime:date)
                  cell
                    text smart_name:from2
                  cell
                    small
                      while to2<>""
                        if not (to2 parse any:(var Str value
                          value := to2 ; remain := ""
                        text smart_name:value ; eol
                        to2 := remain
                  cell color (color hsl (shunt level>0 and n
                    if (mailboxes:p parse any:(var Str mailb
    button "Delete it"
      if (what parse (var Str mailbox) (var Str area))
        each umb user:user:mailbox
          if umb=mailbox
            file_delete mailbox:umb:area_path+area+"/"
      goto_backward
    para
      [You can delete an area only if it is empty.]

method page set_spam_filter user
  arg_rw HtmlPage page ; arg Str user
  implicit page
    title "Set the spam filter"
    var Str box := "all"
    select "Set spam filter for " box
      each umb user:user:mailbox
        option "mailbox "+umb umb
      option "all mailboxes" "all"
    var Int days := 120
    input "studying " days length 3 noeol ; [ days mail arch
    var Float unknown_threshold100 := 50
    input "using an unknown threshold of " unknown_threshold
    var Float spam_threshold100 := 90
    input "and a spam threshold of " spam_threshold100 lengt
    var Int vdays := 120
    input "then test the filter against " vdays length 3 noe
    page button "set spam filter" noeol
      var Array:Str mailboxes paths
      each umb1 user:user:mailbox
        var Data:MailBox m1 :> mailbox umb1
        if exists:m1 and (keyof:m1=box or box="all")
          mailboxes += keyof m1 ; paths += m1 archive_path
      var Str temp := file_temporary
      var DateTime since := datetime ; since seconds -= days
      spam_study paths since unknown_threshold100/100 spam_t
      for (var Int i) 0 mailboxes:size-1
        var Data:MailBox m1 :> mailbox mailboxes:i
        file_copy temp (m1 smart_path "")+"spam_filter.txt"
        file_delete (m1 smart_path "")+"spam_ip.txt" # old o
        file_delete (m1 smart_path "")+"spam_word.txt"
      spam_load_dictionary temp (var (Dictionary Str Float) 
      file_delete temp
      var DateTime since := datetime ; since seconds -= vday
      var Int count := 0
      for (var Int p) 0 paths:size-1
        var Array:FileInfo files := file_list paths:p standa
        for (var Int i) 0 files:size-1
          if files:i:datetime>=since
            count += 1
      var Int spam_rejected := 0 ; var Int spam_unknown := 0
      var Int valid_rejected := 0 ; var Int valid_unknown :=
      table columns 5
        cell header [Date]
        cell header [From]
        cell header [To]
        cell header [Subject]
        cell header [Rating]
        var Int current := 0
        for (var Int p) 0 paths:size-1
          var Array:FileInfo files := file_list paths:p stan
          for (var Int i) 0 files:size-1
            if files:i:datetime>=since
              current += 1
              part test "test mail filter "+string:current+"
                (var Stream s) open paths:p+files:i:name in+
                var CBool spam := s:readline parse acword:"s
                s close
                var Float rating := spam_filter paths:p+file
                var Int level := shunt rating>spam_threshold
                if spam
                  if level>0
                    spam_rejected += 1
                  eif level=0
                    spam_unknown += 1
                  else
                    spam_accepted += 1
                else
                  if level>0
                    valid_rejected += 1
                  eif level=0
                    valid_unknown += 1
                  else
                    valid_accepted += 1
                if (spam and level<0) or (not spam and level
                  var Str from2 := "" ; var Str to2 := "" ; 
                  (var Stream s) open paths:p+files:i:name i
                  (var MimeStream ms) bind s true
                  while (ms header_line (var Str l))
                    if (l parse acword:"from" ":" any:(var S
                      ms_decode value
                      from2 := value
                    eif (l parse acword:"to" ":" any:(var St
                      ms_decode value
                      to2 += (shunt to2<>"" "," "")+value
                    eif (l parse acword:"subject" ":" any:(v
                      ms_decode value
                      subject2 := value
                  cell
                    text (string files:i:datetime:date)
                  cell
                    text smart_name:from2
                  cell
                    small
                      while to2<>""
                        if not (to2 parse any:(var Str value
                          value := to2 ; remain := ""
                        text smart_name:value ; eol
                        to2 := remain
                  cell color (color hsl (shunt level>0 and n
                    if (mailboxes:p parse any:(var Str mailb
                      link (shunt subject2<>"" subject2 "no 
                      link (shunt subject2<>"" subject2 "no subject") "archive/"+domain+"/"+mailbox+"/"+(replace files:i:name ".mail" "")+"/" options "text" no_extension
                    else
                      text (shunt subject2<>"" subject2 "no 
                  cell
                    text (string 100*rating "fixed 0")+"%"
      var Int total := spam_rejected+spam_unknown+spam_accep
      para
        text "Rejected spams: "
        font color (color hsl 120 100 50)
          text (string 100.0*spam_rejected/total "fixed 0")+
        text " ("+string:spam_rejected+")" ; eol
        text "Unknown spams: "
        font color (color hsl 240 100 50)
          text (string 100.0*spam_unknown/total "fixed 0")+"
        text " ("+string:spam_unknown+")" ; eol
        text "Accepted spams: "
        font color (color hsl 60 100 50)
          text (string 100.0*spam_accepted/total "fixed 0")+
        text" ("+string:spam_accepted+")" ; eol
      para
        text "Rejected valid mails: "
        font color (color hsl 0 100 50)
          text (string 100.0*valid_rejected/total "fixed 0")
        text " ("+string:valid_rejected+")" ; eol
        text "Unknown valid mails: "
        font color (color hsl 240 100 50)
          text (string 100.0*valid_unknown/total "fixed 0")+
        text " ("+string:valid_unknown+")" ; eol
        text "Accepted valid mails: "
        font color (color hsl 120 100 50)
          text (string 100.0*valid_accepted/total "fixed 0")
        text " ("+string:valid_accepted+")" ; eol
    page button "remove spam filter"
      var Array:Str mailboxes paths
      each umb2 user:user:mailbox
        var Data:MailBox m2 :> mailbox umb2
        if exists:m2 and (keyof:m2=box or box="all")
          file_delete (m2 smart_path "")+"spam_filter.txt"
          file_delete (m2 smart_path "")+"spam_ip.txt"
          file_delete (m2 smart_path "")+"spam_word.txt"
      goto_backward
    para
      [A threshold of 50% will probably reject all spams, bu
      [A threshold of 99% will reject very fiew valid mails.
      [The optimal value depends on the kind of mails you re



                    else
                      text (shunt subject2<>"" subject2 "no 
                  cell
                    text (string 100*rating "fixed 0")+"%"
      var Int total := spam_rejected+spam_unknown+spam_accep
      para
        text "Rejected spams: "
        font color (color hsl 120 100 50)
          text (string 100.0*spam_rejected/total "fixed 0")+
        text " ("+string:spam_rejected+")" ; eol
        text "Unknown spams: "
        font color (color hsl 240 100 50)
          text (string 100.0*spam_unknown/total "fixed 0")+"
        text " ("+string:spam_unknown+")" ; eol
        text "Accepted spams: "
        font color (color hsl 60 100 50)
          text (string 100.0*spam_accepted/total "fixed 0")+
        text" ("+string:spam_accepted+")" ; eol
      para
        text "Rejected valid mails: "
        font color (color hsl 0 100 50)
          text (string 100.0*valid_rejected/total "fixed 0")
        text " ("+string:valid_rejected+")" ; eol
        text "Unknown valid mails: "
        font color (color hsl 240 100 50)
          text (string 100.0*valid_unknown/total "fixed 0")+
        text " ("+string:valid_unknown+")" ; eol
        text "Accepted valid mails: "
        font color (color hsl 120 100 50)
          text (string 100.0*valid_accepted/total "fixed 0")
        text " ("+string:valid_accepted+")" ; eol
    page button "remove spam filter"
      var Array:Str mailboxes paths
      each umb2 user:user:mailbox
        var Data:MailBox m2 :> mailbox umb2
        if exists:m2 and (keyof:m2=box or box="all")
          file_delete (m2 smart_path "")+"spam_filter.txt"
          file_delete (m2 smart_path "")+"spam_ip.txt"
          file_delete (m2 smart_path "")+"spam_word.txt"
      goto_backward
    para
      [A threshold of 50% will probably reject all spams, bu
      [A threshold of 99% will reject very fiew valid mails.
      [The optimal value depends on the kind of mails you re



method page mail path options
  arg_rw HtmlPage page ; arg Str path options
method page mail path http_options
  arg_rw HtmlPage page ; arg Str path http_options
  implicit page
    requires "mail"
    if path="/"
      mail_list user_name
      para
        link "send a mail" "send" no_extension ; eol
        link "search in the archives" "search" no_extension 
      para
        each umb user:user_name:mailbox
          var Data:MailBox m :> mailbox umb
          if (keyof:m parse any:(var Str box) "@" any:(var S
            var Array:FileInfo areas := file_list m:area_pat
            if areas:size<>0
              [Areas for mailbox] ; fixed (text " "+keyof:m)
            for (var Int i) 0 areas:size-1
              var Str area := areas:i:name
              area := area 0 (area search "/" area:len)
  implicit page
    requires "mail"
    if path="/"
      mail_list user_name
      para
        link "send a mail" "send" no_extension ; eol
        link "search in the archives" "search" no_extension 
      para
        each umb user:user_name:mailbox
          var Data:MailBox m :> mailbox umb
          if (keyof:m parse any:(var Str box) "@" any:(var S
            var Array:FileInfo areas := file_list m:area_pat
            if areas:size<>0
              [Areas for mailbox] ; fixed (text " "+keyof:m)
            for (var Int i) 0 areas:size-1
              var Str area := areas:i:name
              area := area 0 (area search "/" area:len)
              link http_decode:area "area/"+domain+"/"+box+"
              link area "area/"+domain+"/"+box+"/"+area+"/"
              var Int n := (file_list m:area_path+areas:i:na
              if n>0
                fixed [  ] ; small (text string:n+" mail"+(s
              eol
      para
        link "edit your bookmarks" "bookmarks" no_extension 
        link "create a new area" "create_area" no_extension
        fixed [ ] ; link "delete an area" "delete_area" no_e
        link "set auto answer messages" "auto_answer" no_ext
        each umb user:user_name:mailbox
          var Data:MailBox m :> mailbox umb
          if m:auto_answer<>""
            fixed [ ] ; highlight keyof:m
        eol 
        link "set spams filter" "spam_filter" no_extension ;
      spam_list user_name
    eif path="/send"
      mail_edit user_name
    eif path="/preview"
      mail_preview user_name
    eif path="/search"
      mail_search user_name
    eif path="/bookmarks"
      mail_bookmarks user_name
    eif path="/create_area"
      mail_create_area user_name
    eif path="/delete_area"
      mail_delete_area user_name
    eif path="/spam_filter"
      set_spam_filter user_name
    eif path="/auto_answer"
      set_auto_answer_messages user_name
    eif (path parse "/in/" any:(var Str domain) "/" any:(var
      var Data:MailBox b :> mailbox box+"@"+domain
      var Str filename := b:in_path+id+".mail"
              var Int n := (file_list m:area_path+areas:i:na
              if n>0
                fixed [  ] ; small (text string:n+" mail"+(s
              eol
      para
        link "edit your bookmarks" "bookmarks" no_extension 
        link "create a new area" "create_area" no_extension
        fixed [ ] ; link "delete an area" "delete_area" no_e
        link "set auto answer messages" "auto_answer" no_ext
        each umb user:user_name:mailbox
          var Data:MailBox m :> mailbox umb
          if m:auto_answer<>""
            fixed [ ] ; highlight keyof:m
        eol 
        link "set spams filter" "spam_filter" no_extension ;
      spam_list user_name
    eif path="/send"
      mail_edit user_name
    eif path="/preview"
      mail_preview user_name
    eif path="/search"
      mail_search user_name
    eif path="/bookmarks"
      mail_bookmarks user_name
    eif path="/create_area"
      mail_create_area user_name
    eif path="/delete_area"
      mail_delete_area user_name
    eif path="/spam_filter"
      set_spam_filter user_name
    eif path="/auto_answer"
      set_auto_answer_messages user_name
    eif (path parse "/in/" any:(var Str domain) "/" any:(var
      var Data:MailBox b :> mailbox box+"@"+domain
      var Str filename := b:in_path+id+".mail"
      if part<>"" or options="html"
        send_mime_part filename http_decode:part options fal
      if part<>"" or http_options="html"
        send_mime_part filename part http_options false
      else
      else
        mail_display user_name b filename "RBMD" 4 options
        mail_display user_name b filename "RBMD" 4 http_options
    eif (path parse "/unknown/" any:(var Str domain) "/" any
      var Data:MailBox b :> mailbox box+"@"+domain
      var Str filename := b:unknown_path+id+".mail"
    eif (path parse "/unknown/" any:(var Str domain) "/" any
      var Data:MailBox b :> mailbox box+"@"+domain
      var Str filename := b:unknown_path+id+".mail"
      if part<>"" or options="html"
        send_mime_part filename http_decode:part options fal
      if part<>"" or http_options="html"
        send_mime_part filename part http_options false
      else
      else
        mail_display user_name b filename "RBMD" 4 options
        mail_display user_name b filename "RBMD" 4 http_options
    eif (path parse "/spam/" any:(var Str domain) "/" any:(v
      var Data:MailBox b :> mailbox box+"@"+domain
      var Str filename := b:spam_path+id+".mail"
    eif (path parse "/spam/" any:(var Str domain) "/" any:(v
      var Data:MailBox b :> mailbox box+"@"+domain
      var Str filename := b:spam_path+id+".mail"
      if part<>"" or options="html"
        send_mime_part filename http_decode:part options fal
      if part<>"" or http_options="html"
        send_mime_part filename part http_options false
      else
      else
        mail_display user_name b filename "RBMD" 4 options
        mail_display user_name b filename "RBMD" 4 http_options
    eif (path parse "/area/" any:(var Str domain) "/" any:(v
      var Data:MailBox b :> mailbox box+"@"+domain
      if (remain parse any:(var Str id) "/"  any:(var Str pa
        var Str filename := b:area_path+area+"/"+id+".mail"
    eif (path parse "/area/" any:(var Str domain) "/" any:(v
      var Data:MailBox b :> mailbox box+"@"+domain
      if (remain parse any:(var Str id) "/"  any:(var Str pa
        var Str filename := b:area_path+area+"/"+id+".mail"
        if part<>"" or options="html"
          send_mime_part filename http_decode:part options f
        if part<>"" or http_options="html"
          send_mime_part filename part http_options false
        else
        else
          mail_display user_name b filename "RBMD" 5 options
          mail_display user_name b filename "RBMD" 5 http_options
      else
        title "'"+area+"' area"
        mail_list "mail" (var Data:MailBox no_box) b:area_pa
    eif (path parse "/archive/" any:(var Str domain) "/" any
      var Data:MailBox b :> mailbox box+"@"+domain
      var Str filename := b:archive_path+month+"/"+day+"/"+i
      else
        title "'"+area+"' area"
        mail_list "mail" (var Data:MailBox no_box) b:area_pa
    eif (path parse "/archive/" any:(var Str domain) "/" any
      var Data:MailBox b :> mailbox box+"@"+domain
      var Str filename := b:archive_path+month+"/"+day+"/"+i
      if part<>"" or options="html"
        send_mime_part filename http_decode:part options fal
      if part<>"" or http_options="html"
        send_mime_part filename part http_options false
      else
      else
        mail_display user_name b filename "RB" 6 options
        mail_display user_name b filename "RB" 6 http_options