[MJ] - While contemplating ideas to use Tcl and [tcom] as a Getting Things Done frontend with all the data in Outlook, it occured to me that it's fairly trivial to build a basic wiki which stores the pages as Outlook notes. The code below is an initial version. A [starpack] can be downloaded from [http://mpc-soft.nl/files/owiki.nl], this starpack contains a sample css file and a file with all the outlook constants. This version is probably not very efficient and it is missing search, which is an essential part of any wiki. But it does allow wiki syntax in your Outlook notes and displaying it in a browser with links between the notes. Note that it requires the Redemption COM server [http://www.dimastr.com/redemption/] for bypassing outlook security pop-ups. However if you don't mind the popups, changing the store to use Application.Outlook instead is trivial. Just change: set rdo [tcom::ref createobject "Redemption.RDOSession"] $rdo Logon set notesFolder [$rdo GetDefaultFolder $c(OlFolderNotes)] to set rdo [tcom::ref createobject "Outlook.Application"] set notesFolder [[$rdo GetNamespace "MAPI] GetDefaultFolder $c(OlFolderNotes)] Current todos are: * Adding search, probably naive search at first (will be slow) and later maybe use outlook support for search folders to speed it up. * More extensive formatting * Efficiency improvements (caching?) * Clean up web server part or use some existing server ([Wub]?) * Add error checking :-) Code for the application: package require tcom package require snit set appdir [pwd] proc decodeUrl data { regsub -all {\+} $data { } data regsub -all {([][$\\])} $data {\\\1} data regsub -all {%([0-9a-fA-F][0-9a-fA-F])} $data {[format %c 0x\1]} data set data [subst $data] } snit::type WikiPage { option -id option -title option -body option -lastupdate variable header variable footer variable raw constructor args { $self configurelist $args set header [list "'[$self cget -title]"] lappend header "\[Homepage | /\] |" lappend header "\[Today | [clock format [clock seconds] -format {/view/Logbook_%Y_%m_%d}]\]" lappend header "----" set footer [list ----] lappend footer "\[Edit | /edit/[$self cget -title]\]" lappend footer "
" lappend footer "" lappend footer "" lappend footer "
" } method id {} { $self cget -id } method asHTML {} { set result {} set raw [list {*}$header {*}[$self cget -body] {*}$footer] set inUL 0 foreach line $raw { set line [regsub -all {\[(.*?) \| (.*?)\]} $line {\1}] set line [regsub -all {\[(.*?)\]} $line {\1}] if {[string trimright $line] eq "----"} { set line "
" } if {[regexp {^('+)(.*)$} $line -> ticks text]} { set numTicks [string length $ticks] set line "$text" } if {$line eq {}} { set line "

" } if {[string index $line 0] eq {*}} { if {!$inUL} { lappend result

set inUL 0 } lappend result $line } join $result \r\n } } #========================================= snit::type OutlookStore { # Outlook by default creates notes where the Body has the Subject # as first line unless the title is not unique. # Hence the Subject field is used to identify the page typevariable c typevariable rdo typevariable notesFolder typeconstructor { set constantsFile [open [file join $::appdir constants.txt]] foreach line [split [read $constantsFile] \n] { set c([lindex $line 0]) [lindex $line 1] } close $constantsFile set rdo [tcom::ref createobject "Redemption.RDOSession"] $rdo Logon set notesFolder [$rdo GetDefaultFolder $c(OlFolderNotes)] } method getPage {title} { tcom::foreach note [$notesFolder Items] { if {$title eq [string trim [$note Subject]]} { return [list [lrange [split [string map [list \r {}] [$note Body]] \n] 1 end] $note] } } return "{} 0" } method savePage {title body} { lassign [$self getPage $title] _ id if {$id != 0} { $id Body $title\r\n$body } else { set id [[$notesFolder Items] Add] $id Subject $title $id Body $title\r\n$body } $id Save } } #========================================= snit::type Server { option -port 5151 option -store variable socket variable css constructor args { $self configurelist $args set cssFile [open [file join $::appdir wiki.css]] set css [read $cssFile] close $cssFile set socket [socket -server [list $self handle] [$self cget -port]] } method handle {chan add port} { fconfigure $chan -translation crlf -buffering line set request [string trimleft [lindex [gets $chan] 1] /] lassign [split $request /] action page set page [decodeUrl $page] if {$action eq {}} { set action view set page HomePage } puts "Action: $action for page: $page" switch $action { view { puts $chan "HTTP/1.0 200 OK" puts $chan "Content-Type: text/html" puts $chan "" puts $chan [$self viewPage $page] } edit { puts $chan "HTTP/1.0 200 OK" puts $chan "Content-Type: text/html" puts $chan "" lassign [[$self cget -store] getPage $page] content id puts $content set content [join $content \n] puts $chan "Edit $page" puts $chan "

Edit $page

" puts $chan "
" puts $chan "" puts $chan "
" } save { # assume save while {[gets $chan line]!=-1} { lassign [split $line :] key val puts "$key: $val" if {$key eq "Content-Length"} { set length [string trim $val] incr length break } } set request [read $chan $length] set data [join [lrange [split $request =] 1 end] =] set data [decodeUrl $data] set store [$self cget -store] $store savePage $page $data # redirect to page puts $chan "HTTP/1.1 303 See other" puts $chan "Location: /view/$page" puts $chan "" } css { puts $chan "HTTP/1.0 200 OK" puts $chan "Content-Type: text/html" puts $chan "" puts $chan $css } default { puts $chan "HTTP/1.0 200 OK" puts $chan "Content-Type: text/html" puts $chan "" puts $chan "

Unsupported request: $request

" puts stderr "Unsupported request: $request" } } close $chan } method viewPage page { set store [$self cget -store] lassign [$store getPage $page] body id set view [WikiPage %AUTO% -title $page -body $body -id $id] set body [$view asHTML] $view destroy set result " $page $body " } } OutlookStore store Server %AUTO% -store store vwait forever ---- !!!!!! %| enter categories here |% !!!!!!