Patch title: Release 85 bulk changes
Abstract:
File: /pliant/protocol/http/login.page
Key:
    Removed line
    Added line
module "/pliant/language/stream.pli"
module "/pliant/util/crypto/intn.pli"
module "/pliant/util/crypto/rsa.pli"
module "/pliant/admin/md5.pli"
module "/pliant/fullpliant/user.pli"

module "/pliant/language/context.pli"
module "/pliant/fullpliant/this_computer.pli"
module "/pliant/fullpliant/login.pli"


method page detailed_history user day_count
  arg_rw HtmlPage page ; arg Str user ; arg Int day_count
  var DateTime now := datetime
  (var Stream s) open "data:/pliant/login/"+user in+safe
  while not s:atend
    var Str l := s readline
    if (l parse (var DateTime from) (var DateTime to) _ any:(var Str ip) _ any:(var Str comment))
      var Int old := now:date:days-from:date:days
      if old<day_count
        s unreadline l
        var Date day := from date
        if day_count=1
          [Today detailed history:]
        else
          fixed (text string:day)
          text " detailed history ("+string:old+" day"+(shunt old>1 "s" "")+" ago):"
        table columns 4
          cell header [From]
          cell header [To]
          cell header [IP address]
          cell header [comment]
          part scan_day
            while not s:atend
              var Str l := s readline
              if (l parse (var DateTime from) (var DateTime to) _ any:(var Str ip) _ any:(var Str comment))
                if from:date=day
                  cell text:((string from) 11 5)
                  cell text:((string to) 11 5)
                  cell (text ip)
                  cell (text comment)
                else
                  s unreadline l
                  leave scan_day
          var Data:User2 u :> user_database2:data:user user
          if u:from:date=day
            cell text:((string u:from) 11 5)
            cell text:((string u:to) 11 5)
            cell (text u:ip)
            cell (text u:comment)

if user_name=""
  button "Log in" noeol
    if user_name=""
      reset_http_answer
      http_request:send_authentification_request
    else
      reload_page
  if allowed:"create_account"
    button "Create an account for me"
      title "Create an account on this server"
      input "User ID: " (var Str id)
      input "Your real first name: " (var Str first_name) noeol
      input " and name: " (var Str name)
      [How you would describe yourself:] ; eol
      text_input "" (var Str abstract) columns 60 rows 10
      input "Your email: " (var Str email)
      input "Clear password: " (var Str password) password
      input "Public key: " (var Str key) length 60
      button "Create it now"
        title "Account creation report"
        if id=""
          [You must provide a user ID.]
        eif name=""
          [You must provide a real name, and you are praised to provide the right one.]
        eif (exists user:id)
          fixed text:id ; [ already exists on this server.]
        eif key<>"" and rsa_nbbits:key<256
          [Your public key is too short.]
        eif key<>"" and rsa_nbbits:key>1024
          [Your public key is too long.]
        else
          user create id
          user:id first_name := first_name
          user:id name := name
          user:id abstract := abstract
          user:id email := email
          if password<>""
            user_secret_database:data:user create id
            user_secret_database:data:user:id password_md5 := string_md5_hexa_signature password
          if key<>""
            user:id public_key := key
          [Welcome ] ; text name ; [.]
      para
        italic [NB: ] ; [If you don't want your email address to be published on this site, you can leave it blank.]
else
  button "Manage account"
  button "Manage your account"
    title "Manage '"+user_name+"' account"
    button "Change password"
      title "Change '"+user_name+"' password"
      input "Enter old password: " (var Str old) password
      input "Enter new password: " (var Str new) password
      input "Enter new password once again: " (var Str new2) password
      button "Change the password now"
        if user_secret_database:data:user:user_name:password_md5<>string_md5_hexa_signature:old
          text "Old password is incorrect !"
        eif new2<>new
          text "The new password is not correct !"
        else
          var Str md5 := string_md5_hexa_signature new
          user_secret_database:data:user:user_name password_md5 := md5
          var CBool ok := true
          each c this_computer:env:"pliant":"password"
            if (keyof:c parse "client" any) and c<>computer_fullname
              if (user_change_password user_name md5 c)=failure
                text "Failed to change password on server "+c ; eol
                ok := false
          if ok
            goto_backward 2
    button "Generate passwords list"
      each p user_secret_database:data:user:user_name:password_list
        user_secret_database:data:user:user_name:password_list delete keyof:p
      [Here is your new passwords list:] ; eol
      for (var Int l) 1 50
        var Intn r := random 34n^8
        var Str pass := ""
        for (var Int i) 1 8
          pass += "0123456789abcdefghijkmnpqrstuvwxyz" (cast r%34 Int)
          r \= 34
        var Str id := generate_id
        user_secret_database:data:user:user_name:password_list create id
        user_secret_database:data:user:user_name:password_list id := string_md5_hexa_signature pass
        fixed text:pass ; eol
      button "Ok I've printed it"
        goto_backward 2
      para
        [Passwords contain no 'o' and no 'l' letters, so if you wonder if something is an 'o' letter or a zero, then it is a zero, and if you wonder if something is an 'l' or a one, then it is a one.]
    var Int count := user_secret_database:data:user:user_name:password_list:size
    if count>0
      text "You still have "+string:count+" password"+(shunt count>1 "s" "")+" in your list." ; eol
      button "Burn current password"
        part burn_one
          each p user_secret_database:data:user:user_name:password_list
            user_secret_database:data:user:user_name:password_md5 := p
            user_secret_database:data:user:user_name:password_list delete keyof:p
            leave burn_one
        var Str md5 := user_secret_database:data:user:user_name password_md5
        var CBool ok := true
        each c this_computer:env:"pliant":"password"
          if (keyof:c parse "client" any) and c<>computer_fullname
            if (user_change_password user_name md5 c)=failure
              text "Failed to change password on server "+c ; eol
              ok := false
        if ok
          goto_backward
    para
      var DateTime now := datetime
      text "Seven days history summary:" ; eol
      table columns 4
        cell header [Day]
        cell header [First access]
        cell header [Last access]
        cell header [IP addresses]
        var DateTime ts := now
        (var Stream s) open "data:/pliant/login/"+user_name in+safe
        for (var Int i) 0 6
          var DateTime first_from := undefined ; var DateTime last_to := undefined
          var Str ips := ""
          part day_scan
            while not s:atend
              var Str l := s readline
              if (l parse (var DateTime from) (var DateTime to) _ any:(var Str ip) _ any:(var Str comment))
                if from:date=ts:date
                  if first_from=undefined
                    first_from := from
                  last_to := to
                  if (" "+ips+" " search " "+ip+" " -1)=(-1)
                    ips += (shunt ips<>"" " " "")+ip
                eif from:date>ts:date
                  s unreadline l
                  leave day_scan
          var Data:User2 u :> user_database2:data:user user_name
          if u:from:date=ts:date
            if first_from=undefined
              first_from := u from
            last_to := u to
            if (" "+ips+" " search " "+u:ip+" " -1)=(-1)
              ips += (shunt ips<>"" " " "")+u:ip
          if first_from=defined
            cell text:(string first_from:date)
            cell text:((string first_from) 11 5)
            cell text:((string last_to) 11 5)
            cell text:ips
          ts seconds -= 86400
      detailed_history user_name 1
    para
      var Int dc := 7 ; input "Display " dc length 2 noeol
      [ days ]
      button "detailed history"
        title (string dc)+" days history for '"+user_name+"' account"
        detailed_history user_name dc