This file is indexed.

/usr/share/obextool/plugins/vcs_plugin.tcl is in obextool 0.35-0ubuntu2.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

   1
   2
   3
   4
   5
   6
   7
   8
   9
  10
  11
  12
  13
  14
  15
  16
  17
  18
  19
  20
  21
  22
  23
  24
  25
  26
  27
  28
  29
  30
  31
  32
  33
  34
  35
  36
  37
  38
  39
  40
  41
  42
  43
  44
  45
  46
  47
  48
  49
  50
  51
  52
  53
  54
  55
  56
  57
  58
  59
  60
  61
  62
  63
  64
  65
  66
  67
  68
  69
  70
  71
  72
  73
  74
  75
  76
  77
  78
  79
  80
  81
  82
  83
  84
  85
  86
  87
  88
  89
  90
  91
  92
  93
  94
  95
  96
  97
  98
  99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
 129
 130
 131
 132
 133
 134
 135
 136
 137
 138
 139
 140
 141
 142
 143
 144
 145
 146
 147
 148
 149
 150
 151
 152
 153
 154
 155
 156
 157
 158
 159
 160
 161
 162
 163
 164
 165
 166
 167
 168
 169
 170
 171
 172
 173
 174
 175
 176
 177
 178
 179
 180
 181
 182
 183
 184
 185
 186
 187
 188
 189
 190
 191
 192
 193
 194
 195
 196
 197
 198
 199
 200
 201
 202
 203
 204
 205
 206
 207
 208
 209
 210
 211
 212
 213
 214
 215
 216
 217
 218
 219
 220
 221
 222
 223
 224
 225
 226
 227
 228
 229
 230
 231
 232
 233
 234
 235
 236
 237
 238
 239
 240
 241
 242
 243
 244
 245
 246
 247
 248
 249
 250
 251
 252
 253
 254
 255
 256
 257
 258
 259
 260
 261
 262
 263
 264
 265
 266
 267
 268
 269
 270
 271
 272
 273
 274
 275
 276
 277
 278
 279
 280
 281
 282
 283
 284
 285
 286
 287
 288
 289
 290
 291
 292
 293
 294
 295
 296
 297
 298
 299
 300
 301
 302
 303
 304
 305
 306
 307
 308
 309
 310
 311
 312
 313
 314
 315
 316
 317
 318
 319
 320
 321
 322
 323
 324
 325
 326
 327
 328
 329
 330
 331
 332
 333
 334
 335
 336
 337
 338
 339
 340
 341
 342
 343
 344
 345
 346
 347
 348
 349
 350
 351
 352
 353
 354
 355
 356
 357
 358
 359
 360
 361
 362
 363
 364
 365
 366
 367
 368
 369
 370
 371
 372
 373
 374
 375
 376
 377
 378
 379
 380
 381
 382
 383
 384
 385
 386
 387
 388
 389
 390
 391
 392
 393
 394
 395
 396
 397
 398
 399
 400
 401
 402
 403
 404
 405
 406
 407
 408
 409
 410
 411
 412
 413
 414
 415
 416
 417
 418
 419
 420
 421
 422
 423
 424
 425
 426
 427
 428
 429
 430
 431
 432
 433
 434
 435
 436
 437
 438
 439
 440
 441
 442
 443
 444
 445
 446
 447
 448
 449
 450
 451
 452
 453
 454
 455
 456
 457
 458
 459
 460
 461
 462
 463
 464
 465
 466
 467
 468
 469
 470
 471
 472
 473
 474
 475
 476
 477
 478
 479
 480
 481
 482
 483
 484
 485
 486
 487
 488
 489
 490
 491
 492
 493
 494
 495
 496
 497
 498
 499
 500
 501
 502
 503
 504
 505
 506
 507
 508
 509
 510
 511
 512
 513
 514
 515
 516
 517
 518
 519
 520
 521
 522
 523
 524
 525
 526
 527
 528
 529
 530
 531
 532
 533
 534
 535
 536
 537
 538
 539
 540
 541
 542
 543
 544
 545
 546
 547
 548
 549
 550
 551
 552
 553
 554
 555
 556
 557
 558
 559
 560
 561
 562
 563
 564
 565
 566
 567
 568
 569
 570
 571
 572
 573
 574
 575
 576
 577
 578
 579
 580
 581
 582
 583
 584
 585
 586
 587
 588
 589
 590
 591
 592
 593
 594
 595
 596
 597
 598
 599
 600
 601
 602
 603
 604
 605
 606
 607
 608
 609
 610
 611
 612
 613
 614
 615
 616
 617
 618
 619
 620
 621
 622
 623
 624
 625
 626
 627
 628
 629
 630
 631
 632
 633
 634
 635
 636
 637
 638
 639
 640
 641
 642
 643
 644
 645
 646
 647
 648
 649
 650
 651
 652
 653
 654
 655
 656
 657
 658
 659
 660
 661
 662
 663
 664
 665
 666
 667
 668
 669
 670
 671
 672
 673
 674
 675
 676
 677
 678
 679
 680
 681
 682
 683
 684
 685
 686
 687
 688
 689
 690
 691
 692
 693
 694
 695
 696
 697
 698
 699
 700
 701
 702
 703
 704
 705
 706
 707
 708
 709
 710
 711
 712
 713
 714
 715
 716
 717
 718
 719
 720
 721
 722
 723
 724
 725
 726
 727
 728
 729
 730
 731
 732
 733
 734
 735
 736
 737
 738
 739
 740
 741
 742
 743
 744
 745
 746
 747
 748
 749
 750
 751
 752
 753
 754
 755
 756
 757
 758
 759
 760
 761
 762
 763
 764
 765
 766
 767
 768
 769
 770
 771
 772
 773
 774
 775
 776
 777
 778
 779
 780
 781
 782
 783
 784
 785
 786
 787
 788
 789
 790
 791
 792
 793
 794
 795
 796
 797
 798
 799
 800
 801
 802
 803
 804
 805
 806
 807
 808
 809
 810
 811
 812
 813
 814
 815
 816
 817
 818
 819
 820
 821
 822
 823
 824
 825
 826
 827
 828
 829
 830
 831
 832
 833
 834
 835
 836
 837
 838
 839
 840
 841
 842
 843
 844
 845
 846
 847
 848
 849
 850
 851
 852
 853
 854
 855
 856
 857
 858
 859
 860
 861
 862
 863
 864
 865
 866
 867
 868
 869
 870
 871
 872
 873
 874
 875
 876
 877
 878
 879
 880
 881
 882
 883
 884
 885
 886
 887
 888
 889
 890
 891
 892
 893
 894
 895
 896
 897
 898
 899
 900
 901
 902
 903
 904
 905
 906
 907
 908
 909
 910
 911
 912
 913
 914
 915
 916
 917
 918
 919
 920
 921
 922
 923
 924
 925
 926
 927
 928
 929
 930
 931
 932
 933
 934
 935
 936
 937
 938
 939
 940
 941
 942
 943
 944
 945
 946
 947
 948
 949
 950
 951
 952
 953
 954
 955
 956
 957
 958
 959
 960
 961
 962
 963
 964
 965
 966
 967
 968
 969
 970
 971
 972
 973
 974
 975
 976
 977
 978
 979
 980
 981
 982
 983
 984
 985
 986
 987
 988
 989
 990
 991
 992
 993
 994
 995
 996
 997
 998
 999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
###
### VCal plugin for ObexTool
###
### (c) Gerhard Reithofer, Techn. EDV Reithofer - 2003-05
### gerhard.reithofer@tech-edv.co.at http://www.tech-edv.co.at
###
### See COPYING for further details
###

namespace eval ::VCS {

  variable version 1.0

  variable show_alarmtime 0
  variable siemens_warning 1
  variable init_all_entries 1
  variable export_header_line 1
  variable exportfile "obexvcal.txt"

  variable label_font   {Helvetica 12 bold}
  variable dialog_font  {Helvetica 12}
  variable listbox_font {Helvetica 12}

  variable date_lbformat "%4d-%02d-%02d %02d:%02d:%02d"
  variable tmp_prefix "/tmp/vcal_data"
  variable date_separator "."
  variable time_separator ":"

  variable label_width 16
	variable supported_vcal_ver "1.0"

  variable obext_date "%4d%02d%02dT%02d%02d%02d" 
  variable vcal_entr
  variable vcentry_idx
  variable vcal_numbers
  variable top_level .vcal
  variable top_list .vlist
  variable pathname
	variable dataframe
  variable lb_widget
  variable prev_widget
  variable array repeat_day
  variable array vcal_array

  variable array years 
  array set years {start 1970 last 2100}

  load_Messages vcs_plug [getObexCfg config language] $version

  variable cat_name
  set cat_name(CATEGORIES)  [get_text "Category"     vcs_plug] 
  set cat_name(DTSTART)     [get_text "Start"        vcs_plug] 
  set cat_name(DALARM)      [get_text "Alarm"        vcs_plug] 
  set cat_name(DESCRIPTION) [get_text "Description"  vcs_plug] 
  set cat_name(RRULE)       [get_text "Repeat every" vcs_plug] 

  variable cat_type
  set {cat_type(ANNIVERSARY)}   [get_text "Birthday"      vcs_plug] 
  set {cat_type(TCELEBRATE)}    [get_text "Anniversary"   vcs_plug] 
  set {cat_type(VALENTINE)}     [get_text "Special event" vcs_plug] 
  set {cat_type(MISCELLANEOUS)} [get_text "Memo"          vcs_plug] 
  set {cat_type(PHONE CALL)}    [get_text "Phone call"    vcs_plug] 
  set {cat_type(MEETING)}       [get_text "Meeting"       vcs_plug] 

  variable cat_rule
  set cat_rule(D1)  [get_text "day"   vcs_plug]
  set cat_rule(YD1) [get_text "year"  vcs_plug]  
  set cat_rule(MD1) [get_text "month" vcs_plug] 
  set cat_rule(W1)  [get_text "week"  vcs_plug] 
  set cat_rule(D7)  [get_text "week"  vcs_plug]

  variable wdaylist [list MO TU WE TH FR SA SU]

  variable weekdays 
  set weekdays([lindex $wdaylist 0]) [get_text "Mo" vcs_plug] 
  set weekdays([lindex $wdaylist 1]) [get_text "Tu" vcs_plug] 
  set weekdays([lindex $wdaylist 2]) [get_text "We" vcs_plug] 
  set weekdays([lindex $wdaylist 3]) [get_text "Th" vcs_plug] 
  set weekdays([lindex $wdaylist 4]) [get_text "Fr" vcs_plug] 
  set weekdays([lindex $wdaylist 5]) [get_text "Sa" vcs_plug] 
  set weekdays([lindex $wdaylist 6]) [get_text "Su" vcs_plug] 
##################################################################
### Simple utility functions
###
### Just for debugging....
###
  proc debug_vcal { vl lv } { foreach entr $vl { debug_var entr $lv } }
###
### ... to avoid octal interpretation on leading zeroes
###
  proc ztrim { value } {
    regsub ^0+(.+) $value \\1 retval
    return $retval
  }
###
### Extract entry of listbox labels
###
  proc cat_label { key } {
    variable cat_name
debug_out "cat_label $key" 5

    if [info exists cat_name($key)] {
      set rv $cat_name($key)
    } else {
      set rv [string toupper [string index $key 0]]
      append rv [string tolower [string range $key 1 end]]
    }
debug_var rv 5
    return $rv
  }
###
### Extract a value for a category
###
  proc cat_value { key } {
    variable cat_type
debug_out "cat_type $key" 5

    if [info exists cat_type($key)] {
      set rv $cat_type($key)
    } else {
      set rv [string toupper [string index $key 0]]
      append rv [string tolower [string range $key 1 end]]
    }
debug_var rv 5
    return $rv
  }
###
### Extract value for a repetition rule
###
  proc rul_value { rlist } {
    variable wdaylist
    variable weekdays
    variable cat_rule
    variable cat_name
debug_out "rul_value $rlist" 5
    set rlist [split $rlist " "]
    set rule [lindex $rlist 0]
    set rpar [lrange $rlist 1 end]
    if {[lsearch [array names cat_rule] $rule]<0} {
      set msg [get_text "Unexpected Repeat-Rule '%s' found!" vcs_plug]
      warning [format $msg $rule]
      return [list "" "" ""]
    }
    set rv $cat_rule($rule)
debug_var rv 5
debug_var rule 5
    switch $rule {
      MD1 { 
        append rv [format [get_text " at the %s." vcs_plug] [ztrim $rpar]]
      }
      D7 -
      W1 { 
        set days ""
debug_var rpar
        foreach d $wdaylist {
          if {[lsearch $rpar $d]>=0} { append days " $weekdays($d)" }
        }
        append rv [format [get_text " on%s" vcs_plug]  $days]
      }
    }
    return $rv
  }

##################################################################
### Low level widgets
###
### Combo entry (for appointment category and repetition rules)
###
  proc combo_entry { w id ckey } {
    variable cat_type
    variable label_font
    variable dialog_font
    variable label_width
    debug_out "combo_entry $w $id $ckey" 5

    set value ""
    set name $w.[string tolower $id] 
    set dname [cat_label $id]
    set lf [LabelFrame $name -text $dname -justify left \
                       -width $label_width -font $label_font]
    foreach cate [array names cat_type] { lappend cl $cat_type($cate) }
    if [info exists cat_type($ckey)] { 
      set value $cat_type($ckey) 
    } else {
      set value 
    }
#   set txt $ckey
    ComboBox $lf.c -values $cl -text $value -font $dialog_font \
                   -entrybg white -justify left -disabledbackground white
    pack $lf.c $lf
###
### Currently we do not allow to change the catagory
###
    if {[string_equal $id "CATEGORIES"]&&![string_equal $ckey ""]} {
      $lf.c configure -state disabled 
    } else {
		  $lf.c setvalue first
		}
  }
###
### Date/time entry (for apointment and alarm)
###
  proc dtime_entry { w id val }  {
    variable years
    variable label_font
    variable dialog_font
    variable date_separator
    variable time_separator
    variable label_width
    variable obext_date
    debug_out "dtime_entry $w $id $val" 5
    
    set res [scan $val $obext_date Y M D h m s]
    set name $w.[string tolower $id] 
    set dname [cat_label $id]
    set lbl [format [get_text "%s date" vcs_plug] $dname]
    set l1 [LabelFrame ${name}d -text $lbl -justify left \
                       -width $label_width -font $label_font]
    SpinBox $l1.dy -text $Y -width 4 -font $dialog_font \
            -range [list $years(start) $years(last) 1] \
            -textvariable ::VCS::SB_year
    label $l1.d1 -text $date_separator
    SpinBox $l1.dm -text $M -width 2 -font $dialog_font -range [list 1 12 1] \
                   -textvariable ::VCS::SB_month
    label $l1.d2 -text $date_separator
    SpinBox $l1.dd -text $D -width 2 -font $dialog_font -range [list 1 31 1] \
                   -textvariable ::VCS::SB_day
    set lbl [format [get_text "%s time" vcs_plug] $dname]
    set l2 [LabelFrame ${name}t -text $lbl -justify left \
                        -width $label_width -font $label_font]
    SpinBox $l2.th -text $h -width 2 -font $dialog_font -range [list 0 23 1]\
                   -textvariable ::VCS::SB_hour
    label $l2.t1 -text $time_separator
    SpinBox $l2.tm -text $m -width 2 -font $dialog_font -range [list 0 59 1]\
                   -textvariable ::VCS::SB_minute
    label $l2.t2 -text $time_separator
    SpinBox $l2.ts -text $s -width 2 -font $dialog_font -range [list 0 59 1]\
                   -textvariable ::VCS::SB_second
    eval "pack [winfo children $l1] -side left"
    eval "pack [winfo children $l2] -side left"
    pack $l1 $l2 -fill x
  }
###
### Dynamic dialog part for apointment repetition rules
### Consisting of: combobox (day, week, month, year)
###                spinbox (day on monthly repetition only)
###                checkboxes (weekdays on weekly repetition only)
###
  proc rrule_entry { w id val } {
    variable cat_rule
    variable cat_name
    variable weekdays
    variable repeat_day
    variable label_font
    variable dialog_font
    variable label_width
    variable date_separator 
    debug_out "rrule_entry $w $id $val" 5

    set rlist [split $val " "]
    set rule [lindex $rlist 0]
    set rpar [lrange $rlist 1 end]
    if {[lsearch [array names cat_rule] $rule]<0} {
      set msg [get_text "Unexpected Repeat-Rule '%s' found!" vcs_plug]
      warning [format $msg $rule]
      return
    }

    set name $w.[string tolower $id] 
    set l1 [LabelFrame ${name}r -text $cat_name(RRULE) -justify left \
                       -width $label_width -font $label_font]
    foreach r [array names cat_rule] { lappend cl $cat_rule($r) }
    ComboBox $l1.c -values $cl -text $cat_rule($rule) -font $dialog_font \
                   -entrybg white -justify left -disabledbackground white
    eval "pack [winfo children $l1] -side left"
		if {[string_equal $rule "W1"]&&[string_equal $rpar ""]} { 
      $l1.c setvalue first
    } else {
      $l1.c configure -state disabled
		}
    pack $l1 -fill x
    switch $rule {
      MD1 {
        set l2 [LabelFrame ${name}d -text [get_text " on every " vcs_plug] \
                           -justify left -width $label_width -font $label_font]
        SpinBox $l2.s -text $rpar -width 2 -range [list 1 31 1] \
                      -font $dialog_font -textvariable ::VCS::SB_day
        label $l2.p -text $date_separator  
        eval "pack [winfo children $l2] -side left"
        pack $l2 -anchor w
      }
      D7 -
      W1 {
        set l3 [LabelFrame ${name}d -text [get_text " on every " vcs_plug]\
                           -justify left -width $label_width -font $label_font]
        foreach d [list MO TU WE] {
          set vn "wday_${d}"
          set rb $l3.[string tolower $d]
          checkbutton $rb -variable VCS::repeat_day($d) -text $weekdays($d)
        }
        eval "pack [winfo children $l3] -side left"
        pack $l3 -fill x
        set l4 [frame ${name}x]
        foreach d [list SU SA FR TH] {
          set vn "wday_${d}"
          set rb $l4.[string tolower $d]
          checkbutton $rb -variable VCS::repeat_day($d) -text $weekdays($d)
        }
        eval "pack [winfo children $l4] -side right"
        pack $l4 -fill x
        foreach d [array names weekdays] {
          if {[lsearch $rpar $d]<0} {
            set VCS::repeat_day($d) 0
          } else {
            set VCS::repeat_day($d) 1
          }
        }
      }
    }
  }
###
### Simple label entry - surprised ? ;-)
###
  proc label_entry { w id dval } {
    variable label_font
    variable dialog_font
    variable label_width
    debug_out "label_entry $w $id $dval" 5

    set name $w.[string tolower $id] 
    set dname [cat_label $id]
    LabelFrame $name -text $dname -justify left \
                      -width $label_width -font $label_font
    Entry $name.e -text $dval -bg white -justify left -font $dialog_font
    pack $name.e $name -expand 1 -fill x
  }
######################################################################
###  High level "master" widgets definitions and methods
### 
###  Listbox with all VCal entries
###
  proc create_listbox { path } {
    variable listbox_font
    variable label_font
    variable lb_widget
    variable cat_name
		variable top_list
    variable version

    set buttons [list \
		  [get_text "&Edit" vcs_plug]\
	  	  [get_text "Edit selected data record" vcs_plug]\
			  "[namespace current]::show_single"\
      [get_text "&Copy" vcs_plug] \
			  [get_text "Create new record using current selection" vcs_plug]\
        "[namespace current]::new_vcentry 1"\
      [get_text "C&reate" vcs_plug]\
			  [get_text "Create new data record" vcs_plug]\
        "[namespace current]::new_vcentry 0"\
      [get_text "&Delete" vcs_plug]\
			  [get_text "Delete selected data record" vcs_plug]\
        "[namespace current]::delete_rec"\
      [get_text "E&xport..." vcs_plug]\
			  [get_text "Export all records to text file" vcs_plug]\
				"[namespace current]::export_data"\
      [get_text "&Close" vcs_plug]\
			  [get_text "Close list window" vcs_plug]\
				"after idle {destroy $top_list}"\
    ]
    set wintitle [get_text "Obextool VCal-Plugin %s" vcs_plug] 
    set ftitle [format [get_text "VCal Folder: %s" vcs_plug] $path]
		set wtitle [format $wintitle $version]
    set sw [new_swindow $top_list $wtitle $ftitle $buttons 5 .]
    set lb_widget [tablelist::tablelist $sw.lbx \
                     -background white\
                     -font $listbox_font\
                     -labelrelief flat \
                     -showseparators 1 \
                     -columns [list 0 "#" right \
                                    0 $cat_name(CATEGORIES) \
                                    0 $cat_name(DTSTART) \
                                    0 $cat_name(DALARM) \
                                    0 $cat_name(DESCRIPTION) \
                                    0 $cat_name(RRULE)] \
                     -labelcommand tablelist::sortByColumn \
                     -height 15 -width 100 -stretch all]
    $lb_widget columnconfigure 0 -sortmode integer
    pack $lb_widget -expand yes -fill both
    $sw setwidget $lb_widget
    bind [$lb_widget bodypath] <Double-Button-1> \
		      "[namespace current]::show_single"
		BWidget::place $top_list 0 0 center .
		wm deiconify $top_list
  }
###
### insert an entry and values into appointment detail view
###
  proc insert_vcentry { w id val } {
    debug_out "insert_vcentry $w $id $val" 5
    switch $id {
      DTSTART -
      AALARM  -
      DALARM     { dtime_entry $w $id $val }
      CATEGORIES { combo_entry $w $id $val }
      RRULE      { rrule_entry $w $id $val }
      default    { label_entry $w $id $val }
    } 
  }
### 
###  insert one entry/line into listbox overwiew
###
  proc update_listbox { num mode } {
    variable obext_date 
    variable vcal_numbers
    variable date_lbformat 
    variable vcentry_idx
    variable vcal_array
    variable vcal_entr
    variable lb_widget
    variable top_list
debug_out "update_listbox $num $mode" 4

    set lentry(CATEGORIES)  {}
    set lentry(DTSTART)     {}
    set lentry(DALARM)      {}
    set lentry(DESCRIPTION) {}
    set lentry(RRULE)       {}

    if [set_vcal_entr $vcal_array($num)] return

    foreach entr $vcentry_idx {
      set idx [string first "," $entr]
      set typ [string range $entr 0 [expr $idx-1]]
      set vid [string range $entr [expr $idx+1] end]
      if {$typ eq "VEVENT"} {
        switch $vid {
          DTSTART - 
          AALARM  -
          DALARM      { 
            set res [scan $vcal_entr($entr) $obext_date Y M D h m s]
            if {$res == 6} {
              set lentry($vid) [format $date_lbformat $Y $M $D $h $m $s]
            } else {
              set lentry($vid) $vcal_entr($entr)
            }
          }
          CATEGORIES  {
            set lentry($vid) [cat_value $vcal_entr($entr)]
          }
          RRULE       {
            set lentry($vid) [rul_value $vcal_entr($entr)]
          }
          DESCRIPTION {
            set lentry($vid) $vcal_entr($entr)
          }
        } 
      }
    }
###
### Handle listbox entries, if "insert" mode 
### vcal_numbers handling is done by caller
###
		if [string_equal $mode "insert"] {
			$lb_widget insert end [list $num\
																	$lentry(CATEGORIES)\
																	$lentry(DTSTART)\
																	$lentry(DALARM)\
																	$lentry(DESCRIPTION)\
																	$lentry(RRULE)]
		} else {
			set vcal_numbers {}
      set imax [$lb_widget index end]
			for {set i 0} {$i<$imax} {incr i} {
				set id [lindex [$lb_widget get $i] 0]
        lappend vcal_numbers $id
				if {$id == $num} {
					$lb_widget delete $i
					if [string_equal $mode "replace"] {
						$lb_widget insert $i [list $num\
																			 $lentry(CATEGORIES)\
																			 $lentry(DTSTART)\
																			 $lentry(DALARM)\
																			 $lentry(DESCRIPTION)\
																			 $lentry(RRULE)]
						$lb_widget see $i
						$lb_widget selection clear 0 end
						$lb_widget selection set $i
					}
				}
			}
    }
  }
### 
### check if window $which already exists
###
  proc win_check { which name } {
  debug_out "win_check $which $name" 4
    if [winfo exists $which] {
      set msg [get_text "%s window already open!\nPlease" vcs_plug] 
      append msg [get_text " close it before opening a new one." vcs_plug] 
      warning [format $msg $name]
      return 1
    }
    return 0
  }
#################################################################
### Data management and file i/o functions
###
### Read one single VCal file and return list of VCal lines
###
  proc read_entry { path } {
    debug_out "read_entry $path" 4
    set local [ObexFile::read_file_tmp $path]
    if [string_empty $local] {
      warning [format [get_text "Unable to download file '%s'!" vcs_plug] $path]
      return {}
    }
    set fd [open $local "r"]
    fconfigure $fd -translation crlf 
    set vc_lines [split [read $fd] "\n"]
    close $fd
    file delete $local
    return $vc_lines
  }
###
### Download all VCal entries from the mobile
### $vcal_numbers is the list of VCal file names (in reading order)
### $vcal_array($name) internal storage of VCal file number as index
###
  proc download_entries { path } {
    variable vcal_numbers
    variable vcal_array
    global prg_msg bail vinc 
debug_out "download_entries $path" 4

    set flist [ObexFile::list_dir $path]
    set vmax [expr [llength $flist]-1]
    ProgressDlg .prg -command {set bail 1} \
      -variable vinc -textvariable prg_msg -maximum $vmax\
      -type normal -stop [get_text "Stop" vcs_plug] -width 50\
      -title [get_text "Reading all VCal entries..." vcs_plug]  
    set vinc 0
    set bail 0
    set vcal_numbers {}
    foreach entr $flist {
      if [string_equal [lindex $entr 1] "vcs"] {
        set fname [lindex $entr 0]
        set dentr "$path/$fname"
        set prg_msg [format [get_text "Reading %s..." vcs_plug] $dentr]
        set vcard [read_entry $dentr]
        if [string_empty $vcard] {return 0}

				set id [file rootname $fname]
        set vcal_array($id) $vcard
        lappend vcal_numbers $id
        incr vinc
        if $bail break
        status_msg [format [get_text "%d entries read." vcs_plug]  $vinc]
      }
    }
    if [winfo exists .prg] {destroy .prg}
    return $vinc
  }

###
### Analyse VCal lines and store VEVENT records in an array indexed  
### by "GROUP,INDEX", where GROUP is the value of last BEGIN: key and
### INDEX the active field name (line DTSTART, RRULE...)
###
  proc set_vcal_entr { vcard } {
	  variable supported_vcal_ver
    variable vcentry_idx
    variable vcal_entr
    debug_out "set_vcal_entr $vcard" 4
### We use unset var, because of TCL 8.2 compatibility
    if [info exists vcal_entr] {unset vcal_entr} 
    if {![string equal [lindex $vcard 0] "BEGIN:VCALENDAR"]} {
      warning [get_text "File does not seem to be a VCal file!" vcs_plug] 
      return 1
    }

    set level {}
    set vcentry_idx {}
    foreach vc $vcard {
      if [string_empty $vc] continue
      set si [string first ":" $vc]
      set key [string range $vc 0 [expr $si-1]]
      set val [string range $vc [expr $si+1] end]
      switch $key {
        BEGIN { set level [concat $val $level] }
        END   { set level [lrange $level 1 end] }
        default {
          set lvl [lindex $level 0]
          set idx "$lvl,$key"
          set vcal_entr($idx) $val
          lappend vcentry_idx $idx
### debug_out "vcal_entr($idx)=$vcal_entr($idx)" 5
        }
      }
    }
    if ![info exists vcal_entr(VCALENDAR,VERSION)] {
      warning [get_text "No version info in VCal File!" vcs_plug] 
      debug_vcal $vcentry_idx 1
      return 1
    } 
    if ![string_equal $vcal_entr(VCALENDAR,VERSION) $supported_vcal_ver] {
      set msg \
    [get_text "This plugin does not support version %s of VCal file!" vcs_plug] 
      warning [format $msg $vcal_entr(VCALENDAR,VERSION)]
      debug_vcal $vcentry_idx 1
      return 1
    }
    debug_vcal $vcentry_idx 8
    return 0
  }
###
### Create format to write data back to phone (VCal http://www.imc.org/pdi/)
###
  proc format_output { w id val } {
    variable repeat_day
    variable cat_type
    variable cat_rule
    variable obext_date
    debug_out "format_output $w $id $val" 5

    set name $w.[string tolower $id] 
    switch $id {
		DTSTART -
      AALARM  -
      DALARM { ; ### dtime_entry $w $id $val 
        set l1 ${name}d 
        set l2 ${name}t 
        set Y [ztrim [$l1.dy cget -text]]
        set M [ztrim [$l1.dm cget -text]]
        set D [ztrim [$l1.dd cget -text]]
        set h [ztrim [$l2.th cget -text]]
        set m [ztrim [$l2.tm cget -text]]
        set s [ztrim [$l2.ts cget -text]]
        return [format "$obext_date" $Y $M $D $h $m $s]
      }
      CATEGORIES { ; ### combo_entry $w $id $val 
        set lf $name
        set val [$lf.c cget -text]
        foreach cat [array names cat_type] {
          if [string_equal $val $cat_type($cat)] {
            return $cat
          }
        }
      }
      RRULE { ; ### rrule_entry $w $id $val 
        set rule ""
        set l1 ${name}r
        set rval [$l1.c cget -text]
        foreach cat [array names cat_rule] {
          if [string_equal $rval $cat_rule($cat)] {
            set rule $cat
            break;
          }
        }
        if [string_empty $rule] {return ""} 
### debug_var rule
        switch $rule {
          MD1 {
###         set l2 ${name}d
###         set v2 [ztrim [$l2.s cget -text]]
###         return [format "%s %02d" $rule $v2]
### Repeating day is sync'd with day of start date - ger
            set day [$w.dtstartd.dd cget -text]
            return [format "%s %02d" $rule $day]
          }
          D7 -
          W1 {
            set wdays ""
            foreach d [list MO TU WE TH FR SA SU] {
### debug_var ::VCS::repeat_day($d)
              if $VCS::repeat_day($d) { append wdays " $d" }
            }
            return "$rule$wdays"
          }
          default {
            return $rule
          }
        }
      }
      default {
        set val [$name.e cget -text]
        return $val
      }
    } 
  }
###
### Listbox callback on selection (Edit) of an entry
###
  proc export_data { } {
    variable export_header_line
    variable exportfile
    variable lb_widget
		variable top_list

    set def_ext [file extension $exportfile]
    set types [list [list [get_text "ASCII Text Files <TAB>" vcs_plug]      \
                    [list .txt]]\
                    [list [get_text "ASCII Files <Semicolon>" vcs_plug]     \
                    [list .dat]]\
                    [list [get_text "CSV Files <Comma separated>" vcs_plug] \
                    [list .csv]]\
                    [list [get_text "All files" vcs_plug]  [list "*"]]]
    set outn [tk_getSaveFile -parent $top_list\
                             -title [get_text "Export file" vcs_plug] \
                             -defaultextension $def_ext\
                             -filetypes $types\
                             -initialfile $exportfile]
    if [string_empty $outn] return

debug_var outn 4
    set new_ext [file extension $outn]
    if [string_empty $new_ext] { set outn $outn$def_ext }

    switch $new_ext {
      .txt    { set separator "\t" }
      .dat    { set separator ";"  }
      .csv    { set separator ","  }
      default { set separator "\t" }
    }
    set numrecs 0
    set fd [open $outn "w"] 
    set imax [$lb_widget columncount]
    if $export_header_line {
      set row {}
      for {set i 0} {$i<$imax} {incr i} {
        lappend row [$lb_widget columncget $i -title]
      }
      set line [join $row $separator]
      puts $fd $line
    }
    foreach row [$lb_widget get 0 end] {
      set line [join $row $separator]
      puts $fd $line
      incr numrecs
    }
    close $fd
    set msg [get_text "%d records written to file '%s'" vcs_plug]
    status_msg [format $msg $numrecs $outn]
  }
###
### Listbox callback on selection (Delete) of an entry
###
  proc delete_rec { } {
    variable pathname
    variable lb_widget
    variable vcal_entr
debug_out "delete_rec" 4
### Parameter $w currently not used here - ger

    set selidx [$lb_widget curselection]
		if [string_empty $selidx] {
		  warning [get_text "No record selected for deleting!" vcs_plug]
			return
		}
    set selected [$lb_widget get $selidx]
    set id [lindex $selected 0]
### if [set_vcal_entr $vcal_array($id)] return

    set delname $id.vcs
    set vcaldir [file dirname $pathname]
    set delpath "$vcaldir/$delname"

	  set qry [get_text\
	 	"Do you really want to delete the appointment entry %s?" vcs_plug]
		set title [get_text "Deleting appointment entry" vcs_plug]
    if [ask_yes_no $title [format $qry $id]] {
		  set_cursor on
	    ObexFile::obexftp rm $delpath
	    ObexTree::refresh_list ""
			set err 0
		  foreach entr $ObexTree::dir_list {
			  if [string_equal $entr $delpath] { set err 1 }
      }
			if $err {
			  set msg [get_text "Schedule entry %s could not be deleted!"]
				no_permission [format $msg $id]
			} else {
				update_listbox $id delete
			}
		  set_cursor 
    }
  }

###
### Listbox callback on selection (Edit) of an entry
###
  proc show_single { } {
    variable vcal_array
    variable top_level
    variable top_list
    variable version
    variable pathname
    variable lb_widget
debug_out "show_single" 4

    if [win_check $top_level [get_text "VCal detail data" vcs_plug] ] return

    set selidx [$lb_widget curselection]
		if [string_empty $selidx] {
		  warning [get_text "No record selected for editing!" vcs_plug]
			return
		}
    set selected [$lb_widget get $selidx]
    set id [lindex $selected 0]

    set newname $id.vcs
    set old_dir [file dirname $pathname]
    set pathname "$old_dir/$newname"

    set vcard [read_entry $pathname]
    if [string_empty $vcard] return
    if [set_vcal_entr $vcard] return

    vc_dialog $top_list $pathname 0 0
    set vcal_array($id) $vcard
### update_listbox $id replace
  }
###
### Save data (write back) callback on "Save" inVCal detail view
###
  proc save_data { path is_new } {
	  variable top_list
		variable top_level
    variable vcal_entr
		variable vcal_array
    variable vcentry_idx
    variable prev_widget 
    variable tmp_prefix
		variable dataframe
    debug_out "save_data $path $is_new" 4

    set vcs_dir [file dirname $path]
    set id [file rootname [file tail $path]]
    set backup(VCALENDAR,VERSION) "$vcal_entr(VCALENDAR,VERSION)"
    set result [list "BEGIN:VCALENDAR" \
                     $backup(VCALENDAR,VERSION) \
                     "BEGIN:VEVENT" ]
    foreach rule [array names cat_rule] { set rcheck($rule) {} }
		set dcheck ""
    foreach entr $vcentry_idx {
      set idx [string first "," $entr]
      set typ [string range $entr 0 [expr $idx-1]]
      set vid [string range $entr [expr $idx+1] end]
      if {$typ eq "VEVENT"} {

        set vc_entr [format_output $dataframe $vid $vcal_entr($entr)]
        if [string_equal $vid "RRULE"] {
### Rules with "W1" and "D7" are ignored -> no weekdays!
					if [string_equal $vc_entr "W1"] continue 
					if [string_equal $vc_entr "D7"] continue 
        } 

        set backup($entr) $vc_entr
debug_var backup($entr) 6
        if [string_empty $vc_entr] {
          set msg [get_text "No valid VCal entry for\n%s: %s" vcs_plug] 
          warning [format $msg $vid $vc_entr] 
          return
        }
        lappend result "$vid:$vc_entr"
      }
      debug_var entr 5
    }
    lappend result "END:VEVENT" "END:VCALENDAR"
    if ![ask_yes_no [get_text "Confirm" vcs_plug] \
          [get_text "Do you really want to store this record?" vcs_plug]] {
      return 1
    }
debug_var result 3
    set cnt 0
    while 1 { 
      set fn $tmp_prefix[incr cnt].tmp 
      if ![file exists $fn] break
    }

    set fd [open $fn "w"]
    fconfigure $fd -translation crlf 
    foreach line $result {
		  puts $fd $line
			debug_var line 6
	}
debug_var fn 3
    close $fd
    set msg [get_text "Uploading file '%s' to '%s'..." vcs_plug]
    status_msg [format $msg $fn $path]
### We don't check if file exists - even on new entry...
    ObexFile::write_file_tmp $fn $path
###
### Consistency checks
### 
    set vcard [read_entry $path]
    if [string_empty $vcard] return
    if [set_vcal_entr $vcard] return

    set bk_list [array names backup]
    set vc_list [array names vcal_entr]
    set msg {}
    if {[llength $bk_list] != [llength $vc_list]} {
     set msg [get_text "Missing records in stored entry:" vcs_plug]
     foreach idx $bk_list {
       if ![info exists vcal_entr($idx)] {
			   set code [lindex [split $idx ","] 1]
         append msg [format "\n$code:$backup($idx)"]
       }
     }
     foreach idx $vc_list {
       if ![info exists backup($idx)] {
         append msg [format "\n$idx:$vcal_entr($idx)"]
       }
     }
    } else {
      foreach idx $vc_list {
        if ![string_equal $backup($idx) $vcal_entr($idx)] {
          append msg [format "\n%s\n%s" $vcal_entr($idx) $backup($idx)]
        }
      }
      if ![string_empty $msg] {
        set msg [format \
				  [get_text "Saved entries not identical to input entry:%s" vcs_plug]\
					$msg]
      }
    }
    if ![string_empty $msg] {warning [format $msg]}
    destroy $top_level

    set msg [get_text "File '%s' stored" vcs_plug]
    ObexTree::refresh_list [format $msg $path]
	  if [winfo exists $prev_widget] { wm deiconify $prev_widget }
### is it the lis subwindow?
		if [string_equal $prev_widget $top_list] {
      set vcal_array($id) $vcard
      if $is_new {
        lappend vcal_numbers $id
        update_listbox $id insert
			} else {
        update_listbox $id replace
			}
    }
    return 0
  }

  proc new_vcentry { copy } {
    debug_out "new_vcentry $copy" 4
		variable supported_vcal_ver
		variable show_alarmtime
	  variable vcal_numbers
	  variable vcal_entr
		variable lb_widget 
		variable top_level
		variable top_list
		variable pathname

    if [win_check $top_level [get_text "VCal detail data" vcs_plug] ] return

		set id 0
    set vcs_dir [file dirname $pathname]
debug_var vcal_numbers 3
		while 1 {
			if {[lsearch $vcal_numbers [incr id]]<0} break
		}

		set newpath "$vcs_dir/$id.vcs"
		set tomorrow [expr [clock seconds]+(60*60*24)]
		set date [clock format $tomorrow -format "%Y%m%dT%H%M00"]

    if $copy {
      set selidx [$lb_widget curselection]
      if [string_empty $selidx] {
        warning [get_text "No record selected for copying!" vcs_plug]
        return
      }
      set selidx [$lb_widget curselection]
		  debug_var selidx 4
      set selected [$lb_widget get $selidx]
			debug_var selected 3
      set id [lindex $selected 0]
      set vcard [read_entry "$vcs_dir/$id.vcs"]
      set_vcal_entr $vcard
		} else {
  		if [info exists vcal_entr] {unset vcal_entr}
		}

### debug_var newpath
### debug_arr vcal_entr
    set vc_new [list "BEGIN:VCALENDAR" \
		                 "VERSION:$supported_vcal_ver" \
										 "BEGIN:VEVENT"]
### debug_var vcal_entr(VEVENT,CATEGORIES)
		if [info exists vcal_entr(VEVENT,CATEGORIES)] {
		  lappend vc_new "CATEGORIES:$vcal_entr(VEVENT,CATEGORIES)"
		} else {
#		  lappend vc_new "CATEGORIES:MISCELLANEOUS"
		  lappend vc_new "CATEGORIES:"
		}
### debug_var vcal_entr(VEVENT,DTSTART)
		if [info exists vcal_entr(VEVENT,DTSTART)] {
		  lappend vc_new "DTSTART:$vcal_entr(VEVENT,DTSTART)"
		} else {
		  lappend vc_new "DTSTART:$date"
		}
		if ($show_alarmtime) {
### debug_var vcal_entr(VEVENT,DALARM)
			if [info exists vcal_entr(VEVENT,DALARM)] {
				lappend vc_new "DALARM:$vcal_entr(VEVENT,DALARM)"
			} else {
				lappend vc_new "DALARM:$date"
			}
		}
### debug_var vcal_entr(VEVENT,RRULE)
		if [info exists vcal_entr(VEVENT,RRULE)] {
		  lappend vc_new "RRULE:$vcal_entr(VEVENT,RRULE)"
		} else {
    	lappend vc_new "RRULE:W1"
		}
### debug_var vcal_entr(VEVENT,DESCRIPTION)
		if [info exists vcal_entr(VEVENT,DESCRIPTION)] {
		  lappend vc_new "DESCRIPTION:$vcal_entr(VEVENT,DESCRIPTION)"
		} else {
		  lappend vc_new "DESCRIPTION:"
		}
    lappend vc_new "END:VEVENT" "END:VCALENDAR"

### debug_var vc_new 4
    if [set_vcal_entr $vc_new] return
	  vc_dialog $top_list $newpath 1 0
	}

###################################################################
### Top level dialogues and fillup functions
### 
###  Single appointment detail view
###
  proc vc_dialog { parent path is_new is_top } {
    variable version
    variable top_list
    variable top_level
    variable vcal_entr
    variable vcentry_idx
		variable dataframe
    variable label_font
    variable prev_widget $parent

    debug_out "vc_dialog $parent $path $is_new $is_top" 4

	  set buttons [list \
		   [get_text "&Save" vcs_plug]\
			   [get_text "Write entry to device" vcs_plug]\
			   "[namespace current]::save_data $path $is_new"]
    if $is_top {
		 lappend buttons \
		   [get_text "&Read all" vcs_plug]\
				 [get_text "Read all entries and open list" vcs_plug]\
				 "[namespace current]::vc_listbox $path"
      set active 2
			set parent .
		} else {
      set active 1
			set parent $top_list
    }
		lappend buttons \
       [get_text "&Close" vcs_plug]\
			   [get_text "Close detail view window"]\
         "after idle {[namespace current]::close_dialog $prev_widget}"

    set tstr [get_text "Obextool VCal-Plugin %s" vcs_plug] 
		set wtitle [format $tstr $version]
		if $is_new {
		  set frame_str [get_text "New VCal Entry: %s" vcs_plug]
		} else {
		  set frame_str [get_text "Edit VCal Entry: %s" vcs_plug]
		}

    set ftitle [format $frame_str [file tail $path]]
    set dataframe [new_window $top_level $wtitle $ftitle $buttons $active $parent]

    foreach entr $vcentry_idx {
      set idx [string first "," $entr]
      set typ [string range $entr 0 [expr $idx-1]]
      set vid [string range $entr [expr $idx+1] end]
      if {$typ eq "VEVENT"} {
        insert_vcentry $dataframe $vid $vcal_entr($entr)
      }
      debug_var entr 5
    }

		BWidget::place $top_level 0 0 center .
		wm deiconify $top_level
  }
	###
	### Close dialog
	###
	proc close_dialog {  prev } {
	  variable top_level
	  destroy $top_level
		wm deiconify $prev
  }
###
### Create listbox of all VCal entries
###
  proc vc_listbox { path } {
    variable version
		variable top_list
    variable top_level
    variable lb_widget
    variable vcal_numbers
    debug_out "vc_listbox $path" 4

    if [win_check $top_list [get_text "VCal overview" vcs_plug]] return

    set vcs_dir [file dirname $path]
    set vcs_id [file tail [file rootname $path]]
    if ![download_entries $vcs_dir] return

    catch {destroy $top_level}
    create_listbox $vcs_dir

    set cnt 0
    set sel -1
    foreach num $vcal_numbers { 
      update_listbox $num insert
      if {$num eq $vcs_id} {set sel $cnt}
      incr cnt
    }
    if {$sel != -1} {
      $lb_widget selection set $sel
      $lb_widget see $sel
    }
  }
###
### ObexTool main entry point
###
  proc default_handler { args } {
    variable top_level
    variable init_all_entries
    variable pathname [lindex $args 0]
    debug_out "[namespace current]::default_handler $args" 5

    if [win_check $top_level [get_text "VCal detail data" vcs_plug] ] return

    if $init_all_entries {
      vc_listbox $pathname
    } else {
      set vcard [read_entry $pathname]
      if [string_empty $vcard] return
      if [set_vcal_entr $vcard] return
      vc_dialog . $pathname 0 1
		}
  }

  ###
  ### Warning on load of plugin - there is a strange behaviour on 
  ### Siemens phones - ger
  ###
  if $siemens_warning {
    set msg [get_text "On Siemens mobiles, all uploaded" vcs_plug] 
    append msg [get_text " entries are deactivated by default." vcs_plug]
    append msg [get_text " Don't forget to activate any modified" vcs_plug]
    append msg [get_text " entry in the options of your phone directly." vcs_plug] 
    warning $msg
  }
}

return $::VCS::version