# Copyright (C) 2004  Melissa K. Schrumpf
# 
# This software may be distributed freely, provided that it is
# distributed in its entirety, without modifications, and with
# the original copyright notice and license included.
# 
# You may distribute your own separate patches together with
# this software package or a modified package if you always
# include a pointer where to get the original unmodified package.
# In this case you must inform the author about the modified package.
# 
# The software may not be sold for profit or as "hidden" part of 
# another software, but it may be included with collections 
# of other free software, such as CD-ROM images of FTP servers
# and similar, provided that this software is not a significant part 
# of that collection.  In this case you must inform the author of the
# method of distribution.
# 
# Pre-compiled binaries of this software may be distributed in the
# same way, provided that this copyright notice and license is
# included without modification.
# 
# This software may be used freely, for personal and non-profit
# use, provided that the original author is always credited.  If you
# intend to use this software as a significant part of business
# (for-profit) activities, the author's permission is required.  Also,
# any usage that is not covered by this license requires the explicit
# permission of the author.
# 
# This software is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
# 
# 
# 
foreach i [concat . [split [lindex [array get env \
	\[Pp\]\[Aa\]\[Tt\]\[Hh\]] 1] \;]] {
	if {[file readable $i/stdlib.tcl]} {
		puts "include: $i/stdlib.tcl"
		if {![catch {
			source $i/stdlib.tcl
			_runHow
		}]} {break}
	}
}




# SaveAs P:\\ath Type
#	Types:
#	olDoc = 4
#	olHTML = 5
#	ollCal = 8
#	olMSG = 3
#	olRTF = 1
#	olTemplate = 2
#	olTXT = 0
#	olVCal = 7
#	olVCard = 6

# Classes
# 
#   olApplication = 0
#   olNamespace = 1
#   olFolder = 2
#   olRecipient = 4
#   olAttachment = 5
#   olAddressList = 7
#   olAddressEntry = 8
#   olFolders = 15
#   olItems = 16
#   olRecipients = 17
#   olAttachments = 18
#   olAddressLists = 20
#   olAddressEntries = 21
#   olAppointment = 26
#   olMeetingRequest = 53
#   olMeetingCancellation = 54
#   olMeetingResponseNegative = 55
#   olMeetingResponsePositive = 56
#   olMeetingResponseTentative = 57
#   olRecurrencePattern = 28
#   olExceptions = 29
#   olException = 30
#   olAction = 32
#   olActions = 33
#   olExplorer = 34
#   olInspector = 35
#   olPages = 36
#   olFormDescription = 37
#   olUserProperties = 38
#   olUserProperty = 39
#   olContact = 40
#   olDocument = 41
#   olJournal = 42
#   olMail = 43
#   olNote = 44
#   olPost = 45
#   olReport = 46
#   olRemote = 47
#   olTask = 48
#   olTaskRequest = 49
#   olTaskRequestUpdate = 50
#   olTaskRequestAccept = 51
#   olTaskRequestDecline = 52
#   olExplorers = 60
#   olInspectors = 61
#   olPanes = 62
#   olOutlookBarPane = 63
#   olOutlookBarStorage = 64
#   olOutlookBarGroups = 65
#   olOutlookBarGroup = 66
#   olOutlookBarShortcuts = 67
#   olOutlookBarShortcut = 68
#   olDistributionList = 69
#   olPropertyPageSite = 70
#   olPropertyPages = 71
#   olSyncObject = 72
#   olSyncObjects = 73
#   olSelection = 74
#   olLink = 75
#   olLinks = 76
#   olSearch = 77
#   olResults = 78
#   olViews = 79
#   olView = 80
#   olItemProperties = 98
#   olItemProperty = 99
#   olReminders = 100
#   olReminder = 101
# 
# 
# Attachment Types:
# 	olByReference = 4
# 	olByValue = 1
# 	olEmbeddeditem = 5
# 	olOLE = 6
#



proc subchar {str} {
	regsub -all -- {[\\/:\"*?<>|\t]} $str - str
	return $str
}

proc getFormat {itm} {
	set ifmt 0; # default assumption is "Unspecified, defaults to text.
	catch {
		# nuance: need to get the message item into an inspector
		# before BodyFormat will return anything other than 0.
		# also, must close the inspector (1 = discard changes)
		set iinsp [$itm GetInspector]; # returns an OBJECT

		# get the format
		set ifmt [$itm BodyFormat]; # returns an int

		# we must close the Inspector, otherwise we'll run out:
		$iinsp Close 1
		unset iinsp; # release OBJECT

		# an alternate method would be to retrieve the HTML body
		# and parse it for "Converted from" strings:
		# <!-- Converted from text/plain format -->
		# <!-- Converted from text/rtf format -->

		# this is, under most circumstances, actually faster than
		# the GetInspector method.  However, it is less accurate,
		# in that the message may have, at one time, been in text/plain
		# or RTF format, and have been converted to HTML in a Fwd or
		# Re, quoting the OLD conversion text, and not reflecting the
		# current format.  to avoid this, we look for lines
		# containing the conversion tag EXCLUSIVELY.  still, better
		# a little slower than less accurate...

		#set ibod [$itm HTMLBody]
		#set ifmt 2
		#foreach lstr [split $ibod \n] {
		#	set lstr [string trim $lstr]
		#	if {[regexp {^[<][!]-- Converted from text/plain format --[>]$} $lstr]} {
		#		set ifmt 1
		#		break
		#	} elseif {[regexp {^[<][!]-- Converted from text/rtf format --[>]$} $lstr]} {
		#		set ifmt 3
		#		break
		#	}
		#}

		set bftyp "Unknown"
		switch -exact -- $ifmt {
			0 {set bftyp "Unspecified"}
			1 {set bftyp "Text"}
			2 {set bftyp "HTML"}
			3 {set bftyp "RichText"}
		}
		logstr "$indstr         Fmt:  ($ifmt) $bftyp"
	}

	return $ifmt
}

proc safeAndUniqueSubject {isubj itemsubs} {
	set apn 0
	set isubj [subchar $isubj]
	set isubj [string trim $isubj]
	if {$isubj==""} {set isubj "(No Subject)"}
	set fsubj $isubj
	while {[lsearch $itemsubs $fsubj]!=-1} {
		incr apn
		set fsubj "$isubj ($apn)"
	}
	return $fsubj
}

proc processAnItem {itm itemcount indstr fspath i} {
		upvar 1 itemsubs itemsubs
		# log some header data
		logstr "$indstr       Item ($i/$itemcount):"
		catch {
			set isubj [$itm Subject]; # returns a string
			logstr "$indstr         Subj:  $isubj"
		}
		catch {
			set ifrom [$itm SenderName]; # returns a string
			logstr "$indstr         From:  $ifrom"
		}
		catch {
			set ito [$itm To]; # returns a string
			if {[string length $ito]>64} {set ito [string range $ito 0 63]}
			logstr "$indstr         To:    $ito"
		}
		catch {
			set isz [$itm Size]; # returns an int
			logstr "$indstr         Size:  $isz"
		}
		catch {
			set iclass [$itm Class]; # returns a string
			logstr "$indstr         Class: $iclass"
		}

		# in order to save the message properly, we need to know its format
		set ifmt [getFormat $itm]

		# get a filesystem-safe and unique subject name
		set fsubj [safeAndUniqueSubject $isubj $itemsubs]
		
		set nl [string length $fsubj]
		if {$nl>$::maxnamelen} {
			set tmp0 [string range $fsubj 0 [expr $::maxnamelen/2]]
			set tmp1 [string range $fsubj end-[expr ($::maxnamelen/2)-3] end]
			set fsubj "$tmp0...$tmp1"
		}

		# remember it, so it isn't reused later
		lappend itemsubs $fsubj

		# get attachments
		catch {
			set iaobj [$itm Attachments]; # returns an OBJECT
			set iacount [$iaobj Count]; # returns an int

			if {$iacount>0} {
				logstr "$indstr         Attachments: ($iacount)"
				logstr "$indstr           makeDir $fspath\\\\$fsubj"
				makeDir $fspath\\\\$fsubj

				set anaml {}; # attachment name list (for uniqueness)

				for {set j 1} {$j<=$iacount} {incr j} {; # loop on attachments
					set aobj [$iaobj Item $j]; # returns an OBJECT

					if {[catch {set aonam [$aobj FileName]} res]} {
						set tmp0 "Cannot stat Attachment FileName"
						set tmp1 "($fspath\\\\$fsubj)"
						logstr "$indstr           $tmp0 $tmp1"
						#puts stderr "$indstr           $tmp0 $tmp1"
						set aonam Attachment
					} else {
						logstr "$indstr           Name:  $aonam"
					}

					# TODO what to do about attachments?
					# attachments might be in outlook message
					# format, and will then be saved as such.
					# that's not very good!
					# save filesystem path to a global list
					# when done, walk the list, having outlook
					# open the item, export it, and close it

					# determine a unique attachment name
					set apn 0

					set nl [string length $aonam]
					if {$nl>$::maxnamelen} {
						set tmp0 [string range $aonam 0 [expr $::maxnamelen/2]]
						set tmp1 [string range $aonam end-[expr ($::maxnamelen/)-3] end]
						set aonam "$tmp0...$tmp1"
					}

					set faonam [subchar $aonam]
					while {[lsearch $anaml $faonam]!=-1} {
						incr apn
						set faonam "$aonam ($apn)"
					}
					lappend anaml $faonam; # don't reuse attachment names
					set destpath "$fspath\\\\$fsubj\\\\$faonam"

					logstr "$indstr           SaveAsFile $destpath"
#set ::status $destpath; update
					if {[catch {$aobj SaveAsFile $destpath} res]} {
						set tmp0 "Cannot save Attachment '$faonam'"
						set tmp1 "($fspath\\\\$fsubj)"
						logstr "$indstr           $tmp0 $tmp1"
						#puts stderr "$indstr           $tmp0 $tmp1"
						set ifmt 3; # if attachment save failed,
						# force the message to be saved as RTF.
					} else {
						if {[regexp {.msg$} $destpath]} {
							lappend ::attachments $destpath
						}
					}
					unset aobj; # release OBJECT

					# remove empty directories: if the attachment save
					# failed and we're saving it as an RTF, check the
					# directory.  if it's empty, remove it.
					set attl [glob -nocomplain $fspath\\\\$fsubj\\\\*]
					if {$attl=={}} {catch {file delete $fspath\\\\$fsubj}}
				}
			}
			update
		}
		catch {unset iaobj; # release OBJECT}

		# save the item -- TODO don't like the fact that the SaveAs's
		# are completely wrapped in catch {} statements
#set ::status $fspath\\\\$fsubj; update
		switch -exact -- $iclass {
			26 {-}
			48 {
				# 26 = calendar, 48 = task
				set full_fs_path "$fspath\\\\$fsubj.txt"
				set file_type 0
				logstr "$indstr           SaveAs $full_fs_path"
				catch {$itm SaveAs $full_fs_path $file_type}
				set full_fs_path "$fspath\\\\$fsubj.rtf"
				set file_type 1
				logstr "$indstr           SaveAs $full_fs_path"
				catch {$itm SaveAs $full_fs_path $file_type}
				set full_fs_path "$fspath\\\\$fsubj.vcs"
				set file_type 7
				logstr "$indstr           SaveAs $full_fs_path"
				catch { $itm SaveAs $full_fs_path $file_type}
			}
			40 {
				# contact
				set full_fs_path "$fspath\\\\$fsubj.txt"
				set file_type 0
				logstr "$indstr           SaveAs $full_fs_path"
				catch {$itm SaveAs $full_fs_path $file_type}
				set full_fs_path "$fspath\\\\$fsubj.rtf"
				set file_type 1
				logstr "$indstr           SaveAs $full_fs_path"
				catch {$itm SaveAs $full_fs_path $file_type}
				set full_fs_path "$fspath\\\\$fsubj.vcf"
				set file_type 6
				logstr "$indstr           SaveAs $full_fs_path"
				catch {$itm SaveAs $full_fs_path $file_type}
			}
			default {
				# everything else, including mail items and notes
				switch -exact -- $ifmt {
					2 {
						set full_fs_path "$fspath\\\\$fsubj.html"
						set file_type 5
					}
					3 {
						set full_fs_path "$fspath\\\\$fsubj.rtf"
						set file_type 1
					}
					default {
						set full_fs_path "$fspath\\\\$fsubj.txt"
						set file_type 0
					}
				}
				logstr "$indstr           SaveAs $full_fs_path"
				catch {$itm SaveAs $full_fs_path $file_type}
			}
		}
}

proc processItems {iobjs itemcount indstr fspath} {
	if {!$::doSave} {return}

	# a list of item names, to prevent saving over duplicates
	set itemsubs {}
	
	initProgBar .c
	
	for {set i 1} {$i<=$itemcount} {incr i} {

		progBar .c [expr 1.0*$i/$itemcount] "$fspath ($i/$itemcount)"
		incr ::prognow
		progBar .c2 [expr 1.0*$::prognow/$::totprog] \
			"$::progging ($::prognow/$::totprog)"

		set itm [$iobjs Item $i]; # returns an OBJECT

		processAnItem $itm $itemcount $indstr $fspath $i

		unset itm; # release OBJECT

		logstr ""
	}

	unProgBar .c
}

proc tallyItems {tren icount} {
	set tlist [lrange [split $tren /] 1 end]
	set tpat ""
	foreach i $tlist {
		set tpat "$tpat/$i"
		set ::countitems($tpat) [expr $::countitems($tpat) + $icount]
		#puts $tpat\t$::countitems($tpat)
	}
}

proc ttShow {widg x y msg} {
	incr x 8
	incr y 8
	set win .tooltip
	if {![winfo exists $win]} {
		ttCancelAll
		toplevel $win
		wm overrideredirect $win 1
		bind $win <FocusOut> "focus -force $win"
		label $win\.l -text $msg -justify l -background red \
			-foreground black -padx 3 -pady 3 -relief sunken
		pack $win\.l -side top -anchor nw -expand true -fill both
		wm state $win withdrawn
		update
		set rootw [winfo screenwidth .]
		set rooth [winfo screenheight .]
		set tiprw [winfo reqwidth $win]
		set tiprh [winfo reqheight $win]
		if {[expr $x+$tiprw]>$rootw} {set x [expr $rootw - ($tiprw+8)]}
		if {[expr $y+$tiprh]>$rooth} {set y [expr $rooth - ($tiprh+8)]}
		wm state $win normal
		wm geometry $win +$x+$y
		after 5000 "ttHide $widg"
	}
}

proc ttHide {widg} {
	if {[winfo exists .tooltip]} {
		destroy .tooltip
	}
	ttCancelAll
}

proc ttCancelAll {} {
	foreach i [after info] {
		set ainfo [after info $i]
		if {[lindex $ainfo 1]!="timer"} {continue}
		if {[regexp "ttHide" [lindex $ainfo 0]]} {
			after cancel $i
		}
		if {[regexp "ttShow" [lindex $ainfo 0]]} {
			after cancel $i
		}
	}
}

proc processFolder {fobj fspath indstr tren} {
	# fobj is a tcom object to a single folder
	# fspath is the filesystem path to the parent folder
	# indstr is the "indent string" for logging

	set ::fobs($tren) $fobj
	set ::fpat($tren) $fspath

	# get general information about the folder object
	set fname [$fobj Name]; # returns a string
	set ffpath [$fobj FullFolderPath]; # returns a string

	# the "filesystem-safe" name contains none of the restricted chars
	set fname_safe [subchar $fname]
	set fssubpath_safe $fspath\\\\$fname_safe
	makeDir $fssubpath_safe

	# update the status window and console logging
	puts "$indstr  $fname"
	#set ::status $ffpath; update

	# get the subfolders object and count
	set subfolds [$fobj Folders]; # returns an OBJECT
	set subfoldcount [$subfolds Count]; # returns a string
	
	# get the items object and count
	set iobjs [$fobj Items]; # returns an OBJECT
	set itemcount [$iobjs Count]; # returns a string

	if {!$::doSave} {tallyItems $tren $itemcount}

	# log the information we have collected
	logstr "$indstr Name:   $fname"
	logstr "$indstr   Path: $ffpath"
	logstr "$indstr   FS:   $fspath"
	logstr "$indstr   # Subfolders: $subfoldcount"
	logstr "$indstr   # Items: $itemcount"
	flush $::fid

	# process the items.  if there are any, log a header:
	if {$itemcount>0} {
		logstr "\n$indstr     Items ($itemcount):"
	}

	processItems $iobjs $itemcount $indstr $fssubpath_safe

	unset iobjs; # release OBJECT
	flush $::fid

	if {$subfoldcount>0} {logstr "\n$indstr     Subfolders ($subfoldcount):"}

	for {set i 1} {$i<=$subfoldcount} {incr i} {
		set sf [$subfolds Item $i]; # returns an OBJECT
		set sfname [$sf Name]; # returns a string
		
		set sfnamesafe [subchar $sfname]

		logstr "$indstr       makeDir $fssubpath_safe"

		set trennew "$tren/$sfnamesafe"
		regsub -all " " $trennew "_" trennew
		
		if {!$::doSave} {
			Tree:newitem .f.w $trennew -image idir
			set ::countitems($trennew) 0
			update
		}
		
		processFolder $sf $fssubpath_safe "      $indstr" $trennew

		unset sf; # release OBJECT
	}
	#unset subfolds; # release OBJECT
	flush $::fid

}
proc logstr {str} {
	if {!$::doSave} {return}
	puts $::fid $str
}

proc makeDir {path} {
	if {!$::doSave} {return}
	set dlist [file split $path]
	set drv [lindex $dlist 0]
	set subs [lrange $dlist 1 end]
	set mkpath "$drv"
	foreach i $subs {
		set mkpath "$mkpath/$i"
		if {![file isdirectory $mkpath]} {file mkdir $mkpath}
	}
}

proc doProcF {lbl} {
	if {$::exp} {
		tk_dialog .inprog "Busy" "Busy exporting another dir.  Please try again later." "" 0 ok
		return
	}
	set ::exp 1
	.b configure -state disabled
	update
	initProgBar .c2
	set ::totprog $::countitems($lbl)
	set ::prognow 0
	set ::progging $lbl
	set ::status processing...
	puts "$lbl processing..."
	update
	set fslab [subchar $lbl]
	set ::fid [open $fslab-export-log.txt w+]
	processFolder $::fobs($lbl) $::fpat($lbl) "" "$lbl"
	close $::fid
	set ::status done
	puts "$lbl done"
	unProgBar .c2
	update
	set ::exp 0
	if {[llength $::attachments]>0} {.b configure -state normal}
	update
}

proc ttEnter {x y X Y} {
	catch {
		set lbl [Tree:labelat .f.w $x $y]
		after 1000 "ttShow .f.w $X $Y \"$lbl ($::countitems($lbl))\""
	}
}

proc ttLeave {x y} {ttHide .f.w}

proc postMenu {x y} {
	global Tree
	catch {
		set lbl [Tree:labelat .f.w $x $y]
		Tree:setselection .f.w $lbl

		if {[winfo exists .f.w.m]} {destroy .f.w.m}
		menu .f.w.m
	
		.f.w.m add command -label "Export $lbl" \
			-command "doProcF \"$lbl\""
		.f.w.m post [winfo pointerx .] [winfo pointery .]
	}
}

proc initProgBar {w} {
	$w create rect 0 0 255 15 -outline black
}

proc progBar {w pcnt str} {
	$w delete progb
	$w delete stringtag
	set pb [$w create rect 1 1 [expr 254*$pcnt] 14\
		-fill blue -outline blue]
	$w addtag progb withtag $pb
	set h [$w create text 264 7 -text $str -justify left -anchor w]
	$w addtag stringtag withtag $h
	update
}

proc unProgBar {w} {
	$w delete all
}



	

proc processFileSystemAttachments {} {
	set myfid [open atta-tmp.txt w+]
	puts $myfid "set ::attachments {}"
	foreach i $::attachments {
		regsub -all -- {\\} $i {\\\\} i
		puts $myfid "lappend ::attachments \"$i\""
	}
	close $myfid
	puts "processing attachments..."
	set ::status "processing attachments..."
	.b configure -state disabled
	update
	# use ActiveWindow.Close until all windows are closed, then proceed...
	set insp "-"
	while {$insp!=""} {
		catch {$insp Close 1}
		catch {$insp Close}
		update
		set insp [$::com(ol) ActiveWindow]
	}
	set ::fid [open attach_conv_log.txt w+]
	initProgBar .c

	set concnt 0
	set errcnt 0
	
	while {[llength $::attachments]>0} {
		set atta $::attachments
		set ::attachments {}
		set attn [llength $atta]
		set n 0
	 	foreach i $atta {
			incr n
			progBar .c [expr 1.0*$n/$attn] "($n/$attn)"
			puts "  processing $i..."
			set ::status "  processing $i..."
			update

			set bfid [open $i r]
			fconfigure $bfid -translation binary
			set fc [read $bfid 9]
			close $bfid
			set v ""
			binary scan $fc H* v
			if {$v!="d0cf11e0a1b11ae100"} {
				puts $::fid "does not appear to be an msg file: $i"
				puts stderr "does not appear to be an msg file: $i"
				incr errcnt
				continue
			}
 			if {[catch {exec cmd.exe /c start "" $i}]} {
				puts $::fid "failed to open for conversion: $i"
				puts stderr "failed to open for conversion: $i"
				incr errcnt
				continue
			}
			set insp ""
			while {$insp==""} {set insp [$::com(ol) ActiveWindow]}

			if {[catch {set curi [$insp CurrentItem]}]} {
				puts $::fid "failed to open for conversion: $i"
				puts stderr "failed to open for conversion: $i"

				catch {$insp Close 1}
				catch {$insp Close}

				incr errcnt
				continue
			}

			set fspath [file dirname $i]
			regsub -all -- {/} $fspath {\\\\} fspath
			set itemsubs {}
			processAnItem $curi 1 "" $fspath 1
			$curi Close 1
			unset curi
			catch {$insp Close 1}
			catch {$insp Close}
			incr concnt
		}
	}
	unProgBar .c
	puts $::fid "\n\n$concnt attachments converted"
	puts $::fid "$errcnt attachments skipped\n"
	tk_dialog .tot "Tally" "$concnt attachments converted\n$errcnt attachments skipped" "" 0 ok
	close $::fid
	puts "process attachments done"
	set ::status done
	update
}

########################################################################
########################################################################
########################################################################


set expdir "D:\\test-email-export"

catch {console show}

wm title . "Outlook Export"

wm geom . 640x480

label .l -text "Export Outlook Folders to the Filesysem at:\n$expdir"
label .st -textvariable ::status
button .b -text "Recurse & convert *.msg attachments" \
	-command processFileSystemAttachments -state disabled
canvas .c -height 16 -width 256 -highlightthickness 0
canvas .c2 -height 16 -width 256 -highlightthickness 0
pack .l .b .c .c2 .st -side top -expand false -fill x
set ::status ""
update

package require tcom


source tree-procs.tcl

frame .f -bg white
pack .f -fill both -expand 1

Tree:create .f.w -yscrollcommand {.f.sb set}
scrollbar .f.sb -orient vertical -command {.f.w yview}
pack .f.w -side left -fill both -expand true -padx 5 -pady 5
pack .f.sb -side left -fill y

image create photo idir -data {
    R0lGODdhEAAQAPIAAAAAAHh4eLi4uPj4APj4+P///wAAAAAAACwAAAAAEAAQAAADPVi63P4w
    LkKCtTTnUsXwQqBtAfh910UU4ugGAEucpgnLNY3Gop7folwNOBOeiEYQ0acDpp6pGAFArVqt
    hQQAO///
}
image create photo ifile -data {
    R0lGODdhEAAQAPIAAAAAAHh4eLi4uPj4+P///wAAAAAAAAAAACwAAAAAEAAQAAADPkixzPOD
    yADrWE8qC8WN0+BZAmBq1GMOqwigXFXCrGk/cxjjr27fLtout6n9eMIYMTXsFZsogXRKJf6u
    P0kCADv/
}

set ::attachments {}
set ::exp 0

set ::totprog 0
set ::prognow 0
set ::progging ""

set ::fobs(0) ""
set ::fpat(0) ""

set ::maxnamelen 50


.f.w bind x <1> {
	set lbl [Tree:labelat %W %x %y]
	Tree:setselection %W $lbl
}

.f.w bind x <Double-1> {
	if {$Tree(.f.w:[Tree:labelat %W %x %y]:open)} {
		Tree:close %W [Tree:labelat %W %x %y]
	} else {
		Tree:open %W [Tree:labelat %W %x %y]
	}
}

.f.w bind x <2> {postMenu %x %y}
.f.w bind x <3> {postMenu %x %y}

.f.w bind x <Enter> {ttEnter %x %y %X %Y}
.f.w bind x <Leave> {ttLeave %x %y}

regsub -all {\\} $expdir {\\\\} expdirl

after 1 {
	set ::doSave 0
	# make filesystem main directory
	if {![file isdirectory $expdir]} {makeDir $expdir}

	#set ::com(ol) [::tcom::ref createobject "Outlook.Application"]
	set ::com(ol) [::tcom::ref createobject "Outlook.Application.11"]
	set ::com(ol,session) [$::com(ol) Session]
	set ::com(ol,sess,folders) [$::com(ol,session) Folders]
	set fcount [$::com(ol,sess,folders) Count]

	set fid stdout
	for {set i 1} {$i<=$fcount} {incr i} {
		set cfold [$::com(ol,sess,folders) Item $i]; # returns an OBJECT

		set fname [$cfold Name]
		set ffpath [$cfold FullFolderPath]; # returns a string
		if {$fname=="Public Folders"} {continue}

		set tren [subchar $fname]
		regsub -all " " $tren "_" tren
		Tree:newitem .f.w /$tren -image idir
		update

		set doExport [tk_dialog .ask "Map" "Build Export Map of '$fname'?" "" 0 No Yes]

		if {!$doExport} {continue}

		puts $fname
		set ::status $fname; update

		set ::countitems(/$tren) 0
		processFolder $cfold $expdirl "" /$tren
		puts "$fname done"
		set ::status "$fname done"
		update

		unset cfold; # release OBJECT
	}
	set ::doSave 1
}




