#!/usr/bin/wish # Fubar plug-in to handle phonebook package require Img if {![file exists ~/.phonebook.vcf]} { error "Phonebook file $env(HOME)/.phonebook.vcf not found" } namespace eval phonebook { # Returns true if phonebook was reread, false if it is not changed # proc read_phonebook {} { variable phones variable phonebookstamp if {[info exists phonebookstamp]&&[file mtime ~/.phonebook.vcf]<$phonebookstamp} { return 0 } if {[info exists phones]} {unset phones} set f [open ~/.phonebook.vcf r] fconfigure $f -encoding utf-8 set state "none" while {[gets $f line]>=0} { if {![string length $line]} continue if {$state eq "photo"} { if {![regexp ":" $line]} { set index [lindex [array names cur_record "PHOTO*"] 0] append cur_record($index) "$line\n" continue } else { set state "record" } } foreach {field value} [split $line :] break set list [split $field ";"] if {[llength $list>1]} { set field [lindex $list 0] foreach opt [lrange $list 1 end] { if {[string match CHARSET=* $opt]|| [string match ENCODING=* $opt]|| $opt eq "PREF"} continue lappend field $opt } } if {$field eq "END"} { assemble_record cur_record set state "none" array unset cur_record } elseif {$field eq "BEGIN"} { if {[info exists currecord]} { array unset cur_record } set state "record" } else { if {[string match "PHOTO*" $field]} { set cur_record($field) "$value\n" set state "photo" } else { set cur_record($field) "" foreach subval [split $value ";"] { set cur_record($field) "$subval $cur_record($field)" } } } } close $f set phonebookstamp [clock seconds] return 1 } proc assemble_record {var} { upvar $var record variable phones set index $record(N) if [info exists record(ORG)] { append index ",$record(ORG)"} if [info exists record(TITLE)] { append index ",$record(TITLE)"} set phones($index) [array get record] } proc mkwindow {w} { wm title $w "Phone book" frame $w.search entry $w.search.pattern button $w.search.loc -text "Find"\ -command [list ::phonebook::position $w] button $w.search.filter -text "Filter"\ -command [list ::phonebook::filter $w] button $w.search.new -text "New"\ -command [list ::phonebook::new_rec $w] bind $w.search.pattern [list $w.search.loc invoke] bind $w.search.pattern [list $w.search.filter invoke] bind $w.search.pattern [list $w.search.new invoke] pack $w.search.pattern -side left -fill x -expand y pack $w.search.loc $w.search.filter $w.search.new -side left listbox $w.list -yscrollcommand "$w.y set" -width 20 bind $w.list <> "::phonebook::show_record $w \[%W get \[%W curselection\]\]" bind $w.list [list ::phonebook::keyEvent $w.search.pattern %k %s %A %K] scrollbar $w.y -orient vert -command "$w.list yview" frame $w.record foreach {name title} {name "Имя" org "Организация" title "Звание" telcell "Тел. Моб" telwork "Тел.Раб." telhome "Тел.Дом." telother "Прочее" fax "Факс" email "E-Mail"} { label $w.record.l$name -text $title -anchor e label $w.record.$name -anchor w grid $w.record.l$name $w.record.$name -sticky news } label $w.record.image button $w.record.edit -text Edit -command "::phonebook::edit_record" button $w.record.mail -text Mail -state disabled -command "::phonebook::mail_to" grid $w.record.image - -sticky news grid $w.record.mail $w.record.edit -sticky ns grid columnconfigure $w.record 1 -weight 1 grid columnconfigure $w.record 0 -weight 0 grid $w.search - - -sticky news grid $w.list $w.y $w.record -sticky news grid columnconfigure $w 0 -weight 1 grid columnconfigure $w 1 -weight 0 grid columnconfigure $w 2 -weight 1 } proc keyEvent {window keycode state char keysym} { if {![string length $char]} return;#ignore noncharacter keys focus $window event generate $window -keycode $keycode -keysym $keysym\ -state $state -when tail } proc show_record {w index} { variable phones variable current if {[info exists phones($index)]} { array set record $phones($index) set current $index } else { array set record {} if {[info exists current]} {unset current} } $w.record.name configure -text $record(N); set_if_exists $w.record.org record(ORG) set_if_exists $w.record.title record(TITLE) set_if_exists $w.record.telcell "record(TEL CELL)" set_if_exists $w.record.telhome "record(TEL HOME)" set_if_exists $w.record.telwork "record(TEL WORK)" set_if_exists $w.record.telother "record(TEL)" set_if_exists $w.record.fax "record(TEL FAX)" set_if_exists $w.record.email "record(EMAIL INTERNET)" if {[info exists "record(EMAIL INTERNET)"]} { $w.record.mail configure -state normal } else { $w.record.mail configure -state disabled } if {[llength [set img_index [lindex [array names record PHOTO*] 0]]]} { if {![regexp {TYPE=([^[:space:]]+)} $img_index msg fmt]} { set fmt JPEG } $w.record.image configure -image [image create photo -format $fmt -data $record($img_index)] } else { $w.record.image configure -image "" } } proc set_if_exists {w var} { upvar $var v if {[info exists v]} { $w configure -text $v } else { $w configure -text {} } } proc fill_window {w} { variable phones variable filter variable current read_phonebook set list [lsort [array names phones]] if {[info exists filter]} { set list [lsearch -all -inline -regexp $list $filter ] } $w.list delete 0 end eval $w.list insert 0 $list if {![info exists current]||[set index [lsearch -exact $list $current]]<0} { set index 0 } $w.list selection clear 0 end $w.list selection set $index event generate $w.list <> after idle "$w.list see $index;focus $w.list" focus $w.search.pattern } proc position {w} { set pattern [$w.search.pattern get] set list [$w.list get 0 end] set index [lsearch -regexp $list $pattern] if {$index!= -1} { $w.list selection clear 0 end $w.list selection set $index event generate $w.list <> after idle "$w.list see $index;focus $w.list" } } proc filter {w} { variable filter set filter [$w.search.pattern get] if {![string length $filter]} { unset filter } fill_window $w } # # Create an interface # if {$::argv0 ne [info script]} { set m .find.m $m add command -label "Phone..." -command\ "create_or_raise .phonebook ::phonebook::mkwindow; ::phonebook::fill_window .phonebook" } else { button .b -text "Phonebook" -command "toplevel .phonebook; ::phonebook::mkwindow .phonebook ::phonebook::fill_window .phonebook" pack .b } proc mail_to {} { variable current variable phones global CONFIGDIR array set r $phones($current) if {![info exists "r(EMAIL INTERNET)"]} { return } set address ${r(EMAIL INTERNET)} exec $CONFIGDIR/mail $address & } proc new_rec {} { variable edited catch {unset edited} edit_window } proc edit_record {} { variable current variable phones variable edited set edited $current edit_window } proc edit_window {} { } }