Patch title: Release 85 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/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/qp.pli"
module "/pliant/util/encoding/date.pli"
module "/pliant/util/encoding/date.pli"
module "/pliant/util/encoding/neutral.pli"
module "/pliant/util/encoding/http.pli"
module "/pliant/util/crypto/random.pli"
module "/pliant/language/schedule/resourcesem.pli"
module "/pliant/util/crypto/random.pli"
module "/pliant/language/schedule/resourcesem.pli"
module "/pliant/protocol/smtp/mime.pli"




type MimeStream
  field Pointer:Stream stream
  field Str name mime
  field CBool embedded <- false
  field CBool html <- false
  field Int encoding
  field List:Str boundaries


method ms multipart -> c
  arg MimeStream ms ; arg CBool c
  c := (exists ms:boundaries:first) or ms:embedded


method ms bind s reset
  arg_rw MimeStream ms ; arg_rw Stream s ; arg CBool reset
  ms stream :> s
  ms name := ""
  ms mime := ""
  ms embedded := false
  ms html := false
  ms encoding := 0
  if reset
    ms boundaries := var List:Str empty_list


function ms_decode l
  arg_rw Str l
  if (l eparse any:(var Str head) "=?" any:(var Str charset)
    if lower:enc="q"
      ms_decode tail
      l := head+qp_decode:value+tail
    eif lower:enc="b"
      ms_decode tail
      l := head+base64_decode:value+tail

method ms header_line l -> c
  arg_rw MimeStream ms ; arg_w Str l ; arg CBool c
  l := ms:stream readline
  if l=""
    return false
  while not ms:stream:atend and { var Char ch := ms:stream:s
    l += ms:stream readline
  if (l parse acword:"content-type" ":" any:(var Str value) 
    ms mime := value
  if (l parse acword:"content-type" ":" acword:"message" any
    ms embedded := true
  if (l parse acword:"content-type" ":" acword:"text" "/" wo
    ms html := true
  if (l parse acword:"content-type" ":" acword:"multipart" a
    ms boundaries += value
  eif (l parse acword:"content-type" ":" acword:"multipart" 
    ms boundaries += value
  if (l parse acword:"content-transfer-encoding" ":" any acw
    ms encoding := 1
  eif (l parse acword:"content-transfer-encoding" ":" any ac
    ms encoding := 2
  eif (l parse acword:"content-transfer-encoding" ":" any)
    ms encoding := 3
  # Novell unstandard encoding
  if (l parse acword:"content-disposition" ":" any acword:"f
    ms_decode value
    ms name := value
  if (l parse acword:"content-type" ":" any acword:"name" "=
    ms_decode value # cope with crazy Microsoft encoding
    ms name := value
  c := true


method ms body_line l -> c
  arg_rw MimeStream ms ; arg_w Str l ; arg CBool c
  if ms:stream:atend
    return false
  l := ms:stream readline
  if (l 0 2)="--"
    var Pointer:Str b :> ms:boundaries first
    while exists:b
      if l="--"+b or l="--"+b+"--"
        return false
      b :> ms:boundaries next b
  if ms:encoding=1 # base64
    l := base64_decode l
  eif ms:encoding=2 # quoted printable
    if l:len>0 and (l l:len-1)="="
      l := qp_decode (l 0 l:len-1)
    else
      l := qp_decode:l+"[lf]"
  else
    l += "[lf]"
  if ms:embedded  
    while not ms:stream:atend and { var Char ch := ms:stream
      l += ms:stream readline
    if (l parse acword:"content-type" ":" acword:"multipart"
      ms boundaries += value
    eif (l parse acword:"content-type" ":" acword:"multipart
      ms boundaries += value
    if l=""
      ms embedded := false
  c := true


#-----------------------------------------------------------
#  send



function mail_reply user mailbox filename all
  arg Str user mailbox filename ; arg CBool all
  (var Stream s) open filename in+safe+anyeol
  (var MimeStream ms) bind s true ; var Str from subject ; v
  while (ms header_line (var Str l))
    if (l parse acword:"subject" ":" any:(var Str value))
#-----------------------------------------------------------
#  send



function mail_reply user mailbox filename all
  arg Str user mailbox filename ; arg CBool all
  (var Stream s) open filename in+safe+anyeol
  (var MimeStream ms) bind s true ; var Str from subject ; v
  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))
      from := value
    eif (l parse acword:"to" ":" any:(var Str value))
      while value<>""
        if not (value parse any:(var Str first) "," any:(var
          first := value ; remain := ""
        if first<>mailbox and not (first parse any "<" patte
          to += first
        value := remain
    eif (l parse acword:"cc" ":" any:(var Str value))
      while value<>""
        if not (value parse any:(var Str first) "," any:(var
          first := value ; remain := ""
        if first<>mailbox and not (first parse any "<" patte
          cc += first
        value := remain
  var Str body := smart_name:from+" wrote:[lf]>[lf]"
  if not ms:multipart
    while (ms body_line l)
      body += "> "+l
  else
    while (ms body_line l)
      void
    while not s:atend
      ms bind s false
      while (ms header_line l)
        void
      while (ms body_line l)
        if ms:name="" and ms:mime="text/plain"
          body += "> "+l
  mail_reset user
  mail_database2:data:current create user
  var Data:MailCurrent current :> mail_database2:data:curren
  current from := mailbox
  current:target create ""         
  current:target:"" box := from
  if all   
    var Pointer:Str t :> to first
    while exists:t
      var Str id := generate_id
      current:target create id         
      current:target:id box := t
      t :> to next t
    var Pointer:Str t :> cc first
    while exists:t
      var Str id := generate_id
      current:target create id         
      current:target:id box := t
      current:target:id mode := "cc"
      t :> cc next t
  current subject := shunt (lower:subject parse "re:" any) s
  current body := body



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
      subject := value
    eif (l parse acword:"from" ":" any:(var Str value))
      from := value
    eif (l parse acword:"to" ":" any:(var Str value))
      while value<>""
        if not (value parse any:(var Str first) "," any:(var
          first := value ; remain := ""
        if first<>mailbox and not (first parse any "<" patte
          to += first
        value := remain
    eif (l parse acword:"cc" ":" any:(var Str value))
      while value<>""
        if not (value parse any:(var Str first) "," any:(var
          first := value ; remain := ""
        if first<>mailbox and not (first parse any "<" patte
          cc += first
        value := remain
  var Str body := smart_name:from+" wrote:[lf]>[lf]"
  if not ms:multipart
    while (ms body_line l)
      body += "> "+l
  else
    while (ms body_line l)
      void
    while not s:atend
      ms bind s false
      while (ms header_line l)
        void
      while (ms body_line l)
        if ms:name="" and ms:mime="text/plain"
          body += "> "+l
  mail_reset user
  mail_database2:data:current create user
  var Data:MailCurrent current :> mail_database2:data:curren
  current from := mailbox
  current:target create ""         
  current:target:"" box := from
  if all   
    var Pointer:Str t :> to first
    while exists:t
      var Str id := generate_id
      current:target create id         
      current:target:id box := t
      t :> to next t
    var Pointer:Str t :> cc first
    while exists:t
      var Str id := generate_id
      current:target create id         
      current:target:id box := t
      current:target:id mode := "cc"
      t :> cc next t
  current subject := shunt (lower:subject parse "re:" any) s
  current body := body



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 lsh 80 5 60
      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)
        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 neutral_decode:area area
            option http_decode:area area
      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 
  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
      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 
  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 emil_is_available and ms:encoding=3 and not emil
        if emil_is_available and ms:encoding_model=undefined and not emil
           page send_mime_part filename part filter 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
        page:http_request send_static_file temp "filter_"+(s
        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
  implicit page
           page send_mime_part filename part filter 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
        page:http_request send_static_file temp "filter_"+(s
        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
  implicit page
    if options="raw"
      reset_http_answer
      http_request send_static_file filename "filter_ascii"
      return
    var CBool detailed := 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
    var CBool detailed := 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 lsh 80 5 60
      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
        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
          if options=""
            cell void
            cell
          cell void
          cell
            if options<>"detailed"
              small (link "detailed header" "" options "deta
              small (link "detailed header" "" options "deta
            if options<>"raw"
              fixed [ ] ; small (link "raw text" "" options 
              fixed [ ] ; small (link "raw text" "" options 
              if (exists boundaries:first)
                fixed [ ] ; small [(this is a multipart mess
              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
            if (exists boundaries:first)
              fixed [ ] ; small [(this is a multipart message)]
            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 "")+"spam_filter.txt" (var (Dictionary Str Float) filter) (var Float unknown_threshold) (var Float spam_threshold)
                var Float rating := spam_filter filename filter (var Str report)
                text "Spam probability for this mail is avaluated to "+(string rating*100 "fixed 0")+"%" ; eol
                text "Your current unknown threshold is "+(string unknown_threshold*100 "fixed 0")+"%, "
                text "and your current spam threshold is "+(string spam_threshold*100 "fixed 0")+"%, "
                text "so this one would be "+(shunt rating>spam_threshold "rejected" rating>unknown_threshold "unknown" "accepted")+"."
                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)
      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 neutral_decode:area area
                option http_decode: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 ms:html
    if options="raw" or spam
      fixed
        (var Stream s) open filename in+safe
        while not s:atend
          s read_available (var Address adr) (var Int size) 256
          (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
      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 (neutral_encode ms:name) opti
                  link ms:name (http_encode ms:name) options "html" no_extension
                else
                else
                  link ms:name (neutral_encode ms:name) no_e
                  link ms:name (http_encode ms:name) no_extension
              cell
              cell
                small (link "view" (neutral_encode ms:name) 
                fixed [ ] ; small (link "download" (neutral_
                small (link "view" (http_encode ms:name) options "ascii" no_extension)
                fixed [ ] ; small (link "download" (http_encode 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
              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 lsh 90 0 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
              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 lsh 90 0 0
            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

              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_list box filepath subpath
  arg_rw HtmlPage page ; arg Data:MailBox box ; arg Str file

method page mail_list category box filepath subpath
  arg_rw HtmlPage page ; arg Str category ; arg Data:MailBox box ; arg Str filepath subpath
  implicit page
    var Array:FileInfo files := file_list filepath standard+
    if files:size>0
      if exists:box  
  implicit page
    var Array:FileInfo files := file_list filepath standard+
    if files:size>0
      if exists:box  
        [Mails received in] ; fixed (text " "+keyof:box)
        text upper:(category 0 1)+(category 1 category:len)+"s received in" ; fixed (text " "+keyof:box)
      table columns 3
        cell header [From]
        cell header [Subject]
        cell void
        for (var Int i) 0 files:size-1
          if files:i:extension=".mail"
            var Str filename := filepath+files:i:name
            var Str from := "" ; var Str subject := ""
            (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:"from" ":" any:(var Str fro
                ms_decode from1
                from := from1
              if (l parse acword:"subject" ":" any:(var Str 
                ms_decode subject1
                subject := subject1
            cell
              text smart_name:from
            cell
              link (shunt subject<>"" subject "no subject") 
            cell
              small
                note "delete"
                  file_delete filename
                  file_hook filename
                  reload_page
                fixed [ ]
                if (subpath eparse "in/" any) and (reverse:f
                  note "a spam"
                    var Str spam := reverse:head+"/spam/"+re
                    file_tree_create spam
                    file_move filename spam
                    set_spam_mark spam true
                    file_hook filename
                    file_hook spam
                    reload_page
      table columns 3
        cell header [From]
        cell header [Subject]
        cell void
        for (var Int i) 0 files:size-1
          if files:i:extension=".mail"
            var Str filename := filepath+files:i:name
            var Str from := "" ; var Str subject := ""
            (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:"from" ":" any:(var Str fro
                ms_decode from1
                from := from1
              if (l parse acword:"subject" ":" any:(var Str 
                ms_decode subject1
                subject := subject1
            cell
              text smart_name:from
            cell
              link (shunt subject<>"" subject "no subject") 
            cell
              small
                note "delete"
                  file_delete filename
                  file_hook filename
                  reload_page
                fixed [ ]
                if (subpath eparse "in/" any) and (reverse:f
                  note "a spam"
                    var Str spam := reverse:head+"/spam/"+re
                    file_tree_create spam
                    file_move filename spam
                    set_spam_mark spam true
                    file_hook filename
                    file_hook spam
                    reload_page
                eif (subpath eparse "spam/" any) and (revers
                eif ( (subpath eparse "unknown/" any) and (reverse:filename eparse any:(var Str tail) (pattern reverse:"/unknown/") any:(var Str head)) ) or ( (subpath eparse "spam/" any) and (reverse:filename eparse any:(var Str tail) (pattern reverse:"/spam/") any:(var Str head)) )
                  note "not a spam"
                    var Str normal := reverse:head+"/in/"+re
                    file_tree_create normal
                    file_move filename normal
                    set_spam_mark normal false
                    file_hook filename
                    file_hook normal
                    reload_page

                  note "not a spam"
                    var Str normal := reverse:head+"/in/"+re
                    file_tree_create normal
                    file_move filename normal
                    set_spam_mark normal false
                    file_hook filename
                    file_hook normal
                    reload_page

method page spam_list box filepath subpath
  arg_rw HtmlPage page ; arg Data:MailBox box ; arg Str file
  implicit page
    var Array:FileInfo files := file_list filepath standard+
    if files:size>0
      note (string files:size)+" spam"+(shunt files:size>1 "
        var DateTime timestamp := datetime
        title "Spams received in "+keyof:box
        mail_list box filepath subpath
        button "Delete all at once"
          var Array:FileInfo spams := file_list filepath sta
          for (var Int i) 0 spams:size-1
            if spams:i:datetime<timestamp
              file_delete spams:i:name
          goto_backward
      [ received in] ; fixed (text " "+keyof:box) ; eol


method page mail_list user
  arg_rw HtmlPage page ; arg Str user
  implicit page
    title "'"+user+"' mailboxes"
    each umb user:user:mailbox
      var Data:MailBox m :> mailbox umb
      if exists:m and (keyof:m parse any:(var Str box) "@" a
method page mail_list user
  arg_rw HtmlPage page ; arg Str user
  implicit page
    title "'"+user+"' mailboxes"
    each umb user:user:mailbox
      var Data:MailBox m :> mailbox umb
      if exists:m and (keyof:m parse any:(var Str box) "@" a
        mail_list m m:in_path "in/"+domain+"/"+box+"/"
    para
      each umb user:user:mailbox
        var Data:MailBox m :> mailbox umb
        if exists:m and (keyof:m parse any:(var Str box) "@"
          spam_list m m:spam_path "spam/"+domain+"/"+box+"/"
        mail_list "mail" m m:in_path "in/"+domain+"/"+box+"/"
    each umb user:user:mailbox
      var Data:MailBox m :> mailbox umb
      if exists:m and (keyof:m parse any:(var Str box) "@" a
        var Array:FileInfo files := file_list m:out_path sta
        if files:size>0
          [Mails sent from] ; fixed (text " "+keyof:m)
          table columns 3
            cell header [To]
            cell header [Subject]
            cell void
            for (var Int i) 0 files:size-1
              if files:i:extension=".mail"
                var Str subject := ""
                (var Stream s) open m:out_path+files:i:name 
                (var MimeStream ms) bind s true
                while (ms header_line (var Str l))
                  if (l parse acword:"subject" ":" any:(var 
                    subject := subject1
                var (Link Database:MailMeta) db :> new Datab
                db load m:out_path+files:i:stripped_name+".p
                var Data:MailMeta meta :> db data
                cell
                  each t meta:target
                    if t:status="S"
    each umb user:user:mailbox
      var Data:MailBox m :> mailbox umb
      if exists:m and (keyof:m parse any:(var Str box) "@" a
        var Array:FileInfo files := file_list m:out_path sta
        if files:size>0
          [Mails sent from] ; fixed (text " "+keyof:m)
          table columns 3
            cell header [To]
            cell header [Subject]
            cell void
            for (var Int i) 0 files:size-1
              if files:i:extension=".mail"
                var Str subject := ""
                (var Stream s) open m:out_path+files:i:name 
                (var MimeStream ms) bind s true
                while (ms header_line (var Str l))
                  if (l parse acword:"subject" ":" any:(var 
                    subject := subject1
                var (Link Database:MailMeta) db :> new Datab
                db load m:out_path+files:i:stripped_name+".p
                var Data:MailMeta meta :> db data
                cell
                  each t meta:target
                    if t:status="S"
                      color lsh 0 75 120
                      font color (color hsl 120 0 75)
                        text (smart_name t:box) ; eol
                    eif t:status="R"
                        text (smart_name t:box) ; eol
                    eif t:status="R"
                      color lsh 50 100 0
                      font color (color hsl 0 100 50)
                        text (smart_name t:box) ; eol
                    eif (t:last_error parse word:"sending" a
                        text (smart_name t:box) ; eol
                    eif (t:last_error parse word:"sending" a
                      color lsh 80 80 60
                      font color (color hsl 60 80 80)
                        text (smart_name t:box) ; eol
                    eif t:last_error<>""
                        text (smart_name t:box) ; eol
                    eif t:last_error<>""
                      color lsh 80 80 30
                      font color (color hsl 30 80 80)
                        text (smart_name t:box) ; eol
                    else
                      text (smart_name t:box) ; eol
                cell
                  text subject
                cell
                  var Str name := m:out_path+files:i:strippe
                  note "details"
                    var (Link Database:MailMeta) db2 :> new 
                    db2 load name+".pdb"
                    var Data:MailMeta meta2 :> db2 data
                    table columns 6
                      cell header [Target mailbox]
                      cell header [Status]
                      cell header [Try count]
                      cell header [Last tryed on]
                      cell header [... to server]
                      cell header [... reported error]
                      each t2 meta2:target
                        cell
                          text t2:box
                        if t2:status="S"
                        text (smart_name t:box) ; eol
                    else
                      text (smart_name t:box) ; eol
                cell
                  text subject
                cell
                  var Str name := m:out_path+files:i:strippe
                  note "details"
                    var (Link Database:MailMeta) db2 :> new 
                    db2 load name+".pdb"
                    var Data:MailMeta meta2 :> db2 data
                    table columns 6
                      cell header [Target mailbox]
                      cell header [Status]
                      cell header [Try count]
                      cell header [Last tryed on]
                      cell header [... to server]
                      cell header [... reported error]
                      each t2 meta2:target
                        cell
                          text t2:box
                        if t2:status="S"
                          cell color lsh 80 30 120
                          cell color (color hsl 120 30 80)
                            [Sent]
                        eif t2:status="R"
                            [Sent]
                        eif t2:status="R"
                          cell color lsh 80 30 0
                          cell color (color hsl 0 30 80)
                            [Rejected]
                        eif (t2:last_error parse word:"sendi
                            [Rejected]
                        eif (t2:last_error parse word:"sendi
                          cell color lsh 80 30 60
                          cell color (color hsl 60 30 80)
                            [Currently sending]
                        eif t2:last_error<>""
                            [Currently sending]
                        eif t2:last_error<>""
                          cell color lsh 80 30 30
                          cell color (color hsl 30 30 80)
                            [Temporary rejected]
                        else
                          cell
                            [Not tried yet]
                        cell
                          text (string t2:try_count)
                        cell
                          text (string t2:last_try)
                        cell
                          text t2:last_server
                        cell
                          if (t2:last_error parse word:"send
                            text meter
                          else
                            text t2:last_error
                    button "Try to forward now" noeol
                      forward_mail name+".mail" false "try t
                      goto_backward
                    if allowed:"advanced_mail"
                      button "Forward to any SMTP server of 
                        forward_path name+".mail" "" "indire
                        forward_mail name+".mail" false "try
                        goto_backward
                    if this_computer:env:"pliant":"mail":"fo
                      button "Forward to our ISP" noeol
                        forward_path name+".mail" this_compu
                        forward_mail name+".mail" false "try
                        goto_backward
                    button "Delete"
                      file_delete name+".mail"
                      file_delete name+".pdb"
                      file_hook name+".mail"
                      file_hook name+".pdb"
                      goto_backward
                            
      else
        text "Mailbox "+keyof:m+" is not defined !"
        
                            [Temporary rejected]
                        else
                          cell
                            [Not tried yet]
                        cell
                          text (string t2:try_count)
                        cell
                          text (string t2:last_try)
                        cell
                          text t2:last_server
                        cell
                          if (t2:last_error parse word:"send
                            text meter
                          else
                            text t2:last_error
                    button "Try to forward now" noeol
                      forward_mail name+".mail" false "try t
                      goto_backward
                    if allowed:"advanced_mail"
                      button "Forward to any SMTP server of 
                        forward_path name+".mail" "" "indire
                        forward_mail name+".mail" false "try
                        goto_backward
                    if this_computer:env:"pliant":"mail":"fo
                      button "Forward to our ISP" noeol
                        forward_path name+".mail" this_compu
                        forward_mail name+".mail" false "try
                        goto_backward
                    button "Delete"
                      file_delete name+".mail"
                      file_delete name+".pdb"
                      file_hook name+".mail"
                      file_hook name+".pdb"
                      goto_backward
                            
      else
        text "Mailbox "+keyof:m+" is not defined !"
        
method page spam_list user
  arg_rw HtmlPage page ; arg Str user
  implicit page
    para
      table columns 2 border 0
        cell
          var Int total := 0
          each umb user:user:mailbox
            var Data:MailBox m :> mailbox umb
            if exists:m and (keyof:m parse any:(var Str box) "@" any:(var Str domain))
              var Array:FileInfo unknown := file_list m:unknown_path standard+relative
              var Array:FileInfo spam := file_list m:spam_path standard+relative
              if unknown:size>0 or spam:size>0
                small
                  fixed (text keyof:m+": ")
                  if unknown:size>0
                    text (string unknown:size)+" unknown mail"+(shunt unknown:size>1 "s" "")
                  if unknown:size>0 and spam:size>0
                    [, ]
                  if spam:size>0
                    text (string spam:size)+" spam"+(shunt spam:size>1 "s" "")
                  eol
                total += unknown:size+spam:size
        cell
          if total>0
            page note "spams cleanup"
              var DateTime timestamp := datetime
              title "Spams cleanup"
              for (var Int lap) 0 1
                each umb user:user:mailbox
                  var Data:MailBox m :> mailbox umb
                  if exists:m and (keyof:m parse any:(var Str box) "@" any:(var Str domain))
                    para
                      mail_list (shunt lap=0 "unknown mail" "spam") m (shunt lap=0 m:unknown_path m:spam_path) (shunt lap=0 "unknown" "spam")+"/"+domain+"/"+box+"/"
              page button "Delete all at once"
                for (var Int lap) 0 1
                  each umb user:user:mailbox
                    var Data:MailBox m :> mailbox umb
                    if exists:m and (keyof:m parse any:(var Str box) "@" any:(var Str domain))
                      var Array:FileInfo spams := file_list (shunt lap=0 m:unknown_path m:spam_path) standard
                      for (var Int i) 0 spams:size-1
                        if spams:i:datetime<timestamp
                          file_delete spams:i:name
                goto_backward



#-----------------------------------------------------------
# search



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
#-----------------------------------------------------------
# search



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+neutral_encode:name+"/"
        file_tree_create b:area_path+http_encode: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 neutral_decode:name+" in "+umb+" mailbox"
            option http_decode: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"
    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"
    select "In which mailbox: " (var Str box)
    var Str box := "all"
    select "Set spam filter for " box
      each umb user:user:mailbox
      each umb user:user:mailbox
        option umb umb
    var Int days := 30
    input "Study mail archives on " days length 3 noeol ; [ 
        option "mailbox "+umb umb
      option "all mailboxes" "all"
    var Int days := 120
    input "studying " days length 3 noeol ; [ days mail archives] ; eol
    var Float unknown_threshold100 := 50
    input "using an unknown threshold of " unknown_threshold100 length 4 noeol ; [%] ; eol
    var Float spam_threshold100 := 90
    input "and a spam threshold of " spam_threshold100 length 4 noeol ; [%] ; eol
    var Int vdays := 120
    input "then test the filter against " vdays length 3 noeol ; [days mail archives] ; eol
    page button "set spam filter" noeol
    page button "set spam filter" noeol
      var Data:MailBox mb :> mailbox box
      var DateTime limit := datetime ; limit seconds -= days
      spam_ip_study mb:archive_path limit (mb smart_path "")
      spam_word_study mb:archive_path limit (mb smart_path "
      goto_backward
      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*86400
      spam_study paths since unknown_threshold100/100 spam_threshold100/100 temp
      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 ones
        file_delete (m1 smart_path "")+"spam_word.txt"
      spam_load_dictionary temp (var (Dictionary Str Float) filter) (var Float unknown_threshold) (var Float spam_threshold)
      file_delete temp
      var DateTime since := datetime ; since seconds -= vdays*86400
      var Int count := 0
      for (var Int p) 0 paths:size-1
        var Array:FileInfo files := file_list paths:p standard+recursive+relative
        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 spam_accepted := 0
      var Int valid_rejected := 0 ; var Int valid_unknown := 0 ; var Int valid_accepted := 0
      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 standard+recursive+relative
          for (var Int i) 0 files:size-1
            if files:i:datetime>=since
              current += 1
              part test "test mail filter "+string:current+"/"+string:count
                (var Stream s) open paths:p+files:i:name in+safe
                var CBool spam := s:readline parse acword:"spam" any
                s close
                var Float rating := spam_filter paths:p+files:i:name filter (var Str report)
                var Int level := shunt rating>spam_threshold 1 rating>unknown_threshold 0 -1
                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>0)
                  var Str from2 := "" ; var Str to2 := "" ; var Str subject2 := ""
                  (var Stream s) open paths:p+files:i:name in+safe+anyeol
                  (var MimeStream ms) bind s true
                  while (ms header_line (var Str l))
                    if (l parse acword:"from" ":" any:(var Str value))
                      ms_decode value
                      from2 := value
                    eif (l parse acword:"to" ":" any:(var Str value)) or (l parse acword:"cc" ":" any:(var Str value))
                      ms_decode value
                      to2 += (shunt to2<>"" "," "")+value
                    eif (l parse acword:"subject" ":" any:(var Str value))
                      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) "," any:(var Str remain))
                          value := to2 ; remain := ""
                        text smart_name:value ; eol
                        to2 := remain
                  cell color (color hsl (shunt level>0 and not spam 0 60) 50 75)
                    if (mailboxes:p parse any:(var Str mailbox) "@" any:(var Str domain))
                      link (shunt subject2<>"" subject2 "no subject") "archive/"+domain+"/"+mailbox+"/"+(replace files:i:name ".mail" "")+"/" options "raw" no_extension
                    else
                      text (shunt subject2<>"" subject2 "no subject")
                  cell
                    text (string 100*rating "fixed 0")+"%"
      var Int total := spam_rejected+spam_unknown+spam_accepted+valid_rejected+valid_unknown+valid_accepted
      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"
    page button "remove spam filter"
      var Data:MailBox mb :> mailbox box
      file_delete (mb smart_path "")+"spam_ip.txt"
      file_delete (mb smart_path "")+"spam_word.txt"
      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
      goto_backward
    para
      [A threshold of 50% will probably reject all spams, but is also likely to reject some valid mails.] ; eol
      [A threshold of 99% will reject very fiew valid mails.] ; eol
      [The optimal value depends on the kind of mails you receive and the tradeoff you select between accepting a fiew spams, or rejecting some valid mails.]




method page set_auto_answer_messages user
  arg_rw HtmlPage page ; arg Str user
  implicit page
    title "Set the auto answer messages"
    table columns 2
      cell header [Mailbox] 
      cell header [Auto answer message] 
      each umb user:user:mailbox
        var Data:MailBox m :> mailbox umb
        cell
          text keyof:m
        cell
          text_input "" m:auto_answer columns 80 rows 5
    button "update"
      goto_backward    
      

#-----------------------------------------------------------
# dispatch



method page mail path options
  arg_rw HtmlPage page ; arg Str path 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)
#-----------------------------------------------------------
# dispatch



method page mail path options
  arg_rw HtmlPage page ; arg Str path 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)
              link neutral_decode:area "area/"+domain+"/"+bo
              link http_decode: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
              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 spams filter" "spam_filter" no_extension
        link "set auto answer messages" "auto_answer" no_extension
        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 ; eol
      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="/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"
    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 neutral_decode:part options 
        send_mime_part filename http_decode:part options false
      else
        mail_display user_name b filename "RBMD" 4 options
      else
        mail_display user_name b filename "RBMD" 4 options
    eif (path parse "/unknown/" any:(var Str domain) "/" any:(var Str box) "/" any:(var Str id) "/" any:(var Str part)) and (is_owner user_name box+"@"+domain)
      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 false
      else
        mail_display user_name b filename "RBMD" 4 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"
      if part<>"" or options="html"
    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 neutral_decode:part options 
        send_mime_part filename http_decode:part options false
      else
        mail_display user_name b filename "RBMD" 4 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"
        if part<>"" or options="html"
      else
        mail_display user_name b filename "RBMD" 4 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"
        if part<>"" or options="html"
          send_mime_part filename neutral_decode:part option
          send_mime_part filename http_decode:part options false
        else
          mail_display user_name b filename "RBMD" 5 options
      else
        title "'"+area+"' area"
        else
          mail_display user_name b filename "RBMD" 5 options
      else
        title "'"+area+"' area"
        mail_list (var Data:MailBox no_box) b:area_path+area
        mail_list "mail" (var Data:MailBox no_box) b:area_path+area+"/" ""
    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"
    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 neutral_decode:part options 
        send_mime_part filename http_decode:part options false
      else
        mail_display user_name b filename "RB" 6 options



      else
        mail_display user_name b filename "RB" 6 options