Following is Messages 0.9.4 which includes many improvements, etc., as follows: -Code reduction: replaced redundant code in several places with functions. -Added support for forums. Messages can now be used to display/administer news headlines or it can be used as an engine for a discussion forum. Known issues: -Bo's encrypt.r, which is used to create %logins.bin, runs into a memory error when decrypting more than a half dozen login usernames/passwords. You may view Messages "in action" at rebolrepublic.org. View message system "news" style... http://www.rebolrepublic.org/cgi-bin/messages.cgi?actionType=display&messageType=news&messageID=none View message system "forum" style... http://www.rebolrepublic.org/cgi-bin/messages.cgi?actionType=forum&messageType=news&messageID=none NOTE: the stylesheet for messages is based on the messageType variable. PLANS FOR FUTURE RELEASES: Support for classifieds (essentially a forum system without comments); support for HTML tags in message content; replace encrypt.r functions with RSA-encrypted login system based on Tom's rsa.r As always, input is appreciated. -Ryan #!rebol -cs REBOL [ Title: "Messages" Date: 20-Apr-2001 Version: 0.9.4 File: %messages.cgi Home: http://www.rebolrepublic.org Author: "Ryan C. Christiansen" Email: [EMAIL PROTECTED] Rights: "Copyright (C) Ryan C. Christiansen 1999-2001" Purpose: { Create, display, edit, and delete messages using a standard XML storage format and CSS2-reference <DIV> tags for display. The script is dependent on the use of .css stylesheets for separate messageTypes. } Comment: { This file %messages.cgi is a single engine for creating, displaying, editing, and deleting messages. For displaying, editing, and deleting messages, %messages.cgi must receive the following variables as CGI input: actionType, messageType, and messageID. For creating messages, %messages.cgi must receive a REBOL e-mail object! as input or the following variables as CGI input: actionType, messageType, subject, author, and content. During message creation, %messages.cgi creates the following variables: date and messageID. } History: [ 0.0.9 [4-Jan-2001 "Created %std_msg_func_lib.r based on previous work." "Ryan"] 0.1.1 [5-Jan-2001 "Added 'display-markup object! functions and changed file name to %standard-message-function-library.r" "Ryan"] 0.1.2 [8-Jan-2001 "Fixed 'read-message-directory to output file names including path to directory defined by messageType." "Ryan"] 0.2.1 [9-Jan-2001 "Corrected target 'word in 'write-xml-message. Added 'create-message object! functions. Corrected 'display-markup to output string! datatype instead of block! datatype. Negated use of 'message-request-data target variable in 'read-directory-messages. Added 'get-messages-for-display object! functions." "Ryan"] 0.2.3 [10-Jan-2001 "Added 'display-messages function, the top-level function for displaying messages. Pared down usage in 'Example portion of header to include only top-most functions. Removed /html-output function from 'get-messages-for-display object! and removed /html function from 'display-markup object!" "Ryan"] 0.2.4 [11-Jan-2001 "Changed the order of values (switched 'author' and 'subject') for the XML grammar in all functions. Changed the 'either switch in 'display-messages from 'none to the string! datatype 'none'." "Ryan"] 0.2.5 [8-Feb-2001 "Removed incorrect class/id combinations from CSS font designations. Changed 'display-markup and 'display-messages to markup content using only CSS class designations instead of class/id combinations." "Ryan"] 0.2.7 [18-Feb-2001 "Added routine to 'display-messages function which will display all messages in a directory minus the content value. The index option is called by sending 'index' as the 'messageID value to 'display-messages." "Ryan"] 0.3.7 [28-Mar-2001 "Changed name of script to %messages.cgi. Changed e-mail address in header. Updated Comment and Example field in header. Changed 'display-markup to markup messages using <div> tags instead of <font> tags. Changed 'display-markup from a function to an object which includes 'for-reading object including 'with-reference (display messageID and messageType) and 'without-reference functions, and also 'for-editing object with 'with-reference function to display a message or messages for editing, including <FORM> and <INPUT> tags. Added 'edit-message function for editing messages. Added 'edited-from-cgi function to 'decode-to-object object! Added 'delete-message function. Added 'message-action-cgi uber-function." "Ryan"] 0.5.0 [29-Mar-2001 "Added return display for delete, create, and edit switches in 'message-action-cgi. Changed 'append to 'insert in 'read-directory-messages function, which will make newest messages display first. Changed radio button value for edit/delete choice from 'choice' to 'actionType'. Fixed the way 'for-editing object functions display form values and form targets. Added form for creating new messages to 'for-editing object functions. Added 'create-form' action type to switch in 'message-action-cgi function. Added 'display-create-form function to display message creation form. Added Bohdan Lechnowsky's %encrypt.r functions. Created 'encrypt-logins function for creating %.bin files containing usernames and passwords. Added 'display-login-form function to display login form. Added 'sessionID check to all administration functions including delete, edit, display-admin, create, and create-form. Added 'sessionID variables to form output in all admin forms. Added sort/reverse statement in 'read-dir ectory-messages function in an attempt to make the newest messages display first. Added if error? try statement to program section script which will default to displaying messages in the absence of cgi input data." "Ryan"] 0.5.1 [30-Mar-2001 "Changed sort/reverse statement in 'read-directory-messages function so that it sorts the 'message-directory block instead of the 'message-block block." "Ryan"] 0.5.6 [4-Apr-2001 "Removed HTML headers from 'display-create-form and 'display-login-form. Removed 'without-reference function in 'display-messages/for-reading object!, making 'display-messages/for-reading a function replacing the 'with-reference function. Made 'display-messages/for-editing a function replacing the 'with-reference function within the 'display-messages/for-editing object! All messages will display references. Changed 'display-admin' switch to 'edit-form' in 'message-action-cgi function. Added parse statement to display 'messageID and 'messageType in 'display-messages/for-editing function." "Ryan"] 0.6.0 [5-Apr-2001 "Added 'display-comments' switch to 'message-action-cgi, including 'reverse-input function which will make the messageID the messageType for comment viewing and posting. Added post/view comments link to 'display-messages/for-editing function. Added error correction to stylesheet loading, making it load %comments.css on error (expecting an error when the messageType is messageID after the 'reverse-input operation. Added 'display-comment-form function." "Ryan"] 0.6.6 [6-Apr-2001 "Added 'post-comment-input object to 'comment' switch, including 'parent-messageID value in 'comment' switch and 'display-comment-form function, allowing a comment's parent to be displayed after commenting, eliminating an error. Made 'display-messages/for-reading function an object! containing functions 'for-commenting and 'no-commenting. Updated 'message-action-cgi switch statements for the change. Added 'parent-message-input object and 'post-comment-reverse-input object to 'comment' switch for displaying original message and proper comment input form after comment creation. Added <DIV> tag to post/view comments link. Added post/view comments links to 'display-messages/for-editing function. Added 'display-comments-edit' switch to 'message-action-cgi function." "Ryan"] 0.7.4 [11-Apr-2001 "Added 'message-block return statement to 'read-directory-messages function and moved 'sort/reverse statement to sort 'message-block instead of 'message-directory. Added error-checking to 'display' switch in 'message-action-cgi. Added 'make decimal! statement to 'login' switch in 'message-action-cgi. Created 'check-sessionID function to replace redundant code in 'message-action-cgi. Added 'sessionID-timeout value in configuration section. Changed 'Edit' and 'Delete' and 'Create New!' options in 'display-messages/for-editing function to be more descriptive. Added 'search-messages function. Added 'search' switch to 'message-action-cgi. Added search form to all 'display-messages object! output." "Ryan"] 0.7.5 [12-Apr-2001 "Moved 'message-block return statement in 'search-messages function. Removed 'search' switch debugging in 'message-action-cgi." "Ryan"] 0.8.1 [18-Apr-2001 "Changed 'insert to 'append in 'read-directory-messages function. Added 'display-search-form function to replace redundant code in 'display-messages object! Added 'display-create-button function to replace redundant code in 'display-messages/for-editing function. Added 'display-edit-message-button function to replace redundant code in 'display-messages/for-editing function. Added 'display-delete-message-button function to replace redundant code in 'display-messages/for-editing function. Added 'display-comments-link function to replace redundant code in 'display-messages object!" "Ryan"] 0.8.2 [19-Apr-2001 "Added 'display-comments-edit-link function to replace redundant code in 'display-messages/for-editing function." "Ryan"] 0.9.4 [20-Apr-2001 "Added 'return-div-text function to replace redundant code in 'display-messages object! Added 'return-messageID function to replace redundant code in 'display-messages object! Added 'return-messageType function to replace redundant code in 'display-messages object! Added 'display-messages/forum-style function for using %messages.cgi to run a forum. Added 'display-create-button-forum function for creating new messages in 'display-messages/forum-style function. Added 'create-form-forum' switch to 'message-action-cgi function. Added 'display-create-form-forum function for displaying a message creation form in a forum environment. Added 'create-forum' switch to 'message-action-cgi function for creating new messages in a forum environment. Added 'display-comments-forum-link function for using the commenting system within a forum environment. Added 'display-comments-forum' switch to 'message-action-cgi function for using the commenting system within a forum environment. Added 'display-com ments-form-forum function for displaying a commenting system form within a forum environment. Added 'comment-forum' switch to 'message-action-cgi for creating comments within a forum environment. Added 'display-search-form-forum function to allow searches within a forum environment. Added 'search-forum' switch to 'message-action-cgi function to return forum-style message display after a search." "Ryan"] ] Example: { Decode CGI input and create, display, edit, or delete message(s). This is the script's uber-function for CGI. message-action-cgi To decode CGI input from the web server: cgi-input: retrieve-user-data Using decoded CGI data, write XML standard message file to directory determined by messageType. create-message/from-cgi cgi-input Using an e-mail message or newsgroup message in the form of a REBOL e-mail object!, write XML standard message file to 'email' directory. create-message/from-email email-message Convert decoded CGI data into the standard message object!, overwriting a previously created message. edit-message cgi-input Delete a previously created message. delete-message cgi-input Using decoded CGI data containing messageID and messageType variables, either display a single message (messageID specified), a directory of messages (messageID = "none"), or an index of messages (messageID = "index") to the browser, including displaying the messageID and messageType to the reader. display-messages/for-reading/with-reference cgi-input Using decoded CGI data containing messageID and messageType variables, either display a single message (messageID specified), a directory of messages (messageID = "none"), or an index of messages (messageID = "index") to the browser, not displaying the messageID nor the messageType to the reader. display-messages/for-reading/without-reference cgi-input Using decoded CGI data containing messageID and messageType variables, either display a single message (messageID specified), a directory of messages (messageID = "none"), or an index of messages (messageID = "index") to the browser, including displaying the messageID and messageType to the reader, in an HTML form for editing. display-messages/for-editing/with-reference cgi-input } ] ;######################################## ;# CONFIGURATION # ;######################################## sessionID-timeout: make decimal! 1000 ;######################################## ;# FUNCTIONS # ;######################################## translate-message: make object! [ xml-tags: [ ["subject" "/subject"] ["author" "/author"] ["date" "/date"] ["content" "/content"] ["messageID" "/messageID"] ["messageType" "/messageType"] ] markup-data: func [ "Converts a standard message object! into a string containing the XML-format standard message." data [object!] "The standard message object!" ][ data-object: make data [] object-data: next first data-object output: copy "" for x 1 (length? xml-tags) 1 [ item: reform [rejoin ["data-object" "/" (first object-data)]] made-tag: rejoin ["" (build-tag [(xml-tags/1/1)]) (do item) (build-tag [(xml-tags/1/2)])] xml-tags: next xml-tags object-data: next object-data append output made-tag ] xml-tags: head xml-tags output ] read-markup: func [ "Converts a file containing the XML-format standard message into a standard message object!" xml-file [file!] "File containing the XML-format standard message." ][ message-data: load/markup xml-file xml-data: make object! [ subject: message-data/<subject> author: message-data/<author> date: message-data/<date> content: message-data/<content> messageID: message-data/<messageID> messageType: message-data/<messageType> ] xml-data ] ] decode-to-object: make object! [ from-cgi: func [ "Converts decoded CGI data into the standard message object!" cgi-data [object!] "Decoded CGI data." ][ make object! [ subject: cgi-data/subject author: cgi-data/author date: now content: cgi-data/content messageID: time-in-digits now messageType: cgi-data/messageType ] ] edited-from-cgi: func [ "Converts decoded CGI data into the standard message object!" cgi-data [object!] "Decoded CGI data." ][ make object! [ subject: cgi-data/subject author: cgi-data/author date: cgi-data/date content: cgi-data/content messageID: cgi-data/messageID messageType: cgi-data/messageType ] ] from-email: func [ "Converts the standard REBOL e-mail object! into the standard message object!" email-data [object!] "Standard REBOL e-mail object!" ][ make object! [ subject: email-data/subject author: email-data/from date: email-data/date content: email-data/content messageID: time-in-digits now messageType: "email" ] ] time-in-digits: func [ "Convert the date and time from 'now' into a string of digits." sun-dial [date!] "The current date and time from 'now." ][ year: to-string sun-dial/year month: to-string sun-dial/month if (length? month) < 2 [insert month "0"] day: to-string sun-dial/day if (length? day) < 2 [insert day "0"] current-time: sun-dial/time hour: to-string current-time/hour if (length? hour) < 2 [insert hour "0"] minutes: to-string current-time/minute if (length? minutes) < 2 [insert minutes "0"] seconds: to-string current-time/second if (length? seconds) < 2 [insert seconds "0"] rejoin [year month day hour minutes seconds] ] ] time-in-digits: func [ "Convert the date and time from 'now' into a string of digits." sun-dial [date!] "The current date and time from 'now'" ][ year: to-string sun-dial/year month: to-string sun-dial/month if (length? month) < 2 [insert month "0"] day: to-string sun-dial/day if (length? day) < 2 [insert day "0"] current-time: sun-dial/time hour: to-string current-time/hour if (length? hour) < 2 [insert hour "0"] minutes: to-string current-time/minute if (length? minutes) < 2 [insert minutes "0"] seconds: to-string current-time/second if (length? seconds) < 2 [insert seconds "0"] rejoin [year month day hour minutes seconds] ] retrieve-user-data: func [] [ return make object! decode-cgi either system/options/cgi/request-method = "POST" [ input ][ system/options/cgi/query-string ] ] write-xml-message: func [ "Write the XML-formatted standard message data with a file name determined by messageID and to a directory determined by messageType." xml-message-string [string!] "The XML-formatted standard message as it resides in memory as a string! datatype." ][ message-data: load/markup xml-message-string save-path: make file! (rejoin [message-data/<messageType> "/" message-data/<messageID>]) write/binary save-path xml-message-string ] read-message-directory: func [ "Read a directory of file names corresponding to a directory of XML-formatted standard messages with the directory determined by messageType." message-request-data [object!] "The data from the request to view messages, typically from an HTML form submitted to CGI." ][ message-directory: read (directory-name: make file! (rejoin [message-request-data/messageType "/"])) foreach message message-directory [ replace message message (make file! (rejoin [message-request-data/messageType "/" message])) ] message-directory ] read-message: func [ "Read a specific XML-formatted standard message with the directory determined by messageType and the file name determined by messageID." message-request-data [object!] "The data from the request to view a specific message, typically from an HTML form submitted to CGI." ][ message-directory: read (directory-name: make file! (rejoin [message-request-data/messageType "/" message-request-data/messageID])) ] read-directory-messages: func [ "Read a directory of XML-formatted standard messages with the directory determined by messageType." message-directory [block!] "A block of file names corresponding to a directory of XML-formatted standard messages." ][ message-block: copy [] sort/reverse message-directory foreach file-name message-directory [ file-contents: read file-name append message-block file-contents message-block ] ] display-markup: make object! [ xml-values: ["subject" "author" "date" "content" "messageID" "messageType"] css: func [ "Markup a standard message using standardized cascading style sheets tags as the display markup." xml-message-string [string!] "The XML-formatted standard message as it resides in memory as a string! datatype." ][ css-markup: copy [] standard-message-data: load/markup xml-message-string foreach value xml-values [ value-content: reform [rejoin ["standard-message-data" "/" "<" (first xml-values) ">"]] append css-markup (rejoin [{<div class="} value {">} (do value-content) {</div>}]) xml-values: next xml-values ] xml-values: head xml-values css-markup: make string! css-markup ] ] create-message: make object! [ from-cgi: func [ "Using decoded CGI data, writes XML standard message file to directory determined by messageType." cgi-input [object!] "Decoded CGI data as submitted from an HTML form." ][ standard-message-object: decode-to-object/from-cgi cgi-input xml-message-string: translate-message/markup-data standard-message-object write-xml-message xml-message-string ] from-email: func [ "Using an e-mail message in the form of a REBOL e-mail object!, writes XML standard message file to 'email' directory." email-message [object!] "E-mail message in the form of a REBOL e-mail object!" ][ standard-message-object: decode-to-object/from-email email-message xml-message-string: translate-message/markup-data standard-message-object write-xml-message xml-message-string ] ] edit-message: func [ "Converts decoded CGI data into the standard message object!, overwriting a previously created message." cgi-data [object!] "Decoded CGI data." ][ standard-message-object: decode-to-object/edited-from-cgi cgi-input xml-message-string: translate-message/markup-data standard-message-object write-xml-message xml-message-string ] delete-message: func [ "Deletes a previously created message." cgi-data [object!] "Decoded CGI data." ][ file-to-delete: make file! (rejoin [cgi-data/messageType "/" cgi-data/messageID]) delete file-to-delete ] get-messages-for-display: make object! [ all-messages-in-directory: make object! [ css-output: func [ "Using decoded CGI data, create a block! of messages marked up for display using standardized cascading style sheets tags as the display markup." cgi-input [object!] "Decoded CGI data as submitted from an HTML page, most likely sent using GET with messageType and messageID (set to none) sent as an appendage to the url request." ][ message-directory: read-message-directory cgi-input messages: read-directory-messages message-directory messages-for-display: copy [] foreach xml-message messages [ css-message: display-markup/css xml-message append messages-for-display css-message ] messages-for-display ] ] specific-message: make object! [ css-output: func [ "Using decoded CGI data, mark up a specific message for display using standardized cascading style sheets tags as the display markup." cgi-input [object!] "Decoded CGI data as submitted from an HTML page, most likely sent using GET with messageType and messageID sent as an appendage to the url request." ][ file-path: make file! (rejoin [cgi-input/messageType "/" cgi-input/messageID]) xml-message: read file-path css-message: display-markup/css xml-message ] ] ] display-messages: make object! [ css-classes: ["subject" "author" "date" "content" "messageID" "messageType"] for-reading: make object! [ for-commenting: func [ {Using decoded CGI data containing messageID and messageType variables, either display a single message (messageID specified), a directory of messages (messageID = "none"), or an index of messages (messageID = "index") to the browser, including displaying the messageID and messageType to the reader.} cgi-input [object!] "Decoded CGI data as submitted from an HTML page, most likely sent using GET with messageType and messageID sent as an appendage to the url request." ][ switch/default cgi-input/messageID [ "none" [ messages: get-messages-for-display/all-messages-in-directory/css-output cgi-input display-search-form cgi-input foreach message messages [ foreach class css-classes [ switch/default class [ "messageID" [ return-div-text class message this-messageID: return-messageID class message ] "messageType" [ return-div-text class message this-messageType: return-messageType class message ] ][ css-tag: build-tag [div class (class)] parse/all message [to css-tag copy text thru </div> (print text)] ] ] display-comments-link this-messageID this-messageType ] ] "index" [ messages: get-messages-for-display/all-messages-in-directory/css-output cgi-input display-search-form cgi-input foreach message messages [ foreach class css-classes [ switch/default class [ "content" [ next css-classes ] "messageID" [ return-div-text class message this-messageID: return-messageID class message ] "messageType" [ return-div-text class message this-messageType: return-messageType class message ] ][ css-tag: build-tag [div class (class)] parse/all message [to css-tag copy text thru </div> (print text)] ] ] display-comments-link this-messageID this-messageType ] ] ][ message: get-messages-for-display/specific-message/css-output cgi-input display-search-form cgi-input foreach class css-classes [ switch/default class [ "messageID" [ return-div-text class message this-messageID: return-messageID class message ] "messageType" [ return-div-text class message this-messageType: return-messageType class message ] ][ css-tag: build-tag [div class (class)] parse/all message [to css-tag copy text thru </div> (print text)] ] ] display-comments-link this-messageID this-messageType ] ] no-commenting: func [ {Using decoded CGI data containing messageID and messageType variables, either display a single message (messageID specified), a directory of messages (messageID = "none"), or an index of messages (messageID = "index") to the browser, including displaying the messageID and messageType to the reader.} cgi-input [object!] "Decoded CGI data as submitted from an HTML page, most likely sent using GET with messageType and messageID sent as an appendage to the url request." ][ switch/default cgi-input/messageID [ "none" [ messages: get-messages-for-display/all-messages-in-directory/css-output cgi-input display-search-form cgi-input foreach message messages [ foreach class css-classes [ css-tag: build-tag [div class (class)] parse/all message [to css-tag copy text thru </div> (print text)] ] ] ] "index" [ messages: get-messages-for-display/all-messages-in-directory/css-output cgi-input display-search-form cgi-input foreach message messages [ foreach class css-classes [ either class = "content" [ next css-classes ][ css-tag: build-tag [div class (class)] parse/all message [to css-tag copy text thru </div> (print text)] ] ] ] ] ][ message: get-messages-for-display/specific-message/css-output cgi-input display-search-form cgi-input foreach class css-classes [ css-tag: build-tag [div class (class)] parse/all message [to css-tag copy text thru </div> (print text)] ] ] ] ] for-editing: func [ {Using decoded CGI data containing messageID and messageType variables, either display a single message (messageID specified), a directory of messages (messageID = "none"), or an index of messages (messageID = "index") to the browser, including displaying the messageID and messageType to the reader, in an HTML form for editing.} cgi-input [object!] "Decoded CGI data as submitted from an HTML page, most likely sent using GET with messageType and messageID sent as an appendage to the url request." ][ switch/default cgi-input/messageID [ "none" [ messages: get-messages-for-display/all-messages-in-directory/css-output cgi-input display-search-form cgi-input display-create-button cgi-input foreach message messages [ foreach class css-classes [ switch/default class [ "messageID" [ return-div-text class message this-messageID: return-messageID class message ] "messageType" [ return-div-text class message this-messageType: return-messageType class message ] ][ css-tag: build-tag [div class (class)] parse/all message [to css-tag copy text thru </div> (print text)] ] ] display-edit-message-button cgi-input this-messageID this-messageType display-delete-message-button cgi-input this-messageID this-messageType display-comments-edit-link cgi-input this-messageID this-messageType ] ] "index" [ messages: get-messages-for-display/all-messages-in-directory/css-output cgi-input display-search-form cgi-input display-create-button cgi-input foreach message messages [ foreach class css-classes [ switch/default class [ "content" [ next css-classes ] "messageID" [ return-div-text class message this-messageID: return-messageID class message ] "messageType" [ return-div-text class message this-messageType: return-messageType class message ] ][ css-tag: build-tag [div class (class)] parse/all message [to css-tag copy text thru </div> (print text)] ] ] display-edit-message-button cgi-input this-messageID this-messageType display-delete-message-button cgi-input this-messageID this-messageType display-comments-edit-link cgi-input this-messageID this-messageType ] ] ][ message: get-messages-for-display/specific-message/css-output cgi-input display-search-form cgi-input display-create-button cgi-input print {<FORM METHOD=GET ACTION="messages.cgi">} foreach class css-classes [ switch class [ "subject" [ pre-subject: {<INPUT TYPE="text" NAME="subject" VALUE="} css-tag: build-tag [div class (class)] parse/all message [thru css-tag copy text to </div> (item: copy text)] post-subject: {"><BR>} print rejoin [pre-subject item post-subject] ] "author" [ pre-author: {<INPUT TYPE="text" NAME="author" VALUE ="} css-tag: build-tag [div class (class)] parse/all message [thru css-tag copy text to </div> (item: copy text)] post-author: {"><BR>} print rejoin [pre-author item post-author] ] "date" [ pre-date: {<INPUT TYPE="hidden" NAME="date" VALUE ="} css-tag: build-tag [div class (class)] parse/all message [thru css-tag copy text to </div> (item: copy text)] post-date: {">} print rejoin [pre-date item post-date] ] "content" [ print {<TEXTAREA NAME="content" ROWS="24" COLS ="40">} css-tag: build-tag [div class (class)] parse/all message [thru css-tag copy text to </div> (print text)] print {</TEXTAREA><P>} ] "messageID" [ pre-messageID: {<INPUT TYPE="hidden" NAME ="messageID" VALUE="} css-tag: build-tag [div class (class)] parse/all message [thru css-tag copy text to </div> (item: copy text)] parse/all message [to css-tag copy text thru </div> (print text)] post-messageID: {">} print rejoin [pre-messageID item post-messageID] parse/all message [thru css-tag copy text to </div> (this-messageID: copy text)] ] "messageType" [ pre-messageType: {<INPUT TYPE="hidden" NAME ="messageType" VALUE="} css-tag: build-tag [div class (class)] parse/all message [thru css-tag copy text to </div> (item: copy text)] parse/all message [to css-tag copy text thru </div> (print text)] post-messageType: {">} print rejoin [pre-messageType item post-messageType] parse/all message [thru css-tag copy text to </div> (this-messageType: copy text)] ] ] ] pre-sessionID: {<INPUT TYPE="hidden" NAME="sessionID" VALUE="} post-sessionID: {">} print rejoin [pre-sessionID cgi-input/sessionID post-sessionID] print {Edit the text above and then<BR><INPUT TYPE="radio" NAME ="actionType" VALUE="edit"> Save Changes <INPUT TYPE="radio" NAME ="actionType" VALUE="delete"> Delete Message } print {<INPUT TYPE="submit" VALUE="Go!"></FORM>} display-comments-edit-link cgi-input this-messageID this-messageType ] ] forum-style: func [ {Using decoded CGI data containing messageID and messageType variables, either display a single message (messageID specified), a directory of messages (messageID = "none"), or an index of messages (messageID = "index") to the browser, including displaying the messageID and messageType to the reader.} cgi-input [object!] "Decoded CGI data as submitted from an HTML page, most likely sent using GET with messageType and messageID sent as an appendage to the url request." ][ switch/default cgi-input/messageID [ "none" [ messages: get-messages-for-display/all-messages-in-directory/css-output cgi-input display-search-form-forum cgi-input display-create-button-forum cgi-input foreach message messages [ foreach class css-classes [ switch/default class [ "messageID" [ return-div-text class message this-messageID: return-messageID class message ] "messageType" [ return-div-text class message this-messageType: return-messageType class message ] ][ css-tag: build-tag [div class (class)] parse/all message [to css-tag copy text thru </div> (print text)] ] ] display-comments-forum-link this-messageID this-messageType ] ] "index" [ messages: get-messages-for-display/all-messages-in-directory/css-output cgi-input display-search-form-forum cgi-input display-create-button-forum cgi-input foreach message messages [ foreach class css-classes [ switch/default class [ "content" [ next css-classes ] "messageID" [ return-div-text class message this-messageID: return-messageID class message ] "messageType" [ return-div-text class message this-messageType: return-messageType class message ] ][ css-tag: build-tag [div class (class)] parse/all message [to css-tag copy text thru </div> (print text)] ] ] display-comments-forum-link this-messageID this-messageType ] ] ][ message: get-messages-for-display/specific-message/css-output cgi-input display-search-form-forum cgi-input display-create-button-forum cgi-input foreach class css-classes [ switch/default class [ "messageID" [ return-div-text class message this-messageID: return-messageID class message ] "messageType" [ return-div-text class message this-messageType: return-messageType class message ] ][ css-tag: build-tag [div class (class)] parse/all message [to css-tag copy text thru </div> (print text)] ] ] display-comments-forum-link this-messageID this-messageType ] ] ] display-create-form: func [ {Display the HTML form used for message creation.} cgi-input [object!] "Decoded CGI data as submitted from an HTML page, most likely sent using GET with messageType and messageID sent as an appendage to the url request." ][ print { <FORM METHOD=GET ACTION="messages.cgi"> <INPUT TYPE="hidden" NAME="actionType" VALUE="create"> } pre-messageType: {<INPUT TYPE="hidden" NAME="messageType" VALUE="} post-messageType: {">} print rejoin [pre-messageType cgi-input/messageType post-messageType] pre-sessionID: {<INPUT TYPE="hidden" NAME="sessionID" VALUE="} post-sessionID: {">} print rejoin [pre-sessionID cgi-input/sessionID post-sessionID] print { <INPUT TYPE="text" NAME="subject" VALUE="subject"><BR> <INPUT TYPE="text" NAME="author" VALUE="author"><BR> <TEXTAREA NAME="content" ROWS="24" COLS="40">content</TEXTAREA><BR> <INPUT TYPE="submit" VALUE="Save This Message!"> </FORM> } ] display-create-form-forum: func [ {Display the HTML form used for message creation.} cgi-input [object!] "Decoded CGI data as submitted from an HTML page, most likely sent using GET with messageType and messageID sent as an appendage to the url request." ][ print { <FORM METHOD=GET ACTION="messages.cgi"> <INPUT TYPE="hidden" NAME="actionType" VALUE="create-forum"> } pre-messageType: {<INPUT TYPE="hidden" NAME="messageType" VALUE="} post-messageType: {">} print rejoin [pre-messageType cgi-input/messageType post-messageType] print { <INPUT TYPE="text" NAME="subject" VALUE="subject"><BR> <INPUT TYPE="text" NAME="author" VALUE="author"><BR> <TEXTAREA NAME="content" ROWS="24" COLS="40">content</TEXTAREA><BR> <INPUT TYPE="submit" VALUE="Save This Message!"> </FORM> } ] display-comment-form: func [ {Display the HTML form used for message creation.} cgi-input [object!] "Decoded CGI data as submitted from an HTML page, most likely sent using GET with messageType and messageID sent as an appendage to the url request." ][ print { <FORM METHOD=GET ACTION="messages.cgi"> <INPUT TYPE="hidden" NAME="actionType" VALUE="comment"> } pre-messageType: {<INPUT TYPE="hidden" NAME="messageType" VALUE="} post-messageType: {">} print rejoin [pre-messageType cgi-input/messageType post-messageType] pre-parent-messageID: {<INPUT TYPE="hidden" NAME="parent-messageID" VALUE="} post-parent-messageID: {">} print rejoin [pre-parent-messageID cgi-input/parent-messageID post-parent-messageID] pre-parent-messageType: {<INPUT TYPE="hidden" NAME="parent-messageType" VALUE="} post-parent-messageType: {">} print rejoin [pre-parent-messageType cgi-input/parent-messageType post-parent-messageType] print { <INPUT TYPE="text" NAME="subject" VALUE="subject"><BR> <INPUT TYPE="text" NAME="author" VALUE="author"><BR> <TEXTAREA NAME="content" ROWS="24" COLS="40">content</TEXTAREA><BR> <INPUT TYPE="submit" VALUE="Save This Message!"> </FORM> } ] display-comment-form-forum: func [ {Display the HTML form used for message creation.} cgi-input [object!] "Decoded CGI data as submitted from an HTML page, most likely sent using GET with messageType and messageID sent as an appendage to the url request." ][ print { <FORM METHOD=GET ACTION="messages.cgi"> <INPUT TYPE="hidden" NAME="actionType" VALUE="comment-forum"> } pre-messageType: {<INPUT TYPE="hidden" NAME="messageType" VALUE="} post-messageType: {">} print rejoin [pre-messageType cgi-input/messageType post-messageType] pre-parent-messageID: {<INPUT TYPE="hidden" NAME="parent-messageID" VALUE="} post-parent-messageID: {">} print rejoin [pre-parent-messageID cgi-input/parent-messageID post-parent-messageID] pre-parent-messageType: {<INPUT TYPE="hidden" NAME="parent-messageType" VALUE="} post-parent-messageType: {">} print rejoin [pre-parent-messageType cgi-input/parent-messageType post-parent-messageType] print { <INPUT TYPE="text" NAME="subject" VALUE="subject"><BR> <INPUT TYPE="text" NAME="author" VALUE="author"><BR> <TEXTAREA NAME="content" ROWS="24" COLS="40">content</TEXTAREA><BR> <INPUT TYPE="submit" VALUE="Save This Message!"> </FORM> } ] display-login-form: func [ {Display the HTML form used for logging in to use admin functions.} cgi-input [object!] "Decoded CGI data as submitted from an HTML page, most likely sent using GET with messageType and messageID sent as an appendage to the url request." ][ print { <FORM METHOD=GET ACTION="messages.cgi"> <INPUT TYPE="hidden" NAME="actionType" VALUE="login"> } pre-messageType: {<INPUT TYPE="hidden" NAME="messageType" VALUE="} post-messageType: {">} print rejoin [pre-messageType cgi-input/messageType post-messageType] pre-messageID: {<INPUT TYPE="hidden" NAME="messageID" VALUE="} post-messageID: {">} print rejoin [pre-messageID cgi-input/messageID post-messageID] print { <INPUT TYPE="text" NAME="userID" VALUE="username"><BR> <INPUT TYPE="password" NAME="password" VALUE="password"><BR> <INPUT TYPE="submit" VALUE="Login!"> </FORM> } ] check-sessionID: func [ {Check a user's sessionID value to make sure it is still valid.} user-sessionID [string!] {The sessionID value as generated after login and continuously updated during a session.} sessionID-timeout [decimal!] {A decimal value representing the amount of time a user may be logged in to use administration functions without taking any action.} /local sessionID-check ][ user-sessionID: make decimal! user-sessionID sessionID-check: make decimal! time-in-digits now return either (user-sessionID + sessionID-timeout) > sessionID-check [ true ][ false ] ] search-messages: func [ "Searches a directory of messages for a keyword match and returns a block of messageIDs for messages containing the keyword." cgi-data [object!] "Decoded CGI data." /local message-directory messages messages-with-keyword xml-message this-message message-with-keyword ][ message-directory: read-message-directory cgi-data messages: read-directory-messages message-directory messages-with-keyword: copy [] foreach xml-message messages [ if find xml-message cgi-data/keyword [ message-with-keyword: load/markup xml-message append messages-with-keyword message-with-keyword/<messageID> ] ] messages-with-keyword ] display-search-form: func [ {Display the HTML form used for searching messages for a keyword.} cgi-input [object!] "Decoded CGI data as submitted from an HTML page, most likely sent using GET with messageType and messageID sent as an appendage to the url request." ][ print rejoin [{<FORM METHOD=GET ACTION="messages.cgi"><INPUT TYPE ="hidden" NAME="actionType" VALUE="search"><INPUT TYPE="hidden" NAME ="messageType" VALUE="} cgi-input/messageType {"><INPUT TYPE="hidden" NAME ="messageID" VALUE="none"><INPUT TYPE="text" NAME="keyword" VALUE ="keyword"><INPUT TYPE="submit" VALUE="Search } cgi-input/messageType {!"></FORM>}] ] display-search-form-forum: func [ {Display the HTML form used for searching messages for a keyword.} cgi-input [object!] "Decoded CGI data as submitted from an HTML page, most likely sent using GET with messageType and messageID sent as an appendage to the url request." ][ print rejoin [{<FORM METHOD=GET ACTION="messages.cgi"><INPUT TYPE ="hidden" NAME="actionType" VALUE="search-forum"><INPUT TYPE="hidden" NAME ="messageType" VALUE="} cgi-input/messageType {"><INPUT TYPE="hidden" NAME ="messageID" VALUE="none"><INPUT TYPE="text" NAME="keyword" VALUE ="keyword"><INPUT TYPE="submit" VALUE="Search } cgi-input/messageType {!"></FORM>}] ] display-create-button: func [ {Display the HTML form used to generate a message creation form.} cgi-input [object!] "Decoded CGI data as submitted from an HTML page, most likely sent using GET with messageType and messageID sent as an appendage to the url request." ][ print rejoin [{<FORM METHOD=GET ACTION="messages.cgi"><INPUT TYPE ="hidden" NAME="actionType" VALUE="create-form"><INPUT TYPE="hidden" NAME ="messageType" VALUE="} cgi-input/messageType {"><INPUT TYPE="hidden" NAME ="sessionID" VALUE="} cgi-input/sessionID {"><INPUT TYPE="submit" VALUE ="Create New Message!"></FORM><P>}] ] display-create-button-forum: func [ {Display the HTML form used to generate a message creation form.} cgi-input [object!] "Decoded CGI data as submitted from an HTML page, most likely sent using GET with messageType and messageID sent as an appendage to the url request." ][ print rejoin [{<FORM METHOD=GET ACTION="messages.cgi"><INPUT TYPE ="hidden" NAME="actionType" VALUE="create-form-forum"><INPUT TYPE="hidden" NAME="messageType" VALUE="} cgi-input/messageType {"><INPUT TYPE="submit" VALUE="Create New Message!"></FORM><P>}] ] display-edit-message-button: func [ {Display the HTML form used to generate a message editing form.} cgi-input [object!] "Decoded CGI data as submitted from an HTML page, most likely sent using GET with messageType and messageID sent as an appendage to the url request." this-messageID [string!] {The messageID of a specific message as parsed from a string.} this-messageType [string!] {The messageType of a specific message as parsed from a string.} ][ print rejoin [{<FORM METHOD=GET ACTION="messages.cgi"><INPUT TYPE ="hidden" NAME="messageID" VALUE="} this-messageID {"><INPUT TYPE="hidden" NAME="messageType" VALUE="} this-messageType {"><INPUT TYPE="hidden" NAME ="sessionID" VALUE="} cgi-input/sessionID {"><INPUT TYPE="hidden" NAME ="actionType" VALUE="edit-form"><INPUT TYPE="submit" VALUE="Edit Message"></FORM>}] ] display-delete-message-button: func [ {Display the HTML form used to generate a message editing form.} cgi-input [object!] "Decoded CGI data as submitted from an HTML page, most likely sent using GET with messageType and messageID sent as an appendage to the url request." this-messageID [string!] {The messageID of a specific message as parsed from a string.} this-messageType [string!] {The messageType of a specific message as parsed from a string.} ][ print rejoin [{<FORM METHOD=GET ACTION="messages.cgi"><INPUT TYPE ="hidden" NAME="messageID" VALUE="} this-messageID {"><INPUT TYPE="hidden" NAME="messageType" VALUE="} this-messageType {"><INPUT TYPE="hidden" NAME ="sessionID" VALUE="} cgi-input/sessionID {"><INPUT TYPE="hidden" NAME ="actionType" VALUE="delete"><INPUT TYPE="submit" VALUE="Delete Message"></FORM>}] ] display-comments-link: func [ {Display a link which will will send a CGI request to show the comments related to a message.} this-messageID [string!] {The messageID of a specific message as parsed from a string.} this-messageType [string!] {The messageType of a specific message as parsed from a string.} ][ print rejoin [{<DIV class="commentlink"><A HREF ="messages.cgi?actionType=display-comments&messageType=} this-messageType {&messageID=} this-messageID {">Post/View Comments</A></DIV>}] ] display-comments-edit-link: func [ {Display a link which will will send a CGI request to show the comments related to a message.} cgi-input [object!] "Decoded CGI data as submitted from an HTML page, most likely sent using GET with messageType and messageID sent as an appendage to the url request." this-messageID [string!] {The messageID of a specific message as parsed from a string.} this-messageType [string!] {The messageType of a specific message as parsed from a string.} ][ print rejoin [{<DIV class="commentlink"><A HREF ="messages.cgi?actionType=display-comments-edit&messageType=} this-messageType {&messageID=} this-messageID {&sessionID=} cgi-input/sessionID {">Post/View Comments</A></DIV>}] ] display-comments-forum-link: func [ {Display a link which will will send a CGI request to show the comments related to a message.} this-messageID [string!] {The messageID of a specific message as parsed from a string.} this-messageType [string!] {The messageType of a specific message as parsed from a string.} ][ print rejoin [{<DIV class="commentlink"><A HREF ="messages.cgi?actionType=display-comments-forum&messageType=} this-messageType {&messageID=} this-messageID {">Post/View Comments</A></DIV>}] ] return-div-text: func [ {Return a portion of a message, including its <DIV> tags.} class [string!] {A div class name} message [string!] {A message marked up with CSS-classed <DIV> tags.} /local css-tag ][ css-tag: build-tag [div class (class)] parse/all message [to css-tag copy text thru </div> (print text)] ] return-messageID: func [ class [string!] {A div class name} message [string!] {A message marked up with CSS-classed <DIV> tags.} /local css-tag this-messageID ][ css-tag: build-tag [div class (class)] parse/all message [thru css-tag copy text to </div> (this-messageID: copy text)] this-messageID ] return-messageType: func [ class [string!] {A div class name} message [string!] {A message marked up with CSS-classed <DIV> tags.} /local css-tag this-messageType ][ css-tag: build-tag [div class (class)] parse/all message [thru css-tag copy text to </div> (this-messageType: copy text)] this-messageType ] message-action-cgi: func [ {Decode CGI input and create, display, edit, or delete message(s).} cgi-input [object!] "Decoded CGI data as submitted from an HTML page, most likely sent using GET with messageType and messageID sent as an appendage to the url request." ][ print "Content-Type: text/html^/" default-input: make cgi-input [ messageID: "none" ] if error? try [ stylesheet-to-load: make file! (rejoin [cgi-input/messageType ".css"]) stylesheet: read stylesheet-to-load ][ stylesheet-to-load: %comments.css stylesheet: read stylesheet-to-load ] print { <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <HTML> <HEAD> <TITLE></TITLE> } print {<STYLE type="text/css">} print stylesheet print {</STYLE>} print { </HEAD> <BODY> } switch/default cgi-input/actionType [ "create-form" [ either (check-sessionID cgi-input/sessionID sessionID-timeout) [ display-create-form cgi-input ][ display-login-form cgi-input ] ] "create-form-forum" [ display-create-form-forum cgi-input ] "create" [ either (check-sessionID cgi-input/sessionID sessionID-timeout) [ create-message/from-cgi cgi-input display-messages/for-editing default-input ][ display-login-form cgi-input ] ] "create-forum" [ create-message/from-cgi cgi-input display-messages/forum-style default-input ] "comment" [ if error? try [ create-message/from-cgi cgi-input ][ comments-directory: make file! rejoin [cgi-input/messageType {/}] make-dir comments-directory create-message/from-cgi cgi-input ] parent-message-input: make cgi-input [ messageType: cgi-input/parent-messageType messageID: cgi-input/parent-messageID ] post-comment-input: make cgi-input [ messageType: cgi-input/parent-messageID messageID: "none" ] post-comment-reverse-input: make cgi-input [ messageID: "none" messageType: parent-message-input/messageID parent-messageID: parent-message-input/messageID parent-messageType: parent-message-input/messageType ] display-messages/for-reading/for-commenting parent-message-input wait 1 display-messages/for-reading/for-commenting post-comment-input display-comment-form post-comment-reverse-input ] "comment-forum" [ if error? try [ create-message/from-cgi cgi-input ][ comments-directory: make file! rejoin [cgi-input/messageType {/}] make-dir comments-directory create-message/from-cgi cgi-input ] parent-message-input: make cgi-input [ messageType: cgi-input/parent-messageType messageID: cgi-input/parent-messageID ] post-comment-input: make cgi-input [ messageType: cgi-input/parent-messageID messageID: "none" ] post-comment-reverse-input: make cgi-input [ messageID: "none" messageType: parent-message-input/messageID parent-messageID: parent-message-input/messageID parent-messageType: parent-message-input/messageType ] display-messages/forum-style parent-message-input wait 1 display-messages/forum-style post-comment-input display-comment-form-forum post-comment-reverse-input ] "display" [ if error? try [display-messages/for-reading/for-commenting cgi-input][] ] "forum" [ if error? try [display-messages/forum-style cgi-input][] ] "search" [ searched-messages: search-messages cgi-input foreach searched-message searched-messages [ search-cgi-input: make cgi-input [ messageID: searched-message ] display-messages/for-reading/for-commenting search-cgi-input ] ] "search-forum" [ searched-messages: search-messages cgi-input foreach searched-message searched-messages [ search-cgi-input: make cgi-input [ messageID: searched-message ] display-messages/forum-style search-cgi-input ] ] "display-comments" [ reverse-input: make cgi-input [ messageID: "none" messageType: cgi-input/messageID parent-messageID: cgi-input/messageID parent-messageType: cgi-input/messageType ] display-messages/for-reading/for-commenting cgi-input if error? try [display-messages/for-reading/for-commenting reverse-input][] display-comment-form reverse-input ] "display-comments-edit" [ either (check-sessionID cgi-input/sessionID sessionID-timeout) [ reverse-input: make cgi-input [ messageID: "none" messageType: cgi-input/messageID parent-messageID: cgi-input/messageID parent-messageType: cgi-input/messageType ] display-messages/for-reading/for-commenting cgi-input if error? try [display-messages/for-editing reverse-input] [] ][ display-login-form cgi-input ] ] "display-comments-forum" [ reverse-input: make cgi-input [ messageID: "none" messageType: cgi-input/messageID parent-messageID: cgi-input/messageID parent-messageType: cgi-input/messageType ] display-messages/forum-style cgi-input if error? try [display-messages/forum-style reverse-input][] display-comment-form-forum reverse-input ] "edit-form" [ either (check-sessionID cgi-input/sessionID sessionID-timeout) [ display-messages/for-editing cgi-input ][ display-login-form cgi-input ] ] "edit" [ either (check-sessionID cgi-input/sessionID sessionID-timeout) [ edit-message cgi-input display-messages/for-editing default-input ][ display-login-form cgi-input ] ] "delete" [ either (check-sessionID cgi-input/sessionID sessionID-timeout) [ delete-message cgi-input display-messages/for-editing default-input ][ display-login-form cgi-input ] ] "display-login" [ display-login-form cgi-input ] "login" [ unencrypted-logins: decrypt read %logins.bin do unencrypted-logins login: make object! [ userID: cgi-input/userID password: cgi-input/password ] login-string: make string! logins either all [(find/any/case login-string login/userID) (find/any/case login-string login/password)][ cgi-input: make cgi-input [ sessionID: make decimal! time-in-digits now ] display-messages/for-editing cgi-input ][ display-login-form cgi-input ] ] ][ display-messages/for-reading/for-commenting default-input ] print { </BODY> </HTML> } ] encrypt-logins: func [ {Encrypt login usernames and passwords.} logins [string!] {A string containing the 'login word and a database of usernames and associated passwords.} ][ write/binary %logins.bin encrypt {logins:[["username1" "password1"] ["username2" "password2"]]} ] ;#################################################################### ;# # ;# BOHDAN LECHNOWSKY'S ENCRYPT.R # ;# # ;# REBOL [ # ;# Title: "En-/decryption Functions" # ;# Date: 20-Jul-1999 # ;# Author: "Bohdan Lechnowsky" # ;# File: %encrypt.r # ;# Purpose: "A basic encryption scheme." # ;# Usage: { # ;# Put the command: # ;# # ;# do %encrypt.r # ;# # ;# near the beginning of your %user.r file. Once # ;# it has been run, do the following: # ;# # ;# >> write/binary %pass.r encrypt "password-here" # ;# # ;# Whenever you need to assign that particular # ;# password, do the following (this example shows # ;# setting the default proxy password): # ;# # ;# system/schemes/default/proxy/pass: decrypt read %pass.r # ;# } # ;# Category: [file util 3] # ;# ] # ;# # ;#################################################################### hash: func [ "Returns a hash value for a string" string [string!] value [integer!] ][ (checksum string) // value ] encrypt: func [ "Encrypts a string" string [string!] /local shift-val codeword ][ codeword: "mycode" ;-- change as needed shift-val: hash codeword 8 if zero? shift-val [shift-val: 5] string: shift enbase/base compress string 2 shift-val to-string load append insert head string "2#{" "}" ] decrypt: func [ "Decrypts an encrypted string" string [string!] /local shift-val codeword ][ codeword: "mycode" ;-- change as needed shift-val: hash codeword 8 if zero? shift-val [shift-val: 5] string: shift/right enbase/base string 2 shift-val to-string decompress load append insert head string "2#{" "}" ] shift: func [ "Takes a base-2 binary string and shifts bits" data [string!] places [integer!] /left /right /local first-bits last-bits ][ if any [places < 1 places >= length? data] [ print "ERROR: Shift places exceeds length of binary data or is invalid" return none ] either right [ last-bits: copy/part tail data (places * -1) remove/part tail data (places * -1) data: head insert head data last-bits ][ first-bits: copy/part data places remove/part data places append data first-bits ] return data ] ;######################################## ;# PROGRAM # ;######################################## ; if error? try [ cgi-input: retrieve-user-data message-action-cgi cgi-input ;][ ; no-cgi-input: make object! [ ; actionType: "display" ; messageType: "news" ; messageID: "none" ; ] ; message-action-cgi no-cgi-input ;] Ryan C. Christiansen Web Developer Intellisol International 4733 Amber Valley Parkway Fargo, ND 58104 701-235-3390 ext. 6671 FAX: 701-235-9940 http://www.intellisol.com Global Leader in People Performance Software _____________________________________ Confidentiality Notice This message may contain privileged and confidential information. If you think, for any reason, that this message may have been addressed to you in error, you must not disseminate, copy or take any action in reliance on it, and we would ask you to notify us immediately by return email to [EMAIL PROTECTED] -- To unsubscribe from this list, please send an email to [EMAIL PROTECTED] with "unsubscribe" in the subject, without the quotes.
