This page provides examples of how to read and write a Microsoft Outlook document using the Tcom package. See How one discovers the API for a COM-exporting application for more help on finding Outlook commands.
package require tcom
proc ConvertTime {t} {
regexp {([+-])(\d\d)(\d\d)} [clock format [clock seconds] -format %z] m sign hours minutes
set tlocal [expr "$t $sign ($hours *60 +$minutes)*60"]
return [expr {(25569+$tlocal/24/3600)+(($tlocal%(24*3600))/(24.0*3600))}]
}
set outlook [::tcom::ref getactiveobject Outlook.Application]
set app [$outlook Application]
set entry [$app CreateItem [expr 1]]
$entry Subject "This is the subject"
$entry Start [ConvertTime [clock scan {2009-02-13 21:00}]]
$entry End [ConvertTime [clock scan {2009-02-13 21:30}]]
$entry SaveJaf:A Small Outlook Calendar Clien/Server Pair I used these to query my appointments from my UNIX machine, I tend to miss meetings while working on a Unix station.
This could help finish the work on A Calendar Widget, see Future Feature discussion.
First the Server:
proc msdate_to_iso {val} {
set base_ticks [clock scan 20000101]
set base_offset 36526;# days since 31. Dec 1899, ARRRGGHHHHH
set offset [expr {int($val)-$base_offset}]
set clkdate [clock scan "$offset days" -base $base_ticks]
set isodate [clock format $clkdate -format %Y%m%d]
set fhours [expr {24.0*($val-int($val))}]
set hours [expr {int($fhours)}]
set mins [expr {int(($fhours-$hours)*60)}]
return "$isodate $hours:$mins"
}
proc get_appointments {startdate enddate} {
# set up search scope
set w_startdate \
[clock format [clock scan "${startdate}T000000"] -format "'%d/%m/%Y'"]
set w_enddate \
[clock format [clock scan "${enddate}T000000"] -format "'%d/%m/%Y'"]
set restriction "\[Start\] <= $w_enddate AND \[End\] >= $w_startdate"
# tcom stuff
if {[catch {::tcom::ref getactiveobject Outlook.Application} outlook]} {
return {}
}
set app [$outlook Application]
set session [$app Session]
$session Logon
set calitems [$session GetDefaultFolder 9]
set calendar [$calitems Items]
$calendar IncludeRecurrences 1
$calendar Sort "\[Start\]"
set wanted [$calendar Restrict $restriction]
$wanted Sort "\[Start\]"
# make list out of the returned data
set retlist {}
::tcom::foreach ent $wanted {
lappend retlist [list "Start" [msdate_to_iso [$ent Start]] \
"End" [msdate_to_iso [$ent End]] \
"Subject" [$ent Subject] \
"Location" [$ent Location] \
"Categories" [$ent Categories]]
}
puts "returning [llength $retlist] items"
return $retlist
}
proc process {chan addr port} {
# if nothing there
if {[eof $chan]} { close $chan; return }
# buffering to lines to accomodate puts/gets on the other side
fconfigure $chan -buffering line
# retrieve message
set mess [gets $chan]
# report message
puts "$addr:$port \@ $chan tells me \"$mess\""
# remove extra blanks
set mess_clean [string trim [regsub -all -- { +} $mess { }]]
# retrieve command and argument
set mesg_list [split $mess_clean { }]
set command [lindex $mesg_list 0]
set startdate [lindex $mesg_list 1]
set enddate [lindex $mesg_list 2]
# react
switch -exact -- $command {
"get_appointments" { puts $chan [$command $startdate $enddate] }
default {
puts $chan "Only \"get_appointments\" allowed"
puts "erroneous command: $command"
}
}
close $chan
}
package require tcom
set listen [socket -server process 3456]
vwait forever The client is trivially simple:
set ipserver "mypcname_or_inetaddress_here"; # put PC name or address here
set ipport "3456" ; # big (> 1024) port here
proc get_appointments {startdate enddate} {
set channel [socket $::ipserver $::ipport]
fconfigure $channel -buffering line
puts $channel "get_appointments $startdate $enddate"
gets $channel retval
close $channel
return $retval
}By the way: Does anybody know why Microsoft chose to format dates as floats (apart from the fact that they might have wanted to do something different than Unix)?
An integer part counting the days since 31 Dec 1899 (Day 0) while the fractional part represents the fraction of the day that elapsed is kind of odd. Or is there a hiden benefit I'm not aware of?
Cheers, Jaf.