##
## cookie [set|get] and supporting functions
##
## $Id: cookie.tcl 1337564 2012-05-12 15:20:22Z mxmanghi $
##


namespace eval ::rivet {

## clock_to_rfc850_gmt seconds -- Convert an integer-seconds-since-1970 
## click value to RFC850 format, with the additional requirement that it 
## be GMT only.
##
    proc clock_to_rfc850_gmt {seconds} {
        return [clock format $seconds -format "%a, %d-%b-%y %T GMT" -gmt 1]
    }

## make_cookie_attributes paramsArray -- Build up cookie parameters.
##
## If an expires element appears in the array, it's appended to the
## result as "; expires=value"
##
## If an element is present named "days", "hours", or "minutes", the
## corresponding value is converted to seconds, added to the current
## time, converted to RFC850 time format, and appended to the result
## as, for example, "; expires=Sun, 25-Sep-05 23:09:52 GMT"
##
## If any other elements named "path", "domain", or "secure" are present,
## they too are appended to the result.
##
## The resut is returned.
##

    proc make_cookie_attributes {paramsArray} {
        upvar 1 $paramsArray params

        set cookieParams ""
        set expiresIn    0

        if { [info exists params(expires)] } {
            append cookieParams "; expires=$params(expires)"
        } else {
            foreach {time num} [list days 86400 hours 3600 minutes 60] {
                if {[info exists params($time)]} {
                    incr expiresIn [expr {$params($time) * $num}]
                }
            }
            if {$expiresIn != 0} {
                set secs [expr [clock seconds] + $expiresIn]
                append cookieParams "; expires=[clock_to_rfc850_gmt $secs]"
            }
        }
        if { [info exists params(path)] } {
            append cookieParams "; path=$params(path)"
        }
        if { [info exists params(domain)] } {
            append cookieParams "; domain=$params(domain)"
        }
        if { [info exists params(secure)] && $params(secure) == 1} {
            append cookieParams "; secure"
        }
        if { [info exists params(HttpOnly)] && $params(HttpOnly)} {
            append cookieParams "; HttpOnly"
        }

        return $cookieParams
    }

## cookie [set|get] cookieName ?cookieValue? [-days expireInDays]
##    [-hours expireInHours] [-minutes expireInMinutes]
##    [-expires  Wdy, DD-Mon-YYYY HH:MM:SS GMT]
##    [-path uriPathCookieAppliesTo]
##    [-secure 1|0]
##

    proc cookie {cmd name args} {
        set badchars "\[ \t;\]"

        switch -- $cmd {
        "set" {
            set value [lindex $args 0]
            set args  [lrange $args 1 end]
            import_keyvalue_pairs params $args

            if {[regexp $badchars $name]} {
            return -code error \
                "name may not contain semicolons, spaces, or tabs"
            }
            if {[regexp $badchars $value]} {
            return -code error \
                "value may not contain semicolons, spaces, or tabs"
            }

            set cookieKey "Set-Cookie"
            set cookieValue "$name=$value"

            append cookieValue [make_cookie_attributes params]

            headers add $cookieKey $cookieValue
        }

        "get" {
            ::request::global RivetCookies

            if {![array exists RivetCookies]} { load_cookies RivetCookies }
            if {![info exists RivetCookies($name)]} { return }
            return $RivetCookies($name)
        }

        "delete" {
            ## In order to delete a cookie, we just need to set a cookie
            ## with a time that has already expired.
            cookie set $name "" -minutes -1
        }
        "unset" {
            ::request::global RivetCookies
            if {![array exists RivetCookies]} { load_cookies RivetCookies }
            if {![info exists RivetCookies($name)]} { return }
            unset RivetCookies($name)
        }
        }
    }

}
