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 [L1 ], 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 [L2 ] 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:
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 "<form method='get' action=\"/cmd/search\">" lappend footer "<input type =\"text\" name=text size=20>" lappend footer "<input type=\"hidden\" name=\"show\" value=1>" lappend footer "<input type=\"submit\" value =\"Find\"></form>" } 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 {<a href='\2'>\1</A>}] set line [regsub -all {\[(.*?)\]} $line {<a href='/view/\1'>\1</A>}] if {[string trimright $line] eq "----"} { set line "<hr/>" } if {[regexp {^('+)(.*)$} $line -> ticks text]} { set numTicks [string length $ticks] set line "<h$numTicks>$text</h$numTicks>" } if {$line eq {}} { set line "<p>" } if {[string index $line 0] eq {*}} { if {!$inUL} { lappend result <ul> set inUL 1 } set line <li>[string range $line 1 end]</li> } elseif {$inUL} { lappend result </ul> 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 "<HTML><HEAD><TITLE>Edit $page</TITLE><LINK REL=\"stylesheet\" HREF=\"/css/wiki\">" puts $chan "</HEAD><BODY BGCOLOR=\"#FFF8F8\"><H1>Edit $page</H1>" puts $chan "<form method=\"post\" action=\"/save/$page\">" puts $chan "<textarea name='content' cols=80 rows=30>$content</textarea>" puts $chan "<BR><input type=\"submit\" value='Save'></form> </BODY></HTML>" } 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 "<h1>Unsupported request: $request</h1>" 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 " <html> <title>$page</title> <head> <link rel=\"stylesheet\" href=\"/css/wiki\" type=\"text/css\" /> </head> <body> $body </body> </html> " } } OutlookStore store Server %AUTO% -store store vwait forever