REBOL [
    Title: "Wiki"
    Date: 3-Jul-2002
    Name: Wiki
    Version: 1.0.0
    File: %Wiki.r
    Author: "Andrew Martin"
    Purpose: {Wiki. Creates a Wiki using Rebol, and the Xitami web server.}
    Email: Al.Bri@xtra.co.nz
    Web: http://valley.150m.com
    Category: [util net markup 5]
]

Wiki_Directory: %/C/Rebol/Wiki/Files/   ; Where all the Wiki's .txt files are stored.
Remote: %/c/Xitami/cgi-bin/
if Remote <> what-dir [
    write join Remote Rebol/script/header/File read Rebol/script/header/File
    ]

if not value? 'Values [
    do %/C/Rebol/Values/Values.r
    ]

if none? Rebol/options/cgi/script-name [
    browse http://localhost/cgi-bin/Wiki.r
    quit
    ]

Forbidden: {\/:*?"<>|}  ; A Wiki name cannot contain any of these characters.
Permitted: exclude Printable charset Forbidden
CGI: make object! [
    Post?: "POST" = Rebol/options/cgi/request-method
    Get?: "GET" = Rebol/options/cgi/request-method
    Script-File: to-file Rebol/options/cgi/script-name
    Script-URL: join make url! compose [
        http (join Rebol/options/cgi/server-name Rebol/options/cgi/script-name)
        ] #"?"
    Query: Rebol/options/cgi/query-string
    ]
Date_Rule: [
    1 2 digit [#"/" | #"-"] [1 2 digit | 3 12 alpha] [#"/" | #"-"] [4 digit | 2 digit]
    ]
File_Rule: [some [some Permitted opt #"/"]]
See_Other: func [URL [url!]] [
    print rejoin [
        Rebol/options/cgi/server-protocol " Status: 303 See Other" newline
        "Location: " URL newline
        ]
    ]
Deplus: func [Value [string!]] [
    dehex replace/all copy Value #"+" #" "
    ]
Enspace: func [Value [file! string!]] [
    replace/all copy Value #" " "%20"
    ]

Envelope: func [Title [string!] Body [block!]] [
    content-type text/html
    print ML compose/deep [
        ?xml/version/encoding "1.0" "UTF-8"
        <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
            "http://www.w3.org/TR/xhtml11/DTD/xhtml11-frameset.dtd">
        html [
            head [
                title (Title)
                link/rel/type/href "stylesheet" "text/css" %/Stylesheet.css
                ]
            body [(Body)]
            ]
        ]
    ]

Pages: make object! [
    New: make object! [
        Name: File: none
        Rule?: does [
            all [
                CGI/Get?
                string? CGI/Query
                not empty? CGI/Query
                parse/all CGI/Query [
                    [
                        Date_Rule (
                            error? try [
                                Name: to-string load deplus CGI/Query
                                ]
                            )
                        | File_Rule (
                            Name: deplus CGI/Query
                            )
                        ] end (
                        File: to-file Name
                        any [directory? File File: Extension File %.txt]
                        )
                    ]
                not exists? Wiki_Directory/:File
                ]
            ]
        Execute: has [Title] [
            either directory? File [
                md/deep Wiki_Directory/:File
                See_Other rejoin [CGI/Script-URL enspace Name]
                ] [
                Envelope Title: join "New: " Name compose/deep [
                    h1 (Title)
                    (
                        Save/Html Name "Change text in Name text box to rename page." rejoin [
                            Name newline
                            head insert/dup copy "" #"*" length? Name newline
                            ]
                        )
                    ]
                ]
            ]
        ]
    Save: make object! [
        Rule?: does [
            CGI/Post?
            ]
        Execute: has [Post Length Name Text File] [
            Post: make string! 2 + Length: to-integer Rebol/options/cgi/content-length
            read-io Rebol/ports/input Post Length
            parse/all Post [
                "Name=" copy Name to #"&" skip
                "Text=" copy Text to end
                end
                ]
            either none? Name [
                See_Other CGI/Script-URL
                ] [
                Name: deplus Name
                File: extension to-file Name %.txt
                either none? Text [
                    if exists? Wiki_Directory/:File [
                        delete Wiki_Directory/:File
                        ]
                    See_Other rejoin [
                        CGI/Script-URL
                        use [Dir] [
                            either none? Dir: directory File [
                                ""
                                ] [
                                rejoin [
                                    enspace directory File
                                    ]
                                ]
                            ]
                        ]
                    ] [
                    Text: deplus Text
                    make-dir/deep directory Wiki_Directory/:File
                    write/binary Wiki_Directory/:File Text
                    See_Other rejoin [CGI/Script-URL enspace Name]
                    ]
                ]
            ]
        Html: func [Name [string!] Hint [string!] Text [string!]] [
            compose/deep [
                form/method/action "POST" (CGI/Script-File) [
                    label [
                        "Name: " input/type/name/value "text" "Name" (Name) #" " (Hint)
                        ] br
                    textarea/name/rows/cols/wrap/style "Text" 25 80 "virtual" "width:100%;" (
                        Text
                        )
                    div/align "right" [
                        input/type/value "submit" "Save"
                        ]
                    ]
                ]
            ]
        ]
    Edit: make object! [
        Title: "Edit"
        Name: File: none
        Command: join #"*" Title
        Rule?: does [
            all [
                CGI/Get?
                string? CGI/Query
                not empty? CGI/Query
                parse/all CGI/Query [
                    Command #"=" copy Name File_Rule end (
                        Name: deplus Name
                        File: extension to-file Name %.txt
                        )
                    ]
                exists? Wiki_Directory/:File
                ]
            ]
        Execute: has [Page_Title] [
            Page_Title: rejoin [Title ": " Name]
            Envelope Page_Title compose/deep [
                h1 (Page_Title)
                (
                    Save/Html Name "Change text in Name text box to clone page."
                        read Wiki_Directory/:File
                    )
                ]
            ]
        Html: func [Title [string!]] [
            compose/deep [
                form/method/action "GET" (CGI/Script-File) [
                    input/type/value "submit" "Edit"
                    input/type/name/value "hidden" (Command) (Title)
                    ]
                ]
            ]
        ]
    Random_Page: make object! [
        random/seed now
        Title: "Random"
        Command: join #"*" Title
        Rule?: does [
            all [
                CGI/Get?
                string? CGI/Query
                not empty? CGI/Query
                parse/all CGI/Query [
                    Command #"=" Title end
                    ]
                ]
            ]
        Execute: has [File] [
            until [
                File: first random recursive-read Wiki_Directory
                %.txt = extension? File
                ]
            See_Other rejoin [CGI/Script-URL enspace copy/part File find File %.txt]
            ]
        Html: does [
            compose/deep [
                form/method/action "GET" (CGI/Script-File) [
                    input/type/value "submit" (Title)
                    input/type/name/value "hidden" (Command) (Title)
                    ]
                ]
            ]
        ]
    Search: make object! [
        Query: none
        Title: "Search"
        Command: join #"*" Title
        Rule?: has [Rule Index] [
            Rule: join Command #"="
            all [
                CGI/Get?
                string? CGI/Query
                not empty? CGI/Query
                any [
                    all [
                        #"?" = last CGI/Query
                        any [
                            Query: dehex copy/part CGI/Query
                                find CGI/Query #"?"
                            ]
                        ]
                    all [
                        found? Index: find CGI/Query Rule
                        1 = Index: index? Index
                        found? Index: find/tail CGI/Query Rule
                        Query: deplus Index
                        ]
                    ]
                ]
            ]
        Execute: has [Results Index Title] [
            if empty? Query [
                See_Other CGI/Script-URL
                exit
                ]
            Results: make block! 100
            append Results [
                tr [
                    th "Results"
                    th "Document"
                    ]
                ]
            foreach File recursive-read Wiki_Directory [
                if %.txt = Extension? File [
                    Text: read Wiki_Directory/:File
                    if found? Index: find Text Query [
                        File: head clear extension? File
                        append Results compose/deep [
                            tr [
                                td [
                                    (rejoin ["..." copy/part Index -35])
                                    span/class "Hilight" (copy/part Index length? Query)
                                    (append copy/part at Index 1 + length? Query 35 "...")
                                    ]
                                td [
                                    a/href (rejoin [CGI/Script-File #"?" File]) (File)
                                    ]
                                ]
                            ]
                        ]
                    ]
                ]
            Envelope Title: rejoin ["Search: " Query] compose/deep [
                h1 (Title)
                table/width "100%" [(Results)]
                hr
                table/width "100%" [
                    tr [
                        td/align "left" [(Contents/Html)]
                        td/align "left" [(Random_Page/Html)]
                        td/align "center" [(Search/Html Query)]
                        td/align "right" #" "
                        ]
                    ]
                ]
            ]
        Html: func [Default [string!]] [
            compose/deep [
                form/method/action "GET" (CGI/Script-File) [
                    label [
                        (rejoin [Title SP Rebol/script/header/title ": "])
                        input/type/name/value "text" (Command) (Default)
                        ]
                    input/type/value "submit" (Title)
                    ]
                ]
            ]
        ]
    View: make object! [
        File: Name: none
        Rule?: does [
            all [
                CGI/Get?
                string? CGI/Query
                not empty? CGI/Query
                parse/all dehex CGI/Query [
                    [
                        copy Name Date_Rule (
                            error? try [
                                Name: to-string load Name
                                ]
                            )
                        | copy Name File_Rule
                        ]
                    end (
                        File: join to-file Name %.txt
                        )
                    ]
                exists? Wiki_Directory/:File
                ]
            ]
        Execute: has [Title] [
            Envelope Title: to-string filename File compose/deep [
                (
                    eText/Wiki/Base read Wiki_Directory/:File rejoin [
                        CGI/Script-File #"?" any [directory File ""]
                        ]
                    )
                hr
                table/width "100%" [
                    tr [
                        td/align "left" [(Contents/Html)]
                        td/align "left" [(Random_Page/Html)]
                        td/align "center" [(Search/Html Title)]
                        td/align "right" [(Edit/Html Name)]
                        ]
                    ]
                ]
            ]
        ]
    Delete_Subdirectory: make object! [
        Title: "Delete"
        Command: join #"*" Title
        Subdirectory: none
        Rule?: does [
            all [
                CGI/Get?
                string? CGI/Query
                not empty? CGI/Query
                parse/all CGI/Query [
                    Command #"=" copy Subdirectory File_Rule end (
                        Subdirectory: to-file deplus Subdirectory
                        )
                    ]
                ]
            ]
        Execute: has [Url] [
            Url: CGI/Script-URL
            if all [
                exists? Wiki_Directory/:Subdirectory
                empty? read Wiki_Directory/:Subdirectory
                delete Wiki_Directory/:Subdirectory
                not none? Subdirectory: directory Subdirectory
                ] [
                Url: rejoin [CGI/Script-URL Subdirectory]
                ]
            See_Other Url
            ]
        Html: func [Subdirectory [file!]] [
            compose/deep [
                form/method/action "GET" (CGI/Script-File) [
                    input/type/value "submit" (Title)
                    input/type/name/value "hidden" (Command) (to-string Subdirectory)
                    ]
                ]
            ]
        ]
    Contents: make object! [
        Title: "Contents"
        Subdirectory: none
        Rule?: does [
            all [
                CGI/Get?
                any [
                    none? CGI/Query
                    empty? CGI/Query
                    all [
                        #"/" = last Subdirectory: dehex CGI/Query
                        exists? Wiki_Directory/:Subdirectory
                        Subdirectory: to-file Subdirectory
                        ]
                    ]
                ]
            ]
        Execute: has [Links] [
            Envelope Title compose/deep [
                h1 (Title)
                (all [Subdirectory compose [h2 (to-string Subdirectory)]])
                (
                    Links: make block! 100
                    foreach File read either Subdirectory [
                        Wiki_Directory/:Subdirectory
                        ] [
                        Wiki_Directory
                        ] [
                        if any [
                            Directory? File
                            all [
                                %.txt = Extension? File
                                File: filename File
                                ]
                            ] [
                            append Links compose/deep [
                                li [
                                    a/href (
                                        rejoin [
                                            CGI/Script-File #"?" either Subdirectory [
                                                Subdirectory/:File
                                                ] [
                                                File
                                                ]
                                            ]
                                        ) (File)
                                    ]
                                ]
                            ]
                        ]
                    either empty? Links [
                        Delete_Subdirectory/Html Subdirectory
                        ] [
                        compose/deep [
                            ul [(Links)]
                            ]
                        ]
                    )
                hr
                table/width "100%" [
                    tr [
                        td/align "left" [
                            (
                                either Subdirectory [Contents/Html] [""]
                                )
                            ]
                        td/align "left" [(Random_Page/Html)]
                        td/align "right" [(Search/Html Title)]
                        ]
                    ]
                ]
            ]
        Html: does [
            compose/deep [
                form/method/action "GET" (CGI/Script-File) [
                    input/type/value "submit" (Title)
                    ]
                ]
            ]
        ]
    ]

foreach Page next first Pages [
    Page: get in Pages Page
    if Page/Rule? [
        Page/Execute
        quit
        ]
    ]
Envelope Rebol/script/header/Title compose/deep [
    h1 (Rebol/script/header/Title)
    p/class "Initial" (reform ["Now: " now])
    pre [
        "Rebol/options/cgi: " (mold Rebol/options/cgi)
        ]
    ]