# $Id: logger.tcl 2122 2014-01-30 10:29:02Z sergei $

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

namespace eval ::logger {
    custom::defgroup Logging [::msgcat::mc "Logging options."] -group Chat

    custom::defvar options(logdir) [file join $::configdir logs] \
	[::msgcat::mc "Directory to store logs."] \
	-type string -group Logging

    custom::defvar options(log_chat) 1 \
	[::msgcat::mc "Store private chats logs."] \
	-type boolean -group Logging

    custom::defvar options(log_groupchat) 1 \
	[::msgcat::mc "Store group chats logs."] \
	-type boolean -group Logging

    variable version 1.0

    if {![file exists $options(logdir)]} {
	file mkdir $options(logdir)
    
	# Storing version for possible future conversions
	set fd [open [file join $options(logdir) version] w]
	puts $fd $version
	close $fd
    }

    array set m2d [list [::msgcat::mc "January"]   01 \
			[::msgcat::mc "February"]  02 \
			[::msgcat::mc "March"]     03 \
			[::msgcat::mc "April"]     04 \
			[::msgcat::mc "May"]       05 \
			[::msgcat::mc "June"]      06 \
			[::msgcat::mc "July"]      07 \
			[::msgcat::mc "August"]    08 \
			[::msgcat::mc "September"] 09 \
			[::msgcat::mc "October"]   10 \
			[::msgcat::mc "November"]  11 \
			[::msgcat::mc "December"]  12]

    array set d2m [list 01 [::msgcat::mc "January"]   \
			02 [::msgcat::mc "February"]  \
			03 [::msgcat::mc "March"]     \
			04 [::msgcat::mc "April"]     \
			05 [::msgcat::mc "May"]       \
			06 [::msgcat::mc "June"]      \
			07 [::msgcat::mc "July"]      \
			08 [::msgcat::mc "August"]    \
			09 [::msgcat::mc "September"] \
			10 [::msgcat::mc "October"]   \
			11 [::msgcat::mc "November"]  \
			12 [::msgcat::mc "December"]]
}

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

proc ::logger::add_menu_item {state category m xlib jid} {
    switch -- $category {
	roster {
	    set rjid [roster::find_jid $xlib $jid]
	    if {$rjid != ""} {
		set jid $rjid
	    }
	}
	chat {
	    set nas [::xmpp::jid::stripResource $jid]
	    if {![chat::is_groupchat [chat::chatid $xlib $nas]]} {
		set jid $nas
	    }
	}
    }
    $m add command -label [::msgcat::mc "Show history"] \
	   -state $state \
           -command [list logger::show_log $jid -connection $xlib]
}

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

hook::add chat_create_user_menu_hook \
    [list ::logger::add_menu_item normal chat] 65
hook::add chat_create_conference_menu_hook \
    [list ::logger::add_menu_item normal group] 65
hook::add roster_create_groupchat_user_menu_hook \
    [list ::logger::add_menu_item normal grouproster] 65
hook::add roster_conference_popup_menu_hook \
    [list ::logger::add_menu_item normal roster] 65
hook::add roster_service_popup_menu_hook \
    [list ::logger::add_menu_item disabled roster] 65
hook::add roster_jid_popup_menu_hook \
    [list ::logger::add_menu_item normal roster] 65
hook::add message_dialog_menu_hook \
    [list ::logger::add_menu_item disabled message] 65
hook::add search_popup_menu_hook \
    [list ::logger::add_menu_item disabled search] 65

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

proc ::logger::str_to_log {str} {
    return [string map {\\ \\\\ \r \\r \n \\n} $str]
}

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

proc ::logger::log_to_str {str} {
    return [string map {\\\\ \\ \\r \r \\n \n} $str]
}

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

proc ::logger::jid_to_filename {jid} {
    if {$jid == ""} {
	set jid @@empty
    }
    set utf8_jid [encoding convertto utf-8 $jid]
    set len [string length $utf8_jid]
    set filename ""
    for {set i 0} {$i < $len} {incr i} {
	binary scan $utf8_jid @${i}c sym
	set sym [expr {$sym & 0xFF}]
	switch -- $sym {
	    34 - 37 - 39 - 42 - 43 - 47 - 58 - 59 - 60 - 62 - 63 - 92 - 124 - 126 {
		# 34 " 37 % 39 ' 42 * 43 + 47 / 58 : 59 ; 60 < 62 > 63 ? 92 \ 124 | 126 ~
		append filename [format "%%%02X" $sym]
	    }
	    46 {
		# 46 .
		if {$i + 1 == $len} {
		    append filename [format "%%%02X" $sym]
		} else {
		    append filename [binary format c $sym]
		}
	    }
	    default {
		if {$sym >= 128 || $sym <= 32} {
		    append filename [format "%%%02X" $sym]
		} else {
		    append filename [binary format c $sym]
		}
	    }
	}
    }
    if {[string index $filename 253] == "%"} {
	return [string range $filename 0 252]
    }
    if {[string index $filename 252] == "%"} {
	return [string range $filename 0 251]
    }
    return [string range $filename 0 253]
}

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

proc ::logger::filename_to_jid {filename} {
    if {$filename == "@@empty"} {
	return $filename
    } else {
	set len [string length $filename]
	set utf8_jid ""
	for {set i 0} {$i < $len} {incr i} {
	    catch {
		binary scan $filename @${i}a sym
		switch -- $sym {
		    "%" {
			incr i
			binary scan $filename @${i}a2 num
			append utf8_jid [binary format c 0x$num]
			incr i
		    }
		    default {
			append utf8_jid $sym
		    }
		}
	    }
	}
	return [encoding convertfrom utf-8 $utf8_jid]
    }
}

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

proc ::logger::cdopen {filepath {mode r}} {
    set dir [file dirname $filepath]
    set file [file tail $filepath]
    set current_dir [pwd]
    cd $dir
    if {[catch {open $file $mode} fd]} {
	cd $current_dir
	return -code error $fd
    } else {
	cd $current_dir
	return $fd
    }
}

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

proc ::logger::log_message {chatid from type body x} {
    variable options

    if {$type == "chat" && !$options(log_chat)} return
    if {$type == "groupchat" && !$options(log_groupchat)} return

    if {![hook::is_flag draw_message_hook log]} return

    set xlib [chat::get_xlib $chatid]
    set jid [chat::get_jid $chatid]
    set nas [::xmpp::jid::stripResource $jid]
    if {$type == "chat" && ![chat::is_groupchat [chat::chatid $xlib $nas]]} {
	set jid $nas
    }

    set nick [chat::get_nick $xlib $from $type]
    if {[::xmpp::jid::equal $from [my_jid $xlib $jid]]} {
	set me 1
    } else {
	set me 0
    }

    set seconds [::xmpp::xml::getAttr [::xmpp::delay::parse $x] seconds]
    foreach xelem $x {
	::xmpp::xml::split $xelem tag xmlns attrs cdata subels
	
	# Don't log message if this 'empty' tag is present. It indicates
	# messages history in chat window.
	if {[string equal $tag ""] && [string equal $xmlns tkabber:x:nolog]} {
	    return
	}
    }
    set ts [clock format $seconds -format "%Y%m%dT%H%M%S" -gmt 1]
    set year [clock format $seconds -format %Y]
    set month [clock format $seconds -format %m]

    file mkdir [file join $options(logdir) $year $month]
    set fd [cdopen [file join $options(logdir) $year $month [jid_to_filename $jid]] a]
    fconfigure $fd -encoding utf-8
    puts $fd [str_to_log [list timestamp $ts jid $from nick $nick body $body me $me]]
    close $fd
}

hook::add draw_message_hook ::logger::log_message 15

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

proc ::logger::winid {name} {
    set allowed_name [jid_to_tag $name]
    return .log_$allowed_name
}

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

proc ::logger::describe_month {year-month} {
    variable d2m

    lassign [split ${year-month} -] year month
    return "$d2m($month) $year"
}

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

proc ::logger::create_log_viewer {lw jid args} {
    global tcl_platform
    global defaultnick

    foreach {key val} $args {
	switch -- $key {
	    -connection { set xlib $val }
	    -subdirs { set subdirs $val }
	}
    }
    if {![info exists xlib]} {
	set xlib [lindex [connections] 0]
    }

    set logfile [jid_to_filename $jid]

    set mynick [get_group_nick $xlib $jid]

    toplevel $lw -relief $::tk_relief -borderwidth $::tk_borderwidth -class Chat
    wm group $lw .
    wm withdraw $lw
    set title [::msgcat::mc "History for %s" $jid]
    wm title $lw $title
    wm iconname $lw $title

    set lf [ScrolledWindow $lw.sw]
    set l [text $lw.log -wrap word -takefocus 0]

    set mf [frame $lw.mf]
    pack $mf -side top -fill x -expand no -padx 1m -pady 1m
    set mlabel [label $mf.mlabel -text [::msgcat::mc "Select month:"]]
    pack $mlabel -side left
    set ebutton [button $mf.ebutton -text [::msgcat::mc "Export to XHTML"] \
				    -command [list [namespace current]::export \
						   $l $lw.mf.mcombo $logfile $mynick]]
    pack $ebutton -side right
    pack $lf -padx 1m -pady 1m -fill both -expand yes

    $lf setwidget $l

    regsub -all %W [bind Text <Prior>] [double% $l] prior_binding
    regsub -all %W [bind Text <Next>]  [double% $l] next_binding
    bind $lw <Prior> $prior_binding
    bind $lw <Next>  $next_binding

    $l tag configure they -foreground [option get $lw theyforeground Chat]
    $l tag configure me -foreground [option get $lw meforeground Chat]
    $l tag configure server_lab \
       -foreground [option get $lw serverlabelforeground Chat]
    $l tag configure server \
       -foreground [option get $lw serverforeground Chat]

    $l configure -state disabled

    if {![info exists subdirs]} {
	set subdirs [get_subdirs $logfile]
    }

    set ympairs {}
    foreach sd [lsort -decreasing $subdirs] {
	lappend ympairs [describe_month $sd]
    }
    lappend ympairs [::msgcat::mc "All"]

    set mcombo [ComboBox $mf.mcombo \
			 -editable no \
			 -exportselection no \
			 -values $ympairs \
			 -text [lindex $ympairs 0] \
			 -modifycmd [list \
			    [namespace current]::change_month \
					  $mf.mcombo $logfile $l $mynick]]
    pack $mcombo -side left

    hook::run open_log_post_hook $xlib $jid $lw

    wm deiconify $lw
}

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

proc ::logger::show_log {jid args} {
    set lw [winid $jid]
    debugmsg plugins "LOGGER: $lw"

    variable $lw
    upvar 1 $lw state

    if {![winfo exists $lw]} {
	eval [list create_log_viewer $lw $jid] $args
    } else {
	focus -force $lw
    }

    foreach {key val} $args {
	switch -- $key {
	    -when { set when $val }
	    -timestamp { set timestamp $val }
	}
    }

    set logfile [jid_to_filename $jid]
    set mynick [get_group_nick "" $jid]

    set log $lw.log
    set cbox $lw.mf.mcombo

    set ympairs [$cbox cget -values]
    if {[info exists when]} {
	set text [describe_month $when]
	if {[lsearch -exact $ympairs $text] < 0} {
	    error "no log entries for: $when"
	}
    } else {
	set text [lindex $ympairs 0]
    }

    $cbox configure -text $text

    change_month $cbox $logfile $log $mynick

    if {[info exists timestamp]} {
	set pos [lindex [$log tag ranges TS-$timestamp] 0]
	if {$pos == ""} { set pos end }
    } else {
	set pos end
    }

    $log see $pos
}

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

proc ::logger::get_subdirs {logfile} {
    variable options

    set subdirs {}
    foreach yeard [glob -nocomplain -type d -directory $options(logdir) *] {
	foreach monthd [glob -nocomplain -type d -directory $yeard *] {
	    if {[file exists [file join $monthd $logfile]]} {
		lappend subdirs [file tail $yeard]-[file tail $monthd]
	    }
	}
    }

    return $subdirs
}

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

proc ::logger::draw_messages {l hist mynick} {
    $l configure -state normal
    $l delete 1.0 end

    add_messages $l $hist $mynick
}

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

proc ::logger::formatxmppts {xmppts} {
    set seconds [clock scan $xmppts -gmt 1]
    clock format $seconds -format {%Y-%m-%d %X}
}

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

proc ::logger::exists_and_empty {what} {
    upvar 1 $what var
    expr {[info exists var] && $var == ""}
}

proc ::logger::exists_and_nonempty {what} {
    upvar 1 $what var
    expr {[info exists var] && $var != ""}
}

proc ::logger::add_messages {l hist mynick} {
    $l configure -state normal

    foreach vars $hist {
	array unset tmp
	if {[catch {array set tmp $vars}]} continue

	if {[info exists tmp(timestamp)]} {
	    $l insert end \[[formatxmppts $tmp(timestamp)]\] \
		[list TS-$tmp(timestamp)]
	}
	if {[exists_and_empty tmp(jid)]} {
	    # synthesized message
	    $l insert end "---" server_lab
	    set servertag server
	} else {
	    if {[exists_and_empty tmp(nick)]} {
		# message from the server:
		$l insert end "---" server_lab
		set servertag server
	    } else {
		set nick $tmp(nick)
		if {([info exists tmp(me)] && $tmp(me)) || [string equal $nick $mynick]} {
		    set tag me
		} else {
		    set tag they
		}
		if {[info exists tmp(body)] && [regsub {^/me } $tmp(body) {} body]} {
		    $l insert end "*$nick $body" $tag
		    unset tmp(body)
		} else {
		    $l insert end "<$nick>" $tag
		}
		set servertag ""
	    }
	}
	if {[info exists tmp(body)]} {
	    $l insert end " $tmp(body)" $servertag
	}
	if {![$l compare "end -1 chars linestart" == "end -1 chars"]} {
	    $l insert end "\n"
	}
    }
    $l configure -state disabled
}

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

proc ::logger::change_month {mcombo logfile l mynick} {
    variable m2d

    set month [$mcombo cget -text]
    if {$month == [::msgcat::mc "All"]} {
	draw_messages $l {} $mynick
	foreach m [lsort -increasing [get_subdirs $logfile]] {
	    add_messages $l [read_hist_from_file $logfile $m] $mynick
	    update
	}
    } else {
	set my_list [split $month " "]
	set month [lindex $my_list end]-$m2d([join [lrange $my_list 0 end-1] " "])
	draw_messages $l [read_hist_from_file $logfile $month] $mynick
    }
    $l see end
}

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

proc ::logger::read_hist_from_file {logfile month} {
    variable options

    lassign [split $month -] year month1
    set filename [file join $options(logdir) $year $month1 $logfile]

    set hist {}
    if {[file exists $filename]} {
	set fd [cdopen $filename r]
	fconfigure $fd -encoding utf-8
	while {[gets $fd line] > 0} {
	    lappend hist [log_to_str $line]
	}
	close $fd
    }

    return $hist
}

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

proc ::logger::get_last_messages {jid max interval} {
    if {$max == 0 || $interval == 0} {
	return {}
    }

    set logfile [jid_to_filename $jid]
    set months [lsort -decreasing [get_subdirs $logfile]]
    set messages {}
    set curseconds [clock seconds]
    set max1 [expr {$max - 1}]
    foreach m $months {
	catch {
	    set messages [lsort -increasing -index 1 \
				[concat [read_hist_from_file $logfile $m] \
					$messages]]
	}
	if {$interval > 0} {
	    set idx 0
	    foreach msg $messages {
		set timestamp [lindex $msg 1]
		set seconds [clock scan $timestamp -gmt 1]
		if {$seconds + $interval * 3600 < $curseconds} {
		    incr idx
		} else {
		    break
		}
	    }
	    if {$idx > 0} {
		set messages  [lrange $messages $idx end]
		if {$max > 0 && [llength $messages] >= $max} {
		    return [lrange $messages end-$max1 end]
		} else {
		    return $messages
		}
	    }
	}
	if {$max > 0 && [llength $messages] >= $max} {
	    return [lrange $messages end-$max1 end]
	}
    }
    return $messages
}

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

proc ::logger::export {lw mcombo logfile mynick} {
    variable m2d

    set month [$mcombo cget -text]
    if {$month == [::msgcat::mc "All"]} {
	set hist {}
	foreach m [lsort -increasing [get_subdirs $logfile]] {
	    set hist [concat $hist [read_hist_from_file $logfile $m]]
	}
    } else {
	set my_list [split $month " "]
	set month [lindex $my_list end]-$m2d([join [lrange $my_list 0 end-1] " "])
	set hist [read_hist_from_file $logfile $month]
    }

    set filename [tk_getSaveFile -defaultextension .html]
    if {$filename == ""} return
    set fd [open $filename w]
    fconfigure $fd -encoding utf-8

    puts $fd {<?xml version="1.0" encoding="UTF-8"?>}
    puts $fd {<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd">}
    puts $fd {<html xmlns="http://www.w3.org/1999/xhtml">}
    set head [::xmpp::xml::create head \
		  -subelement [::xmpp::xml::create link \
				      -attrs {rel stylesheet
					      type text/css
					      href tkabber-logs.css}]]
    puts $fd [::xmpp::xml::toText $head]


    foreach vars $hist {
	array unset tmp
	if {[catch {array set tmp $vars}]} continue

	set subtags {}
	if {[info exists tmp(timestamp)]} {
	    set seconds [clock scan $tmp(timestamp) -gmt 1]
	    set timestamp [clock format $seconds -format {[%Y-%m-%d %X]}]
	    lappend subtags [::xmpp::xml::create span \
				    -attrs {class timestamp} \
				    -cdata $timestamp]
	}
	if {[info exists tmp(nick)] && $tmp(nick) != ""} {
	    if {([info exists tmp(me)] && $tmp(me)) || $tmp(nick) == $mynick} {
	        set tag me
	    } else {
	        set tag they
	    }
	    if {[info exists tmp(body)] && [regsub {^/me } $tmp(body) {} body]} {
		set nick "*$tmp(nick) $body"
		unset tmp(body)
	    } else {
		set nick "<$tmp(nick)> "
	    }
	    lappend subtags [::xmpp::xml::create span \
				    -attrs [list class $tag] \
				    -cdata $nick]

	    if {[info exists tmp(body)]} {
		lappend subtags [::xmpp::xml::create span \
					-attrs {class body} \
					-cdata "$tmp(body)"]
	    }
	} else {
	    if {[info exists tmp(body)]} {
		lappend subtags [::xmpp::xml::create span \
					-attrs {class server} \
					-cdata "--- $tmp(body)"]
	    }
	}
	#if {![$l compare "end -1 chars linestart" == "end -1 chars"]} {
	#    puts "\n"
	#}
	set msg [::xmpp::xml::create div \
			-attrs {class message} \
			-subelements $subtags]

	puts $fd [::xmpp::xml::toText $msg]
    }
    
    puts $fd {</html>}
    close $fd

    write_css $lw [file join [file dirname $filename] tkabber-logs.css]
}

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

proc ::logger::write_css {lw filename} {
    set fd [open $filename w]

    puts $fd "
html body {
    background-color: white;
    color: black;
}

.me {
    color: blue;
}

.they {
    color: red;
}

.server {
    color: green;
}
"

    close $fd
}

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

proc ::logger::convert_subdir_log {t logfrom logto jid dir} {
    if {[catch {
	    set fd [cdopen $logfrom r]
	} err]} {
	$t configure -state normal
	$t insert end [::msgcat::mc "File %s cannot be opened: %s.\
				     History for %s (%s) is NOT converted\n" \
				    $err $logfrom $jid $dir] error
	$t configure -state disabled
	$t see end
	update
	return
    }
    fconfigure $fd -encoding utf-8
    set hist [read $fd]
    close $fd

    set fd [cdopen $logto a]
    fconfigure $fd -encoding utf-8
    if {[catch {
	    foreach vars $hist {
		puts $fd [str_to_log $vars]
	    }
	}]} {
	$t configure -state normal
	$t insert end [::msgcat::mc "File %s is corrupt.\
				     History for %s (%s) is NOT converted\n" \
				    $logfrom $jid $dir] error
	$t configure -state disabled
	$t see end
    } else {
	$t configure -state normal
	$t insert end "($dir) $jid\n"
	$t configure -state disabled
	$t see end
    }
    close $fd
    update
}

proc ::logger::convert_root_log {t dirfrom dirto filename jid} {
    set logfile [file join $dirfrom $filename]
    if {[catch {
	    set fd [cdopen $logfile r]
	} err]} {
	$t configure -state normal
	$t insert end [::msgcat::mc "File %s cannot be opened: %s.\
				     History for %s is NOT converted\n" \
				    $err $logfile $jid] error
	$t configure -state disabled
	$t see end
	update
	return
    }
    fconfigure $fd -encoding utf-8
    set hist [read $fd]
    close $fd

    if {[catch {
	    foreach vars $hist {
		array unset tmp
		if {[catch {array set tmp $vars}]} continue

		if {[info exists tmp(timestamp)]} {
		    set seconds [clock scan $tmp(timestamp) -gmt 1]
		    set ym [clock format $seconds -format %Y-%m]
		    lappend newhist($ym) $vars
		}
	    }
	}]} {
	$t configure -state normal
	$t insert end [::msgcat::mc "File %s is corrupt.\
				     History for %s is NOT converted\n" \
				    $logfile $jid] error
	$t configure -state disabled
	$t see end
	update
	return
    }

    foreach ym [lsort [array names newhist]] {
	$t configure -state normal
	$t insert end "($ym) $jid\n"
	$t configure -state disabled
	$t see end
	update
	lassign [split $ym -] year month
	set dir [file join $dirto $year $month]
	set newlog [file join $dir [jid_to_filename $jid]]
	file mkdir $dir

	set fd [cdopen $newlog a]
	fconfigure $fd -encoding utf-8
	catch {
	    foreach vars $newhist($ym) {
		puts $fd [str_to_log $vars]
	    }
	}
	close $fd
    }
}

proc ::logger::convert_logs {t dirfrom dirto} {
    variable version

    # Heuristically reconstruct JIDs
    set fnlist {}
    foreach subdir [glob -nocomplain -type d -directory $dirfrom *] {
	set dir [file tail $subdir]
	if {![regexp {^(\d\d\d\d)-(\d\d)$} $dir -> year month]} continue

	foreach filepath [glob -nocomplain -type f -directory $subdir *] {
	    lappend fnlist [file tail $filepath]
	}
    }
    foreach filepath [glob -nocomplain -type f -directory $dirfrom *] {
	lappend fnlist [file tail $filepath]
    }
    # Sort the list. It's important not only because it removes duplicates
    set fnlist [lsort -unique $fnlist]

    foreach fn $fnlist {
	# Set prefix (for processing groupchats)
	if {![info exists prefix] || ([string first $prefix $fn] != 0)} {
	    set prefix $fn
	}

	# Simple case: no or one underscore in the filename
	set idx [string first _ $fn]
	if {($idx < 0) || ([string first _ $fn [expr {$idx + 1}]] < 0)} {
	    set JID($fn) [string map {_ @} $fn]
	    continue
	}

	# JID without a resource (very likely)
	# Since underscore is not allowed in domain names, just replace
	# the last one by @. It's the best guess we can do
	if {$prefix == $fn} {
	    set idx [string last _ $fn]
	    set pr [string range $fn 0 [expr {$idx - 1}]]
	    set sf [string range $fn [expr {$idx + 1}] end]
	    set JID($fn) $pr@$sf
	    continue
	}

	# JID with a resource is a private chat with someone in the
	# conference room. Take room JID from the $prefix and add
	# resource (don't replace _ in the resource)
	set idx [expr {[string length $prefix] + 1}]
	set sf [string range $fn $idx end]
	set JID($fn) $JID($prefix)/$sf
    }

    # Create dir for new logs
    if {![file exists $dirto]} {
	file mkdir $dirto
    }

    # Process all subdirs YYYY-MM
    foreach subdir [glob -nocomplain -type d -directory $dirfrom *] {
	set dir [file tail $subdir]
	if {![regexp {^(\d\d\d\d)-(\d\d)$} $dir -> year month]} continue

	foreach filepath [glob -nocomplain -type f -directory $subdir *] {
	    set jid $JID([file tail $filepath])
	    set filename [jid_to_filename $jid]
	    set fdir [file join $dirto $year $month]
	    file mkdir $fdir
	    convert_subdir_log $t $filepath [file join $fdir $filename] $jid $dir
	}
    }

    # Process all files in log dir itself
    foreach filepath [glob -nocomplain -type f -directory $dirfrom *] {
	if {[file tail $filepath] == "message_archive"} {
	    convert_subdir_log $t $filepath \
				  [file join $dirto [file tail $filepath]] \
				  message_archive ""
	} else {
	    convert_root_log $t $dirfrom $dirto \
			     [file tail $filepath] $JID([file tail $filepath])
	}
    }

    # Storing version for possible future conversions
    set fd [open [file join $dirto version] w]
    puts $fd $version
    close $fd
}

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

proc ::logger::convert_on_start {} {
    variable version
    variable options

    set version_file [file join $options(logdir) version]
    if {[file exists $version_file]} {
	set fd [open $version_file r]
	set v [string trim [read $fd]]
	close $fd
	if {$v >= $version} return
    }

    set parent_dir [file dirname $options(logdir)]
    set log_dir [file tail $options(logdir)]

    if {$log_dir == ""} {
	return -code error \
	       [::msgcat::mc "You're using root directory %s for storing Tkabber\
			      logs!\n\nI refuse to convert logs database." \
			     $options(logdir)]
    }

    # Create temporary directory for converted logs
    set dir $log_dir.new
    while {[file exists [file join $parent_dir $dir]]} {
	set dir $dir~
    }

    set w .log_convert

    Dialog $w -title [::msgcat::mc "Converting Log Files"] \
	-separator 1 -anchor e -default 0 -cancel 0 -modal none

    bind $w <Destroy> [list set convert_result 1]

    $w add -text [::msgcat::mc "Close"] \
	   -state disabled \
	   -command [list destroy $w]

    set f [$w getframe]

    set msg [message $f.msg -aspect 50000 \
		     -text [::msgcat::mc "Please, be patient while chats\
					  history is being converted to new format"]]
    pack $msg

    set sw [ScrolledWindow $f.sw]
    pack $sw -expand yes -fill both

    set t [text $sw.t -state disabled -wrap word]
    $t tag configure error -foreground [option get $t errorForeground Text]
    $sw setwidget $t

    $w draw
    grab $w

    convert_logs $t $options(logdir) [file join $parent_dir $dir]
    
    set bdir $log_dir~
    while {[file exists [file join $parent_dir $bdir]]} {
	set bdir $bdir~
    }
    file rename -- $options(logdir) [file join $parent_dir $bdir]
    file rename -- [file join $parent_dir $dir] $options(logdir)

    if {[winfo exists $w]} {
	$w itemconfigure 0 -state normal

	$msg configure -text [::msgcat::mc "Chats history is converted.\nBackup\
					    of the old history\
					    is stored in %s" \
					   [file join $parent_dir $bdir]]

	$t configure -state normal
	$t insert end "[::msgcat::mc {Conversion is finished}]\n"
	$t configure -state disabled
	$t see end

	vwait convert_result
    }
    catch {unset ::convert_result}
}

hook::add finload_hook ::logger::convert_on_start 1000

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

# vim:ts=8:sw=4:sts=4:noet
