home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1999 March B / SCO_CASTOR4RRT.iso / scoadmin / root.3 / etc / mail / admin / channel / channel~
Text File  |  1998-08-19  |  61KB  |  1,960 lines

  1. #!/bin/osavtcl
  2. #******************************************************************************
  3. #
  4. #    Copyright (C) 1993-1997 The Santa Cruz Operation, Inc.
  5. #        All Rights Reserved.
  6. #
  7. #    The information in this file is provided for the exclusive use of
  8. #    the licensees of The Santa Cruz Operation, Inc.  Such users have the
  9. #    right to use, modify, and incorporate this code into other products
  10. #    for purposes authorized by the license agreement provided they include
  11. #    this notice and the associated copyright notice with any such product.
  12. #    The information in this file is provided "AS IS" without warranty.
  13. #
  14. #===============================================================================
  15. loadlibindex /usr/lib/sysadm.tlib
  16. proc SCO_MAIL_ADMIN_CHANNEL_MSGS {} {}
  17. global SCO_MAIL_ADMIN_CHANNEL_MSGS
  18. set SCO_MAIL_ADMIN_CHANNEL_MSGS(@catalog@) {channel.cat@mail 1}
  19. set SCO_MAIL_ADMIN_CHANNEL_MSGS(MSG_HELPBOOK) {1 channel}
  20. set SCO_MAIL_ADMIN_CHANNEL_MSGS(MSG_TITLE) {2 {Channel Table File %1$s}}
  21. set SCO_MAIL_ADMIN_CHANNEL_MSGS(MSG_ITEMS) {3 Entries}
  22. set SCO_MAIL_ADMIN_CHANNEL_MSGS(MSG_FILE_DOESNT_EXIST) {4 {File does not exist}}
  23. set SCO_MAIL_ADMIN_CHANNEL_MSGS(MSG_OK) {5 OK}
  24. set SCO_MAIL_ADMIN_CHANNEL_MSGS(MSG_CANCEL) {6 Cancel}
  25. set SCO_MAIL_ADMIN_CHANNEL_MSGS(MSG_HELP) {7 Help}
  26. set SCO_MAIL_ADMIN_CHANNEL_MSGS(MSG_COLUMN_HOST_LBL) {8 Host}
  27. set SCO_MAIL_ADMIN_CHANNEL_MSGS(MSG_COLUMN_FORWARD_LBL) {9 {Forward Via}}
  28. set SCO_MAIL_ADMIN_CHANNEL_MSGS(MSG_OBJECT) {10 Entry}
  29. set SCO_MAIL_ADMIN_CHANNEL_MSGS(MSG_OBJECT_MN) {11 E}
  30. set SCO_MAIL_ADMIN_CHANNEL_MSGS(MSG_ENTRY_MENU_ADD_LBL) {12 Add...}
  31. set SCO_MAIL_ADMIN_CHANNEL_MSGS(MSG_ENTRY_MENU_ADD_MN) {13 A}
  32. set SCO_MAIL_ADMIN_CHANNEL_MSGS(MSG_ENTRY_MENU_ADD_SH) {14 {Add a channel table entry...}}
  33. set SCO_MAIL_ADMIN_CHANNEL_MSGS(MSG_ENTRY_MENU_DELETE_LBL) {15 Delete}
  34. set SCO_MAIL_ADMIN_CHANNEL_MSGS(MSG_ENTRY_MENU_DELETE_MN) {16 D}
  35. set SCO_MAIL_ADMIN_CHANNEL_MSGS(MSG_ENTRY_MENU_DELETE_SH) {17 {Delete a channel table entry}}
  36. set SCO_MAIL_ADMIN_CHANNEL_MSGS(MSG_ENTRY_MENU_MODIFY_LBL) {18 Modify...}
  37. set SCO_MAIL_ADMIN_CHANNEL_MSGS(MSG_ENTRY_MENU_MODIFY_MN) {19 M}
  38. set SCO_MAIL_ADMIN_CHANNEL_MSGS(MSG_ENTRY_MENU_MODIFY_SH) {20 {Modify a channel table entry...}}
  39. set SCO_MAIL_ADMIN_CHANNEL_MSGS(MSG_ENTRY_MENU_UP_LBL) {21 {Move Up}}
  40. set SCO_MAIL_ADMIN_CHANNEL_MSGS(MSG_ENTRY_MENU_UP_MN) {22 U}
  41. set SCO_MAIL_ADMIN_CHANNEL_MSGS(MSG_ENTRY_MENU_UP_SH) {23 {Move a channel table entry up in order}}
  42. set SCO_MAIL_ADMIN_CHANNEL_MSGS(MSG_ENTRY_MENU_DOWN_LBL) {24 {Move Down}}
  43. set SCO_MAIL_ADMIN_CHANNEL_MSGS(MSG_ENTRY_MENU_DOWN_MN) {25 o}
  44. set SCO_MAIL_ADMIN_CHANNEL_MSGS(MSG_ENTRY_MENU_DOWN_SH) {26 {Move a channel table entry down in order}}
  45. set SCO_MAIL_ADMIN_CHANNEL_MSGS(MSG_ENTRY_MENU_SAVE_LBL) {27 Save}
  46. set SCO_MAIL_ADMIN_CHANNEL_MSGS(MSG_ENTRY_MENU_SAVE_MN) {28 S}
  47. set SCO_MAIL_ADMIN_CHANNEL_MSGS(MSG_ENTRY_MENU_SAVE_SH) {29 {Save any changes}}
  48. set SCO_MAIL_ADMIN_CHANNEL_MSGS(MSG_ENTRY_MENU_EXIT_LBL) {30 Exit}
  49. set SCO_MAIL_ADMIN_CHANNEL_MSGS(MSG_ENTRY_MENU_EXIT_MN) {31 x}
  50. set SCO_MAIL_ADMIN_CHANNEL_MSGS(MSG_ENTRY_MENU_EXIT_SH) {32 {Exit %s}}
  51. set SCO_MAIL_ADMIN_CHANNEL_MSGS(MSG_OPTIONS_MENU) {33 Options}
  52. set SCO_MAIL_ADMIN_CHANNEL_MSGS(MSG_OPTIONS_MN) {34 O}
  53. set SCO_MAIL_ADMIN_CHANNEL_MSGS(MSG_OPTIONS_TOOLBAR) {35 Toolbar}
  54. set SCO_MAIL_ADMIN_CHANNEL_MSGS(MSG_OPTIONS_TOOLBAR_SH) {36 {Show/hide Toolbar}}
  55. set SCO_MAIL_ADMIN_CHANNEL_MSGS(MSG_ADD_TITLE) {37 {Add Channel Table Entry}}
  56. set SCO_MAIL_ADMIN_CHANNEL_MSGS(MSG_MODIFY_TITLE) {38 {Modify Channel Table Entry}}
  57. set SCO_MAIL_ADMIN_CHANNEL_MSGS(MSG_NAME_LBL) {39 {Host Name}}
  58. set SCO_MAIL_ADMIN_CHANNEL_MSGS(MSG_NAME_SH) {40 {Enter the host name to be matched for this entry}}
  59. set SCO_MAIL_ADMIN_CHANNEL_MSGS(ERR_NAME_MISSING) {41 {No host name specified for \"Host Name\" field}}
  60. set SCO_MAIL_ADMIN_CHANNEL_MSGS(ERR_NAME_DUPLICATE) {42 {An entry for host name \"%1$s\" already exists}}
  61. set SCO_MAIL_ADMIN_CHANNEL_MSGS(MSG_REAL_NAME_LBL) {43 {Forwarding Host Name}}
  62. set SCO_MAIL_ADMIN_CHANNEL_MSGS(MSG_REAL_NAME_SH) {44 {Enter the host mail will be forwarded to}}
  63. set SCO_MAIL_ADMIN_CHANNEL_MSGS(ERR_REAL_NAME_MISSING) {45 {No host name specified for \"Forwarding Host Name\" field}}
  64. set SCO_MAIL_ADMIN_CHANNEL_MSGS(MSG_SELECT_BTN_LBL) {46 Select...}
  65. set SCO_MAIL_ADMIN_CHANNEL_MSGS(ERR_NAME_SPACE) {47 {A host name may not contain a space}}
  66. set SCO_MAIL_ADMIN_CHANNEL_MSGS(MSG_ROUTE_LIST_LBL) {48 {Route to host:}}
  67. set SCO_MAIL_ADMIN_CHANNEL_MSGS(ERR_ENTER_NAME) {49 {You did not enter a host name}}
  68. set SCO_MAIL_ADMIN_CHANNEL_MSGS(MSG_ROUTE_ADD_BTN_LBL) {50 {    Add...   }}
  69. set SCO_MAIL_ADMIN_CHANNEL_MSGS(MSG_ROUTE_ADD_BTN_SH) {51 {Add a host to the route}}
  70. set SCO_MAIL_ADMIN_CHANNEL_MSGS(MSG_ROUTE_DELETE_BTN_LBL) {52 {   Delete   }}
  71. set SCO_MAIL_ADMIN_CHANNEL_MSGS(MSG_ROUTE_DELETE_BTN_SH) {53 {Delete a host from the route}}
  72. set SCO_MAIL_ADMIN_CHANNEL_MSGS(MSG_ROUTE_UP_BTN_SH) {54 {Move this host name up in the route}}
  73. set SCO_MAIL_ADMIN_CHANNEL_MSGS(MSG_ROUTE_DOWN_BTN_SH) {55 {Move this host name down in the route}}
  74. set SCO_MAIL_ADMIN_CHANNEL_MSGS(MSG_DO_PARTIAL_LBL) {56 {Do subdomain lookups}}
  75. set SCO_MAIL_ADMIN_CHANNEL_MSGS(MSG_DO_PARTIAL_SH) {57 {Allow subdomain lookups on the host name}}
  76. set SCO_MAIL_ADMIN_CHANNEL_MSGS(MSG_ROUTE_ADD_DLG_TITLE) {58 {Add To Route}}
  77. set SCO_MAIL_ADMIN_CHANNEL_MSGS(MSG_ROUTE_ADD_DLG_TEXT_LBL) {59 {Enter host name(s):}}
  78. set SCO_MAIL_ADMIN_CHANNEL_MSGS(MSG_SAVE_CONFIRM_TITLE) {60 {Save Changes?}}
  79. set SCO_MAIL_ADMIN_CHANNEL_MSGS(MSG_SAVE_CONFIRM_QUERY) {61 {Do you wish to save the changes made?}}
  80. set SCO_MAIL_ADMIN_CHANNEL_MSGS(MSG_SAVE_CONFIRM_BTN_YES) {62 Yes}
  81. set SCO_MAIL_ADMIN_CHANNEL_MSGS(MSG_SAVE_CONFIRM_BTN_NO) {63 No}
  82. set SCO_MAIL_ADMIN_CHANNEL_MSGS(MSG_SAVE_CONFIRM_BTN_CANCEL) {64 Cancel}
  83. set SCO_MAIL_ADMIN_CHANNEL_MSGS(MSG_TB_ADD) {65 Add...}
  84. set SCO_MAIL_ADMIN_CHANNEL_MSGS(MSG_TB_DELETE) {66 Delete}
  85. set SCO_MAIL_ADMIN_CHANNEL_MSGS(MSG_TB_MODIFY) {67 Modify...}
  86. set SCO_MAIL_ADMIN_CHANNEL_MSGS(MSG_BTN_UP_PX) {68 /etc/mail/admin/px/prev.px}
  87. set SCO_MAIL_ADMIN_CHANNEL_MSGS(MSG_BTN_DOWN_PX) {69 /etc/mail/admin/px/next.px}
  88. set SCO_MAIL_ADMIN_CHANNEL_MSGS(MSG_SELECTED) {70 Selected}
  89. set SCO_MAIL_ADMIN_CHANNEL_MSGS(MSG_COUNT_LABEL_STRING) {71 {%1$s %2$s, %3$s %4$s}}
  90. set SCO_MAIL_ADMIN_CHANNEL_MSGS(MSG_PARTIAL_LABEL_STRING) {72 {* this entry allows subdomain lookups on the host name}}
  91. set SCO_MAIL_ADMIN_CHANNEL_MSGS(MSG_INIT) {73 Initializing...}
  92. set SCO_MAIL_ADMIN_CHANNEL_MSGS(MSG_REFRESH) {74 {Loading channel table data...}}
  93. set SCO_MAIL_ADMIN_CHANNEL_MSGS(MSG_SAVE) {75 {Saving channel table data...}}
  94. set SCO_MAIL_ADMIN_CHANNEL_MSGS(ERR_USAGE) {76 {Usage: %1$s -f filename [-h hostname]}}
  95. set SCO_MAIL_ADMIN_CHANNEL_MSGS(ERR_DIRECTORY) {77 {\"%1$s\" is a directory, not a file}}
  96. set SCO_MAIL_ADMIN_CHANNEL_MSGS(ERR_DATABASE) {78 {Unable to create channel table database\n\"%1$s\"}}
  97. set SCO_MAIL_ADMIN_CHANNEL_MSGS(ERR_WRITE) {79 {Unable to write channel table file\n\"%1$s\"}}
  98. set SCO_MAIL_ADMIN_CHANNEL_MSGS(ERR_LOAD) {80 {Unable to load channel table file\n\"%1$s\"}}
  99. set SCO_MAIL_ADMIN_CHANNEL_MSGS(ERR_NONSTDCMD) {81 %s}
  100. set appvals(intlpre) SCO_MAIL_ADMIN_CHANNEL        ;# i10n msg prefix
  101. proc IntlMsg {id {argList {}}} {
  102.     global appvals
  103.     return [IntlLocalizeMsg $appvals(intlpre)_MSG_$id $argList]
  104. }
  105. proc IntlErr {id {argList {}}} {
  106.     global appvals
  107.     return [IntlLocalizeMsg $appvals(intlpre)_ERR_$id $argList]
  108. }
  109. proc IntlErrId {id} {
  110.     global appvals
  111.     return $appvals(intlpre)_ERR_$id
  112. }
  113. proc ConfigFile:Open {} {
  114.     global Config_next
  115.     if {![info exists Config_next]} {
  116.     set Config_next 0
  117.     }
  118.     set file "config$Config_next"
  119.     incr Config_next
  120.     upvar #0 Config_${file}_next file_next
  121.     set file_next "1.0"
  122.     return $file
  123. }
  124. proc ConfigFile:Close {file} {
  125.     upvar #0 Config_$file fileList
  126.     upvar #0 Config_${file}_next file_next
  127.     unset file_next
  128.     foreach line [ConfigFile:GetList $file] {
  129.     unset fileList($line)
  130.     }
  131. }
  132. proc ConfigFile:Compare {line1 line2} {
  133.     set subLine1 [ctoken line1 "."]
  134.     set subLine2 [ctoken line2 "."]
  135.     if {$subLine1 == "" && $subLine2 == ""} {
  136.     return 0
  137.     } elseif {$subLine1 == ""} {
  138.     return -1
  139.     }  elseif {$subLine2 == ""} {
  140.     return 1
  141.     } elseif {$subLine1 < $subLine2} {
  142.     return -1
  143.     } elseif {$subLine1 > $subLine2} {
  144.     return 1
  145.     } else {
  146.     set line1 [string trimleft $line1 "."]
  147.     set line2 [string trimleft $line2 "."]
  148.     return [ConfigFile:Compare $line1 $line2]
  149.     }
  150. }
  151. proc ConfigFile:ReplaceLine {file line type id dataVar} {
  152.     upvar #0 Config_$file fileList
  153.     upvar #0 Config_${file}_next file_next
  154.     upvar $dataVar data
  155.     keylset fileList($line) type $type
  156.     keylset fileList($line) data $data
  157.     keylset fileList($line) id $id
  158.     if {[ConfigFile:Compare $line $file_next] == 1} {
  159.     set temp $line
  160.     set file_next [ctoken temp "."]
  161.     incr file_next
  162.     set file_next "${file_next}.0"
  163.     }
  164. }
  165. proc ConfigFile:AppendLine {file line type id dataVar} {
  166.     upvar #0 Config_$file fileList
  167.     upvar #0 Config_${file}_next file_next
  168.     upvar $dataVar data
  169.     if {$line == -1} {
  170.     set line $file_next
  171.     set temp [ctoken file_next "."]
  172.     incr temp
  173.     set file_next "${temp}.0"
  174.     } else {
  175.     set found 0
  176.     set left [ctoken line "."]
  177.     set right [ctoken line "."]
  178.     if {$right == "0"} {
  179.         set tryNext $left
  180.         incr tryNext
  181.         set tryNext "${tryNext}.0"
  182.         if {![info exists fileList($tryNext)]} { 
  183.         set found 1
  184.         }
  185.     }
  186.     if {!$found} {
  187.         set lastDigit [cindex $right end]
  188.         if {$lastDigit < 9} {
  189.             incr lastDigit
  190.             set tryNext "${left}.[csubstr $right 0 end]${lastDigit}"
  191.             if {![info exists fileList($tryNext)]} {
  192.             set found 1
  193.             }    
  194.         }
  195.     }
  196.     if {!$found} {
  197.         set leadingZeros ""
  198.         set tryNext "${left}.${right}.1"
  199.         while {[info exists fileList($tryNext)]} {
  200.         set leadingZeros "${leadingZeros}.0"
  201.         set tryNext "${left}.${right}${leadingZeros}.1"
  202.         }
  203.     }
  204.     set line $tryNext
  205.     }
  206.     keylset fileList($line) type $type
  207.     keylset fileList($line) id $id
  208.     keylset fileList($line) data $data
  209.     if {[string compare $line $file_next] == 1} {
  210.     set temp $line
  211.     set file_next [ctoken temp "."]
  212.     incr file_next
  213.     set file_next "${file_next}.0"
  214.     }
  215.     return $line
  216. }
  217. proc ConfigFile:GetLine {file line typeVar idVar dataVar} {
  218.     upvar #0 Config_$file fileList
  219.     upvar $typeVar type
  220.     upvar $idVar id
  221.     upvar $dataVar data
  222.     if {![info exists fileList($line)]} {
  223.     set type {}
  224.     set id {}
  225.     set data {}
  226.     return -1
  227.     }
  228.     keylget fileList($line) type type
  229.     keylget fileList($line) id id
  230.     keylget fileList($line) data data
  231.     return 0
  232. }
  233. proc ConfigFile:RemoveLine {file line} {
  234.     upvar #0 Config_$file fileList
  235.     if {![info exists fileList($line)]} {
  236.     # already gone
  237.     return
  238.     }
  239.     unset fileList($line)
  240. }
  241. proc ConfigFile:GetList {file} {
  242.     upvar #0 Config_$file fileList
  243.     if {![info exists fileList]} {
  244.     return {}
  245.     }
  246.     return [lsort -command ConfigFile:Compare [array names fileList]]
  247. }
  248. proc Table:ProcessLine {fileID type id data} {
  249.     global Table_lastType Table_lastID
  250.     set lineNum [ConfigFile:AppendLine $fileID -1 $type $id data]
  251.     if {[Table:GetOption $fileID makelower] != {}} {
  252.     set id [string tolower $id]
  253.     }
  254.     case $type {
  255.     CONTINUATION {
  256.         set type $Table_lastType
  257.         set id $Table_lastID
  258.     }
  259.     COMMENT {
  260.     }
  261.     default {
  262.         set Table_lastType $type
  263.         set Table_lastID $id
  264.     }
  265.     }
  266.     if {$id != {}} {
  267.     upvar #0 Table_${fileID}_$type typeList
  268.     lappend typeList($id) $lineNum
  269.     }
  270. }
  271. proc Table:Read {fileName callBack mode} {
  272.     global Table_info
  273.     if {[info exists Table_info($fileName.ID)]} {
  274.     return $Table_info($fileName.ID)
  275.     }
  276.     set fileID [ConfigFile:Open]
  277.     set Table_info($fileID.mode) $mode
  278.     if {![file exists $fileName]} {
  279.     return $fileID
  280.     }
  281.     set fp [open $fileName r]
  282.     set Table_info($fileName.ID) $fileID
  283.     set Table_info($fileID.fileName) $fileName
  284.     eval $callBack $fileID $fp
  285.     close $fp
  286.     return $fileID
  287. }
  288. proc Table:Write {fileID {fileName {}} {callBack {}}} {
  289.     global Table_info
  290.     if {[info exists Table_info($fileID.deferred)]} {
  291.     return
  292.     }
  293.     if {![info exists Table_info($fileID.modified)] && $fileName == {}} {
  294.     return
  295.     }
  296.     if {$callBack == {}} {
  297.     set callBack $Table_info($fileID.writeCB)
  298.     }
  299.     if {$fileName == {}} {
  300.     set fileName $Table_info($fileID.fileName)
  301.     set clearModified 1
  302.     } else {
  303.     set clearModified 0
  304.     }
  305.     #
  306.     # If the file exists, make sure the new file has the
  307.     # same owner and perms.  Otherwise, make sure the
  308.     # parent directory exists.
  309.     #
  310.     if {[file exists $fileName]} {
  311.     file stat $fileName info
  312.     set Table_info($fileID.uid) $info(uid)
  313.     set Table_info($fileID.gid) $info(gid)
  314.     set Table_info($fileID.mode) $info(mode)
  315.     } else {
  316.     set directory [file dirname $fileName]
  317.     set oldUmask [umask]
  318.     umask 0222
  319.     if {![file isdirectory $directory]} {
  320.         mkdir -path $directory
  321.     }
  322.     umask $oldUmask
  323.     }
  324.     set fp [open ${fileName}.new w]
  325.     chmod $Table_info($fileID.mode) ${fileName}.new
  326.     if {[info exists Table_info($fileID.uid)]} {
  327.     chown [list $Table_info($fileID.uid) $Table_info($fileID.gid)] \
  328.         ${fileName}.new
  329.     }
  330.     foreach line [ConfigFile:GetList $fileID] {
  331.     if {[ConfigFile:GetLine $fileID $line type id data] != 0} {
  332.         continue
  333.     }
  334.     eval "$callBack $fileID $fp {$type} {$id} {$data}"
  335.     }
  336.     close $fp
  337.     if {[file exists $fileName]} {
  338.     unlink $fileName
  339.     }
  340.     frename ${fileName}.new $fileName
  341.     if {$clearModified} {
  342.     unset Table_info($fileID.modified)
  343.     }
  344. }
  345. proc Table:Open {fileName readCB writeCB {mode 0666}} {
  346.     global Table_info
  347.     set fileID [Table:Read $fileName $readCB $mode]
  348.     set Table_info($fileID.fileName) $fileName
  349.     set Table_info($fileID.readCB) $readCB
  350.     set Table_info($fileID.writeCB) $writeCB
  351.     set Table_info($fileName.ID) $fileID
  352.     return $fileID
  353. }
  354. proc Table:Close {fileID {fileName {}}} {
  355.     global Table_info
  356.     if {![info exists Table_info($fileID.fileName)]} {
  357.     return
  358.     }
  359.     if {[info exists Table_info($fileID.deferred)]} {
  360.     unset Table_info($fileID.deferred)
  361.     }
  362.     Table:Write $fileID $fileName $Table_info($fileID.writeCB)
  363.     if {$fileName == {}} {
  364.     set fileName $Table_info($fileID.fileName)
  365.     }
  366.     unset Table_info($fileID.fileName)
  367.     unset Table_info($fileName.ID)
  368.     ConfigFile:Close $fileID
  369. }
  370. proc Table:CloseNoWrite {fileID {fileName {}}} {
  371.     global Table_info
  372.     if {![info exists Table_info($fileID.fileName)]} {
  373.     return
  374.     }
  375.     if {[info exists Table_info($fileID.deferred)]} {
  376.     unset Table_info($fileID.deferred)
  377.     }
  378.     if {$fileName == {}} {
  379.     set fileName $Table_info($fileID.fileName)
  380.     }
  381.     unset Table_info($fileID.fileName)
  382.     unset Table_info($fileName.ID)
  383.     ConfigFile:Close $fileID
  384. }
  385. proc Table:DeferWrites {fileID} {
  386.     global Table_info
  387.     set Table_info($fileID.deferred) 1
  388. }
  389. proc Table:ForceWrites {fileID} {
  390.     global Table_info
  391.     if {[info exists Table_info($fileID.deferred)]} {
  392.     unset Table_info($fileID.deferred)
  393.     }
  394.     set Table_info($fileID.modified) 1
  395. proc Table:SetOption {fileID option {value 1}} {
  396.     global Table_options
  397.     set Table_options($fileID.$option) $value
  398. }
  399. proc Table:HasOption {fileID option} {
  400.     return [info exists Table_options($fileID.$option)]
  401. }
  402. proc Table:GetOption {fileID option} {
  403.     global Table_options
  404.     if {![info exists Table_options($fileID.$option)]} {
  405.     return {}
  406.     }
  407.     return $Table_options($fileID.$option)
  408. }
  409. proc Table:Modified {fileID} {
  410.     global Table_info
  411.     if {[info exists Table_info($fileID.modified)]} {
  412.     return $Table_info($fileID.modified)
  413.     } else {
  414.     return 0
  415.     }
  416. }
  417. proc Table:GetLineList {fileID type {idList {}}} {
  418.     upvar #0 Table_${fileID}_$type typeList
  419.     if {![info exists typeList]} {
  420.     return {}
  421.     }
  422.     if {$idList == {}} {
  423.     set idList [array names typeList]
  424.     }
  425.     set lineList {}
  426.     foreach id $idList {
  427.     if {[info exists typeList($id)]} {
  428.         append lineList " $typeList($id)"
  429.     }
  430.     }
  431.     return [lsort -command ConfigFile:Compare $lineList]
  432. }
  433. proc Table:Get {fileID type id {separator {}}} {
  434.     upvar #0 Table_${fileID}_$type typeList
  435.     if {[Table:GetOption $fileID makelower] != {}} {
  436.     set id [string tolower $id]
  437.     }
  438.     set value {}
  439.     if {![info exists typeList($id)]} {
  440.     return $value
  441.     }
  442.     set numLines [llength [Table:GetLineList $fileID $type $id]]
  443.     set thisLine 1
  444.     foreach line $typeList($id) {
  445.     ConfigFile:GetLine $fileID $line dummy dummy data
  446.     if {$thisLine == $numLines} {
  447.         append value "$data"
  448.     } else {
  449.         set data [string trim $data "$separator"]
  450.         append value "$data$separator"
  451.     }
  452.     incr thisLine
  453.     }
  454.     set value [string trimleft $value $separator]
  455.     return $value
  456. }
  457. proc Table:Set {fileID type id data} {
  458.     upvar #0 Table_${fileID}_${type} typeList
  459.     global Table_info
  460.     global Table_lastType Table_lastID
  461.     set name $id
  462.     if {[Table:GetOption $fileID makelower] != {}} {
  463.     set id [string tolower $id]
  464.     }
  465.     if {[info exists typeList($id)]} {
  466.     foreach line $typeList($id) {
  467.         ConfigFile:RemoveLine $fileID $line
  468.     }
  469.     set line [lindex $typeList($id) 0]
  470.     unset typeList($id)
  471.     } else {
  472.     if {[set lineList [Table:GetLineList $fileID $type]] != {}} {
  473.         set line [lindex $lineList end]
  474.     } else {
  475.         if {[Table:GetOption $fileID newFirst] == 1} {
  476.         set line 0
  477.         } else {
  478.         set line -1
  479.         }
  480.     }
  481.     }
  482.     lappend typeList($id) [ConfigFile:AppendLine $fileID $line \
  483.     $type $name data]
  484.     set Table_lastType $type
  485.     set Table_lastID $id
  486.     set Table_info($fileID.modified) 1
  487. }
  488. proc Table:Unset {fileID type id} {
  489.     upvar #0 Table_${fileID}_$type typeList
  490.     global Table_info
  491.     if {[Table:GetOption $fileID makelower] != {}} {
  492.     set id [string tolower $id]
  493.     }
  494.     if {![info exists typeList($id)]} {
  495.     return
  496.     }
  497.     foreach line $typeList($id) {
  498.     ConfigFile:RemoveLine $fileID $line
  499.     }
  500.     unset typeList($id)
  501.     set Table_info($fileID.modified) 1
  502. }
  503. proc Table:AppendLine {fileID type id value {line {}}} {
  504.     global Table_lastType Table_lastID
  505.     global Table_info
  506.     if {$type == "CONTINUATION"} {
  507.     upvar #0 Table_${fileID}_$Table_lastType typeList
  508.     } else {
  509.     upvar #0 Table_${fileID}_$type typeList
  510.     }
  511.     if {[Table:GetOption $fileID makelower] != {}} {
  512.     set id [string tolower $id]
  513.     }
  514.     if {$line == ""} {
  515.     if {[info exists typeList($id)]} {
  516.         set line [lindex $typeList($id) end]
  517.     } else {
  518.         if {[set lineList [Table:GetLineList $fileID $type]] == {}} {
  519.         set line [lindex $lineList end]
  520.         } else {
  521.         if {[Table:GetOption $fileID newFirst] == 1} {
  522.             set line 0
  523.         } else {
  524.             set line -1
  525.         }
  526.         }
  527.     }
  528.     }
  529.     if {$type == "CONTINUATION"} {
  530.     lappend typeList($id) \
  531.         [ConfigFile:AppendLine $fileID $line $type {} value]
  532.     } else {
  533.     lappend typeList($id) \
  534.         [ConfigFile:AppendLine $fileID $line $type $id value]
  535.     }
  536.     set Table_info($fileID.modified) 1
  537. }
  538. proc Table:RemoveLine {fileID type id deleteLine} {
  539.     upvar #0 Table_${fileID}_$type typeList
  540.     global Table_info
  541.     if {[Table:GetOption $fileID makelower] != {}} {
  542.     set id [string tolower $id]
  543.     }
  544.     if {![info exists typeList($id)]} {
  545.     return
  546.     }
  547.     set index 0
  548.     foreach line $typeList($id) {
  549.     if {$line == $deleteLine} {
  550.         lvarpop typeList($id) $index
  551.         ConfigFile:RemoveLine $fileID $line
  552.         break
  553.     }
  554.     incr index
  555.     }
  556.     set Table_info($fileID.modified) 1
  557. }
  558. proc Table:ReplaceLine {fileID type replaceLine id data} {
  559.     global Table_info
  560.     upvar #0 Table_${fileID}_$type typeList
  561.     if {[ConfigFile:GetLine $fileID $replaceLine oldType oldId oldData] == 0} {
  562.     if {$oldId != ""} {
  563.             upvar #0 Table_${fileID}_$oldType oldTypeList
  564.         set index [lsearch -exact $oldTypeList($oldId) $replaceLine]
  565.         if {$index != -1} {
  566.         lvarpop oldTypeList($oldId) $index
  567.         if {[lempty $oldTypeList($oldId)]} {
  568.             unset oldTypeList($oldId)
  569.         }
  570.         }
  571.     }
  572.     }
  573.     ConfigFile:ReplaceLine $fileID $replaceLine $type $id data
  574.     if {$id != ""} {
  575.     if {![info exists typeList($id)]} {
  576.         set typeList($id) {}
  577.     }
  578.     lappend typeList($id) $replaceLine
  579.     }
  580.     set Table_info($fileID.modified) 1
  581. }
  582. proc Table:List {fileID type {ordered 0}} {
  583.     upvar #0 Table_${fileID}_$type typeList
  584.     if {![info exists typeList]} {
  585.     return {}
  586.     }
  587.     if {[Table:GetOption $fileID makelower] == {} && $ordered == 0} {
  588.     return [array names typeList]
  589.     }
  590.     #
  591.     # We have to go get the original ids from before they were converted 
  592.     # to lower case, or they want the ids in the order they appear anyway.
  593.     #
  594.     set returnList {}
  595.     foreach line [Table:GetLineList $fileID $type] {
  596.     ConfigFile:GetLine $fileID $line dummy id dummy
  597.     append returnList " $id"
  598.     }
  599.     return [string trimleft $returnList]
  600. }
  601. proc Map:ReadCB {fileID fp} {
  602.     set context [scancontext create]
  603.     scanmatch $context {^([^#][^     ]*)([     ].*)} {
  604.     Table:ProcessLine $fileID entry $matchInfo(submatch0) \
  605.         $matchInfo(submatch1)
  606.     }
  607.     scanmatch $context {
  608.     Table:ProcessLine $fileID COMMENT {} $matchInfo(line)
  609.     }
  610.     scanfile $context $fp
  611.     scancontext delete $context
  612. }
  613. proc Map:WriteCB {fileID fp type id data} {
  614.     case $type {
  615.     entry {
  616.         puts $fp "${id}${data}"
  617.     }
  618.     COMMENT {
  619.         puts $fp $data
  620.     }
  621.     }
  622. }
  623. proc Map:Open {fileName {mode 0644}} {
  624.     return [Table:Open $fileName Map:ReadCB Map:WriteCB $mode]
  625. }
  626. proc Map:Write {fileID {fileName {}}} {
  627.     return [Table:Write $fileID $fileName]
  628. }
  629. proc Map:ForceWrites {fileID} {
  630.     return [Table:ForceWrites $fileID]
  631. }
  632. proc Map:Get {fileID id} {
  633.     return [string trimleft [Table:Get $fileID entry $id]]
  634. }
  635. proc Map:Set {fileID id data} {
  636.     if {![string match {[     ]*} $data]} {
  637.     set data "    $data"
  638.     }
  639.     return [Table:Set $fileID entry $id $data]
  640. }
  641. proc Map:Unset {fileID id} {
  642.     return [Table:Unset $fileID entry $id]
  643. }
  644. proc Map:List {fileID} {
  645.     set lineOrdered 1
  646.     return [Table:List $fileID entry $lineOrdered]
  647. }
  648. proc Map:Insert {fileID id data idBefore} {
  649.     if {![string match {[     ]*} $data]} {
  650.     set data "    $data"
  651.     }
  652.     # there should really not be duplicate entry ids (keys),
  653.     # but in case a duplicate was hand edited in, we pick the first one
  654.     # as it is the only one that counts in the map file
  655.     set lineBefore [lindex [Table:GetLineList $fileID entry $idBefore] 0]
  656.     # put the new entry after $idBefore
  657.     Table:AppendLine $fileID entry $id $data $lineBefore 
  658. }
  659. proc Map:Modified {fileID} {
  660.     return [Table:Modified $fileID]
  661. }
  662. set appvals(vtApp)    {}        ;# VtOpen return; generally not used 
  663. set appvals(vtMain)    {}        ;# widget string of main dialog
  664. set appvals(toolbar)         1        ;# toolbar
  665. set appvals(toolbarcust)     0        ;# customizable toolbar
  666. set appvals(fieldAdjustment)    0.90
  667. proc UiDefaultFormSpacingSet {form} {
  668.     VtSetValues $form \
  669.         -horizontalSpacing 0 \
  670.         -verticalSpacing 0 \
  671.         -marginWidth 0 \
  672.         -marginHeight 0 
  673. }
  674. proc UiDisplayErrorStackCB {callback cbs} {
  675.     global appvals
  676.     set dialog [keylget cbs dialog]
  677.     VtDestroyDialog $dialog
  678.     SaStatusBarClear [VxGetVar $appvals(vtMain) statusBar]
  679.     if {![lempty $callback]} {
  680.         eval $callback [list $cbs]
  681.     }
  682. }
  683. proc UiDisplayErrorStacks {caller stack {callback ""}} {
  684.     global appvals
  685.     SaDisplayErrorStacks $appvals(vtMain).$caller [list $stack] HELP \
  686.         [list UiDisplayErrorStackCB $callback]
  687. }
  688. proc UiSetAppFocus {} {
  689.     global appvals
  690.     VtSetFocus [VxGetVar $appvals(vtMain) menuBar] 
  691.     if {![lempty [UiMainListGetItems]]} {
  692.         VtSetFocus [VxGetVar $appvals(vtMain) mainList]
  693.     }
  694. }
  695. proc AdjustFieldLength {charLength} {
  696.     global appvals
  697.     set fieldLength [expr $charLength * $appvals(fieldAdjustment)]
  698.     return $fieldLength
  699. }
  700. proc UiMainListSetItems {items} {
  701.     global appvals
  702.     set mainList [VxGetVar $appvals(vtMain) mainList]
  703.     VtDrawnListDeleteItem $mainList -all
  704.     set maxLength [VxGetVar $mainList maxLength]
  705.     ChannelSetMainListLabel $maxLength
  706.     set isCharm [VtInfo -charm]
  707.     set CHARM_formatList [list \
  708.         [list STRING $maxLength 0 2]]
  709.     set MOTIF_formatList [list \
  710.         [list STRING [AdjustFieldLength $maxLength] 0 10]]
  711.     foreach entry $items {
  712.         keylget entry hostName hostName
  713.         keylget entry realName realName
  714.         if {$isCharm} {
  715.             set formatList $CHARM_formatList
  716.         } else {
  717.             set formatList $MOTIF_formatList
  718.         }
  719.         lappend formatList [list STRING [clength $realName]]
  720.         set fieldList [list $hostName $realName]
  721.         VtDrawnListAddItem $mainList \
  722.             -formatList $formatList \
  723.             -fieldList $fieldList
  724.     }
  725. }
  726. proc UiMainListGetItems {} {
  727.     global appvals
  728.     return [VtDrawnListGetItem [VxGetVar $appvals(vtMain) mainList] -all]
  729. }
  730. proc UiMainListCB {cbs} {
  731.     global appvals
  732.     # update selected label and widget sensitivity
  733.     UiUpdateCountLabel
  734.     UiSensitizeMainFunctions
  735. }
  736. proc UiMainListDoubleCB {cbs} {
  737.     UiModifyEntryCB $cbs
  738.     VtUnLock
  739. }
  740. proc UiBuildMainList {form top} {
  741.     global appvals 
  742.     # Build basic main form drawnlist widget including:
  743.     # o Manually built title label for CHARM
  744.     # o Drawnlist record format
  745.     # o traditional Count label beneath the drawn list
  746.     set labelFont medNormalFont
  747.     set mainList [ChannelBuildMainList $form $top]
  748.     VxSetVar $form mainList $mainList
  749.     # Define the accompanying count label
  750.     set countLabel [VtLabel $form.countLabel -label " " \
  751.                 -topSide NONE \
  752.                 -leftSide FORM \
  753.                 -rightSide FORM \
  754.                 -bottomSide FORM \
  755.                 -labelRight]
  756.     VxSetVar $form countLabel $countLabel
  757.     VtSetValues $mainList -bottomSide $countLabel
  758.     # Stash the localized string "Selected" here so we only grab it once
  759.     # from the message catalog
  760.     VxSetVar $countLabel selected [IntlMsg SELECTED]
  761.     # Return the bottom-most widget for further attachments
  762.     return $countLabel
  763. }
  764. proc UiUpdateCountLabel {} {
  765.     global appvals
  766.     set mainList [VxGetVar $appvals(vtMain) mainList]
  767.     set countLabel [VxGetVar $appvals(vtMain) countLabel]
  768.     set numSelected [llength \
  769.         [VtDrawnListGetSelectedItem $mainList -byRecordList]]
  770.         lappend labelArgs [llength [VtDrawnListGetItem $mainList -all]]
  771.         lappend labelArgs $appvals(itemname)
  772.         lappend labelArgs $numSelected
  773.         lappend labelArgs [VxGetVar $countLabel selected]
  774.         set labelValue [IntlMsg COUNT_LABEL_STRING $labelArgs]
  775.     VtSetValues $countLabel -label $labelValue
  776. }
  777. proc UiBuildAddModifyScreen {function} {
  778.     global appvals
  779.     set parent $appvals(vtMain)
  780.     set addModifyScreen [VtFormDialog $parent.addModifyScreen \
  781.         -ok -okLabel [IntlMsg OK] \
  782.         -cancel -cancelLabel [IntlMsg CANCEL] \
  783.         -help -helpLabel [IntlMsg HELP] \
  784.         -cancelButton CANCEL \
  785.         -okCallback AddModifyOkCB \
  786.         -cancelCallback AddModifyCancelCB \
  787.         -wmCloseCallback AddModifyCancelCB \
  788.         -autoLock [list AddModifyOkCB AddModifyCancelCB] ]
  789.     VxSetVar $parent addModifyScreen $addModifyScreen
  790.     set nameForm [VtForm $addModifyScreen.nameForm \
  791.         -marginHeight 0 -marginWidth 0 \
  792.         -leftSide FORM -MOTIF_leftOffset 10 -CHARM_leftOffset 1 \
  793.         -rightSide FORM -MOTIF_rightOffset 10 -CHARM_rightOffset 1 \
  794.         -topSide FORM -topOffset 10 -CHARM_topOffset 1]
  795.     set nameLabel [VtLabel $nameForm.nameLabel \
  796.         -label [IntlMsg NAME_LBL] \
  797.         -labelLeft ]
  798.     set selectNameButton [VtPushButton $nameForm.selectNameButton \
  799.         -label [IntlMsg SELECT_BTN_LBL]\
  800.         -leftSide NONE \
  801.         -rightSide FORM \
  802.         -bottomSide FORM \
  803.         -callback SelectHostCB \
  804.         -autoLock SelectHostCB]
  805.     set nameText [VtText $nameForm.nameText \
  806.         -columns 30  -CHARM_columns 35 \
  807.         -leftSide FORM \
  808.         -rightSide $selectNameButton \
  809.         -alignTop $selectNameButton \
  810.         -shortHelpCallback SaShortHelpCB \
  811.         -shortHelpString [IntlMsg NAME_SH] \
  812.         -callback {SaSetFocus next}]
  813.     VxSetVar $addModifyScreen nameText $nameText
  814.     VxSetVar $addModifyScreen selectNameButton $selectNameButton
  815.     set realNameForm [VtForm $addModifyScreen.realNameForm \
  816.         -marginHeight 0 -marginWidth 0 \
  817.         -leftSide FORM -MOTIF_leftOffset 10 -CHARM_leftOffset 1 \
  818.         -rightSide FORM -MOTIF_rightOffset 10 -CHARM_rightOffset 1 \
  819.         -topSide $nameForm -MOTIF_topOffset 10 -CHARM_topOffset 1]
  820.     set realNameLabel [VtLabel $realNameForm.realNameLabel \
  821.         -label [IntlMsg REAL_NAME_LBL] \
  822.         -labelLeft ]
  823.     set selectRealNameButton [VtPushButton \
  824.                     $realNameForm.selectRealNameButton \
  825.         -label [IntlMsg SELECT_BTN_LBL]\
  826.         -leftSide NONE \
  827.         -rightSide FORM \
  828.         -bottomSide FORM \
  829.         -callback SelectHostCB \
  830.         -autoLock SelectHostCB]
  831.     set realNameText [VtText $realNameForm.realNameText \
  832.         -columns 30 -CHARM_columns 35 \
  833.         -leftSide FORM \
  834.         -rightSide $selectRealNameButton \
  835.         -alignTop $selectRealNameButton \
  836.         -shortHelpCallback SaShortHelpCB \
  837.         -shortHelpString [IntlMsg REAL_NAME_SH] \
  838.         -callback {SaSetFocus next}]
  839.     VxSetVar $addModifyScreen realNameText $realNameText
  840.     VxSetVar $addModifyScreen selectRealNameButton $selectRealNameButton
  841.     set separator [VtSeparator $addModifyScreen.separator \
  842.         -leftSide FORM -leftOffset 0 \
  843.         -rightSide FORM -rightOffset 0 \
  844.         -topSide $realNameForm -MOTIF_topOffset 10 -CHARM_topOffset 1]
  845.     set statusBar [SaStatusBar $addModifyScreen.statusbar 0]
  846.     VtSetValues $separator \
  847.         -bottomSide $statusBar -bottomOffset 0
  848.     if {$function == "add"} {
  849.         VxSetVar $addModifyScreen function add
  850.             VtSetValues $addModifyScreen -title [IntlMsg ADD_TITLE]
  851.     } else {
  852.         VxSetVar $addModifyScreen function modify
  853.             VtSetValues $addModifyScreen -title [IntlMsg MODIFY_TITLE]
  854.     }
  855.     SaSetTabGroups $addModifyScreen [list \
  856.         $nameText \
  857.         $selectNameButton \
  858.         $realNameText \
  859.         $selectRealNameButton]
  860.     set okButton [VtGetValues $addModifyScreen -ok]
  861.     SaSetFocusList $addModifyScreen [list \
  862.         $nameText \
  863.         $realNameText \
  864.         $okButton]
  865.         VtShow $addModifyScreen
  866.     VtSetFocus $nameText
  867.     return $addModifyScreen
  868. }
  869. proc UiBuildSaveConfirmDialog {} {
  870.     global appvals
  871.     set parent $appvals(vtMain)
  872.     # set autoDestroy FALSE, since we want to do cancel
  873.     # on a window manager close, and autoDestroy is not
  874.     # possible in that case
  875.     set saveConfirmDlg [VtQuestionDialog $parent.saveConfirmDlg \
  876.         -title [IntlMsg SAVE_CONFIRM_TITLE] \
  877.         -message [IntlMsg SAVE_CONFIRM_QUERY] \
  878.         -autoDestroy FALSE \
  879.         -okLabel [IntlMsg SAVE_CONFIRM_BTN_YES] \
  880.         -ok -okCallback SaveConfirmOkCB \
  881.         -applyLabel [IntlMsg SAVE_CONFIRM_BTN_NO] \
  882.         -apply -applyCallback SaveConfirmNoCB \
  883.         -cancelLabel [IntlMsg SAVE_CONFIRM_BTN_CANCEL] \
  884.         -cancel -cancelCallback SaveConfirmCancelCB \
  885.         -wmCloseCallback SaveConfirmCancelCB \
  886.         -autoLock [list \
  887.             SaveConfirmOkCB SaveConfirmNoCB SaveConfirmCancelCB]]
  888.     VxSetVar $parent saveConfirm $saveConfirmDlg
  889.     return $saveConfirmDlg
  890. }
  891. proc UiCloseCB {cbs} {
  892.     # Call underlying non-ui module: close that may need additional ui
  893.     if {[ChannelIsModified]} {
  894.         CloseWithUi
  895.         VtUnLock
  896.         return
  897.     }
  898.     UiStop    UiCloseCB2
  899. }
  900. proc UiCloseCB2 {{cbs {}}} {
  901.     # Call underlying non-ui module: close without Ui
  902.     CloseAfterUi
  903. }
  904. proc UiRefreshCB {{cbs {}}} {
  905.     global appvals
  906.     set statusBar [VxGetVar $appvals(vtMain) statusBar]
  907.     set mainList [VxGetVar $appvals(vtMain) mainList]
  908.     SaStatusBarSet $statusBar [IntlMsg REFRESH] 
  909.     Refresh
  910.     # Update count label and widget sensitivity
  911.     UiUpdateCountLabel
  912.     UiSensitizeMainFunctions
  913.     SaStatusBarClear $statusBar
  914.     VtUnLock
  915. }
  916. proc SelectHostOkCB {button cbs} {
  917.         global appvals
  918.         set addModifyScreen [VxGetVar $appvals(vtMain) addModifyScreen]
  919.     set selectNameButton \
  920.         [VxGetVar $addModifyScreen selectNameButton]
  921.     set selectRealNameButton \
  922.         [VxGetVar $addModifyScreen selectRealNameButton]
  923.     set nameText [VxGetVar $addModifyScreen nameText]
  924.     set realNameText [VxGetVar $addModifyScreen realNameText]
  925.     set instance $appvals(selecthost)
  926.     set selection [SaSelectHostGetSelection $instance]
  927.     if {[cequal $button $selectNameButton]} {
  928.         VtSetValues $nameText -value $selection
  929.         VtSetFocus $nameText
  930.     } else {
  931.         VtSetValues $realNameText -value $selection
  932.         VtSetFocus $realNameText
  933.     }
  934.     VtUnLock
  935. }
  936. proc SelectHostCB {cbs} {
  937.     global appvals
  938.     set parent [keylget cbs dialog]
  939.     set whichButton [keylget cbs widget]
  940.     keylset parameters parent $parent
  941.     keylset parameters instance selectHostScreen
  942.     set appvals(selecthost) selectHostScreen
  943.     keylset parameters userproc "SelectHostOkCB $whichButton"
  944.     SaSelectHostDialog $parameters $cbs
  945. }
  946. proc AddModifyCancelCB {cbs} {
  947.     set dialog [keylget cbs dialog]
  948.     VtDestroyDialog $dialog
  949.     VtUnLock
  950.     return
  951. }
  952. proc AddModifyOkCB {cbs} {
  953.     global appvals
  954.     set dialog [keylget cbs dialog]
  955.     set function [VxGetVar $dialog function]
  956.     set nameText [VxGetVar $dialog nameText]
  957.     set realNameText [VxGetVar $dialog realNameText]
  958.     # get the values entered into the widgets
  959.     set newHostName [string trim [VtGetValues $nameText -value]]
  960.     set newRealName [string trim [VtGetValues $realNameText -value]]
  961.     if {[clength $newHostName] == 0 || [ctype space $newHostName]} {
  962.         VtShow [VtErrorDialog $dialog.usererr1 \
  963.             -message [IntlErr NAME_MISSING] \
  964.             -ok]
  965.         VtUnLock
  966.         VtSetFocus $nameText
  967.         return
  968.     }
  969.     if {[regexp {[     ]} $newHostName]} { 
  970.         VtShow [VtErrorDialog $dialog.usererr2 \
  971.             -message [IntlErr NAME_SPACE] \
  972.             -ok]
  973.         VtUnLock
  974.         VtSetFocus $nameText
  975.         return
  976.     }
  977.     if {[clength $newRealName] == 0 || [ctype space $newRealName]} {
  978.         VtShow [VtErrorDialog $dialog.usererr3 \
  979.             -message [IntlErr REAL_NAME_MISSING] \
  980.             -ok]
  981.         VtUnLock
  982.         VtSetFocus $realNameText
  983.         return
  984.     }
  985.     if {[regexp {[     ]} $newRealName]} { 
  986.         VtShow [VtErrorDialog $dialog.usererr4 \
  987.             -message [IntlErr NAME_SPACE] \
  988.             -ok]
  989.         VtUnLock
  990.         VtSetFocus $realNameText
  991.         return
  992.     }
  993.     # set up the new entry
  994.     keylset newEntry hostName $newHostName
  995.     keylset newEntry realName $newRealName
  996.     set mainList [VxGetVar $appvals(vtMain) mainList]
  997.     set selected [VtDrawnListGetSelectedItem $mainList -byRecordList]
  998.     if {$function == "add"} {
  999.         if {[ChannelEntryExists $newHostName]} {
  1000.             VtShow [VtErrorDialog $dialog.usererr5 \
  1001.                 -message [IntlErr NAME_DUPLICATE $newHostName] \
  1002.                 -ok]
  1003.             VtUnLock
  1004.             VtSetFocus $nameText
  1005.             return
  1006.                 }
  1007.         if {[lempty $selected]} {
  1008.             # just put the new entry last
  1009.             set position 0
  1010.             set before [lindex [VtDrawnListGetItem $mainList \
  1011.                         -position 0] 0]
  1012.         } else {
  1013.             # put the new entry after the last selected entry
  1014.             set selectedNum [lindex [VtDrawnListGetSelectedItem \
  1015.                         $mainList -byPositionList] end]
  1016.             set position [expr $selectedNum + 1] 
  1017.             set before [lindex $selected end]
  1018.         }
  1019.         if {[cequal $before ""]} {
  1020.             set beforeEntry ""
  1021.         } else {
  1022.             keylset beforeEntry hostName [lindex $before 0]
  1023.         }
  1024.         # update the data structures
  1025.         ChannelAdd $beforeEntry $newEntry
  1026.     } else {
  1027.         set position [lindex [VtDrawnListGetSelectedItem $mainList \
  1028.                     -byPositionList] 0]
  1029.         set old [lindex $selected 0]
  1030.         set oldHostName [lindex $old 0]
  1031.         set oldRealName [lindex $old 1]
  1032.         if {![cequal [string tolower $newHostName] \
  1033.                  [string tolower $oldHostName]] && \
  1034.             [ChannelEntryExists $newHostName]} {
  1035.             VtShow [VtErrorDialog $dialog.usererr6 \
  1036.                 -message [IntlErr NAME_DUPLICATE $newHostName] \
  1037.                 -ok]
  1038.             VtUnLock
  1039.             VtSetFocus $nameText
  1040.             return
  1041.                 }
  1042.         set modified 0
  1043.         if {![cequal $newHostName $oldHostName] || \
  1044.             ![cequal $newRealName $oldRealName]} {
  1045.             keylset oldEntry hostName $oldHostName
  1046.             keylset oldEntry realName $oldRealName
  1047.             ChannelModify $oldEntry $newEntry
  1048.             set modified 1
  1049.         }
  1050.     }
  1051.     VtDestroyDialog $dialog
  1052.     # update the main drawn list
  1053.     if {$function == "add" || ($function == "modify" && $modified)} {
  1054.         set maxLength [VxGetVar $mainList maxLength]
  1055.         set newLength [clength $newHostName]
  1056.         if {$newLength < $maxLength} {
  1057.             set newLength $maxLength
  1058.         }
  1059.         # For now, we punt on re-drawing the list if the new
  1060.         # host length is larger than the known max length --
  1061.         # this is an expensive operation.
  1062.         if {[VtInfo -charm]} {
  1063.             set formatList [list \
  1064.                 [list STRING $newLength 0 2] \
  1065.                 [list STRING [clength $newRealName]]]
  1066.         } else {
  1067.             set formatList [list \
  1068.                 [list STRING [AdjustFieldLength $newLength] \
  1069.                       0 10] \
  1070.                 [list STRING [clength $newRealName]]]
  1071.         }
  1072.         set fieldList [list \
  1073.             $newHostName \
  1074.             $newRealName]
  1075.         if {$function == "modify"} {
  1076.             VtDrawnListDeleteItem $mainList -position $position
  1077.         }
  1078.         VtDrawnListAddItem $mainList -formatList $formatList \
  1079.                          -fieldList $fieldList \
  1080.                          -position $position
  1081.         VtDrawnListSelectItem $mainList -position $position
  1082.         SaDrawnListShowSelectedItem $mainList
  1083.         UiSensitizeMainFunctions
  1084.         if {"$function" == "add"} {
  1085.             UiUpdateCountLabel
  1086.         }
  1087.     }
  1088.     VtUnLock
  1089.     return
  1090. }
  1091. proc UiAddEntryCB {cbs} {
  1092.     set addScreen [UiBuildAddModifyScreen add]
  1093.     VtUnLock
  1094. }
  1095. proc UiDeleteEntryCB {cbs} {
  1096.     global appvals
  1097.     set list [VxGetVar $appvals(vtMain) mainList]
  1098.     set selectedPositions [VtDrawnListGetSelectedItem $list -byPositionList]
  1099.     set prevTotal [llength [VtDrawnListGetItem $list -all]]
  1100.     set deleteEntries {}
  1101.     foreach item [VtDrawnListGetSelectedItem $list -byRecordList] {
  1102.         keylset entry hostName [lvarpop item]
  1103.         lappend deleteEntries $entry
  1104.     }
  1105.     ChannelDelete $deleteEntries
  1106.     VtDrawnListDeleteItem $list -positionList $selectedPositions
  1107.     set numItemsLeft [llength [VtDrawnListGetItem $list -all]]
  1108.     if {$numItemsLeft > 0} {
  1109.         set first [lindex $selectedPositions 0]
  1110.         set last [lindex $selectedPositions end]
  1111.         set numDeleted [llength $selectedPositions]
  1112.         if {[expr $last - $first + 1] == $numDeleted} {
  1113.             set contiguous 1
  1114.         } else {
  1115.             set contiguous 0
  1116.         }
  1117.         if {$last == $prevTotal && $contiguous} {
  1118.             # select the one above
  1119.             VtDrawnListSelectItem $list -position [expr $first - 1]
  1120.         } else {
  1121.             # select the item that was after the first deleted
  1122.             # (same position number as first deleted was)
  1123.             VtDrawnListSelectItem $list -position $first
  1124.         }
  1125.         SaDrawnListShowSelectedItem $list
  1126.     }
  1127.     UiSensitizeMainFunctions
  1128.     UiUpdateCountLabel
  1129.     VtUnLock
  1130. }
  1131. proc UiModifyEntryCB {cbs} {
  1132.     set dialog [keylget cbs dialog] 
  1133.     set mainList [VxGetVar $dialog mainList]
  1134.     set selected [lindex \
  1135.         [VtDrawnListGetSelectedItem $mainList -byItemList] 0]
  1136.     set modifyScreen [UiBuildAddModifyScreen modify]
  1137.     set nameText [VxGetVar $modifyScreen nameText]
  1138.     set realNameText [VxGetVar $modifyScreen realNameText]
  1139.     VtSetValues $nameText -value [lindex $selected 0]
  1140.     VtSetValues $realNameText -value [lindex $selected 1]
  1141.     VtUnLock
  1142. }
  1143. proc UiMoveUpEntryCB {cbs} {
  1144.     global appvals
  1145.     set list [VxGetVar $appvals(vtMain) mainList]
  1146.     set selectedNum [lindex \
  1147.         [VtDrawnListGetSelectedItem $list -byPositionList] 0]
  1148.     if {$selectedNum == 1} {
  1149.         VtBeep
  1150.         VtUnLock
  1151.         return
  1152.     }
  1153.     set selectedItem [lindex \
  1154.         [VtDrawnListGetItem $list -position $selectedNum] 0]
  1155.     set newPosition [expr $selectedNum - 1]
  1156.     set beforeItem [lindex \
  1157.         [VtDrawnListGetItem $list -position $newPosition] 0]
  1158.     #
  1159.     # Update table data structures
  1160.     #
  1161.     set beforeHostName [lindex $beforeItem 0]
  1162.     keylset entry1 hostName $beforeHostName
  1163.     set hostName [lindex $selectedItem 0]
  1164.     set realName [lindex $selectedItem 1]
  1165.     keylset entry2 hostName $hostName
  1166.     keylset entry2 realName $realName
  1167.     ChannelSwapPosition $entry1 $entry2
  1168.     #
  1169.     # Modify main list widget
  1170.     #
  1171.     # Delete the item selected in the list
  1172.     VtDrawnListDeleteItem $list -position $selectedNum
  1173.     # Add the deleted item back in the new position
  1174.     set maxLength [VxGetVar $list maxLength]    
  1175.     if {[VtInfo -charm]} {
  1176.         set formatList [list \
  1177.             [list STRING $maxLength 0 2] \
  1178.             [list STRING [clength $realName]]]
  1179.     } else {
  1180.         set formatList [list \
  1181.             [list STRING [AdjustFieldLength $maxLength] 0 10] \
  1182.             [list STRING [clength $realName]]]
  1183.     }
  1184.     VtDrawnListAddItem $list -position $newPosition \
  1185.         -fieldList $selectedItem \
  1186.         -formatList $formatList
  1187.     VtDrawnListSelectItem $list -position $newPosition
  1188.     SaDrawnListShowSelectedItem $list
  1189.     VtUnLock
  1190. }
  1191. proc UiMoveDownEntryCB {cbs} {
  1192.     global appvals
  1193.     set list [VxGetVar $appvals(vtMain) mainList]
  1194.     set selectedNum [lindex \
  1195.         [VtDrawnListGetSelectedItem $list -byPositionList] 0]
  1196.     set numItems [llength [VtDrawnListGetItem $list -all]]
  1197.     if {$selectedNum == $numItems} {
  1198.         VtBeep
  1199.         VtUnLock
  1200.         return
  1201.     }
  1202.     set selectedItem [lindex \
  1203.         [VtDrawnListGetItem $list -position $selectedNum] 0]
  1204.     set newPosition [expr $selectedNum + 1]
  1205.     set afterItem [lindex \
  1206.         [VtDrawnListGetItem $list -position $newPosition] 0]
  1207.     #
  1208.     # Update table data structures
  1209.     #
  1210.     set hostName [lindex $selectedItem 0]
  1211.     set realName [lindex $selectedItem 1]
  1212.     keylset entry1 hostName $hostName
  1213.     keylset entry1 realName $realName
  1214.     set afterHostName [lindex $afterItem 0]
  1215.     keylset entry2 hostName $afterHostName
  1216.     ChannelSwapPosition $entry1 $entry2
  1217.     #
  1218.     # Modify main list widget
  1219.     #
  1220.     # Delete the item selected in the list
  1221.     VtDrawnListDeleteItem $list -position $selectedNum
  1222.     # Add the deleted item back in the new position
  1223.     set maxLength [VxGetVar $list maxLength]
  1224.     if {[VtInfo -charm]} {
  1225.         set formatList [list \
  1226.             [list STRING $maxLength 0 2] \
  1227.             [list STRING [clength $realName]]]
  1228.     } else {
  1229.         set formatList [list \
  1230.             [list STRING [AdjustFieldLength $maxLength] 0 10] \
  1231.             [list STRING [clength $realName]]]
  1232.     }
  1233.     VtDrawnListAddItem $list -position $newPosition \
  1234.         -fieldList $selectedItem \
  1235.         -formatList $formatList
  1236.     VtDrawnListSelectItem $list -position $newPosition
  1237.     SaDrawnListShowSelectedItem $list
  1238.     VtUnLock
  1239. }
  1240. proc SaveConfirmOkCB {cbs} {
  1241.     set dialog [keylget cbs dialog]
  1242.     VtDestroyDialog $dialog
  1243.     if {[UiSaveCB {}] != 1} {
  1244.         VtUnLock
  1245.         return
  1246.     } else {
  1247.         VtUnLock
  1248.         UiStop  UiCloseCB2
  1249.     }
  1250. }
  1251. proc SaveConfirmNoCB {cbs} {
  1252.     set dialog [keylget cbs dialog]
  1253.     VtDestroyDialog $dialog
  1254.     VtUnLock
  1255.     UiStop  UiCloseCB2
  1256. }
  1257. proc SaveConfirmCancelCB {cbs} {
  1258.     set dialog [keylget cbs dialog]
  1259.     VtDestroyDialog $dialog
  1260.     VtUnLock
  1261.     return
  1262. }
  1263. proc UiSaveCB {cbs} {
  1264.     global appvals
  1265.     set statusBar [VxGetVar $appvals(vtMain) statusBar]
  1266.     SaStatusBarSet $statusBar [IntlMsg SAVE]
  1267.     if {[ErrorCatch errStack 0 ChannelWrite data]} {
  1268.         VtUnLock
  1269.         UiDisplayErrorStacks UiSaveCB $errStack
  1270.         return 0
  1271.     }
  1272.     SaStatusBarClear $statusBar
  1273.     VtUnLock
  1274.     return 1
  1275. }
  1276. proc UiSensitizeMainFunctions {} {
  1277.     # visit all appropriate menu items:
  1278.     #     VxGetVar
  1279.     #    VtSetsensitive
  1280.     global appvals
  1281.     set mainList [VxGetVar $appvals(vtMain) mainList]
  1282.     set item [VtDrawnListGetSelectedItem $mainList]
  1283.     set selected [llength \
  1284.         [VtDrawnListGetSelectedItem $mainList -byRecordList]]
  1285.     set menuBar [VxGetVar $appvals(vtMain) menuBar]
  1286.     set add [VxGetVar $menuBar add]
  1287.     set delete [VxGetVar $menuBar delete]
  1288.     set modify [VxGetVar $menuBar modify]
  1289.     set moveUp [VxGetVar $menuBar moveUp]
  1290.     set moveDown [VxGetVar $menuBar moveDown]
  1291.     set isCharm [VtInfo -charm]
  1292.     if {!$isCharm} {
  1293.         set toolBar [VxGetVar $appvals(vtMain) toolBar]
  1294.         set addTB [VxGetVar $toolBar addTB]
  1295.         set deleteTB [VxGetVar $toolBar deleteTB]
  1296.         set modifyTB [VxGetVar $toolBar modifyTB]
  1297.         set upTB [VxGetVar $toolBar upTB]
  1298.         set downTB [VxGetVar $toolBar downTB]
  1299.     }
  1300.     if {$selected == 0} {
  1301.         VtSetSensitive $delete 0
  1302.         VtSetSensitive $modify 0
  1303.         VtSetSensitive $moveUp 0
  1304.         VtSetSensitive $moveDown 0
  1305.         if {!$isCharm} {
  1306.             VtSetSensitive $deleteTB 0
  1307.             VtSetSensitive $modifyTB 0
  1308.             VtSetSensitive $upTB 0
  1309.             VtSetSensitive $downTB 0
  1310.         }
  1311.     } elseif {$selected == 1} {
  1312.         VtSetSensitive $delete 1
  1313.         VtSetSensitive $modify 1
  1314.         VtSetSensitive $moveUp 1
  1315.         VtSetSensitive $moveDown 1
  1316.         if {!$isCharm} {
  1317.             VtSetSensitive $deleteTB 1
  1318.             VtSetSensitive $modifyTB 1
  1319.             VtSetSensitive $upTB 1
  1320.             VtSetSensitive $downTB 1
  1321.         }
  1322.     } else {
  1323.         VtSetSensitive $delete 1
  1324.         VtSetSensitive $modify 0
  1325.         VtSetSensitive $moveUp 0
  1326.         VtSetSensitive $moveDown 0
  1327.         if {!$isCharm} {
  1328.             VtSetSensitive $deleteTB 1
  1329.             VtSetSensitive $modifyTB 0
  1330.             VtSetSensitive $upTB 0
  1331.             VtSetSensitive $downTB 0
  1332.         }
  1333.     }
  1334. }
  1335. proc UiStart {} {
  1336.     global appvals
  1337.     # Open/connect to widget server
  1338.     set vtApp [VtOpen $appvals(client) [IntlMsg HELPBOOK]]
  1339.     set appvals(vtApp) $vtApp
  1340.     VtSetAppValues $vtApp \
  1341.                 -errorCallback {SaUnexpectedErrorCB {}}
  1342.     # Create main dialog
  1343.     set vtMain [VtFormDialog $vtApp.main \
  1344.             -title $appvals(title) \
  1345.             -resizable FALSE \
  1346.             -wmShadowThickness 0 \
  1347.             -wmCloseCallback UiCloseCB] 
  1348.     set appvals(vtMain) $vtMain
  1349.     VxSetVar $appvals(vtMain) vtMain $vtMain
  1350.     UiDefaultFormSpacingSet $vtMain
  1351.     SaCharmSetMaxFormDimensions $vtMain
  1352.     # Build pulldown menus
  1353.     set menuBar [UiBuildMenus $vtMain]
  1354.     VxSetVar $appvals(vtMain) menuBar $menuBar
  1355.     # Build the toolbar
  1356.     if {! [VtInfo -charm]} {
  1357.         set toolBar [UiBuildToolBar $vtMain $menuBar]
  1358.     }
  1359.     # Basic drawnlist for channel table entries
  1360.     # Pass main form and widget just above for attachments
  1361.     if {[VtInfo -charm]} {
  1362.         set mainList [UiBuildMainList $vtMain $menuBar]
  1363.     } else {
  1364.         set mainList [UiBuildMainList $vtMain $toolBar]
  1365.     }
  1366.     # Build the status bar with standard SCOadmin status bar pixmap
  1367.     set statusBar [SaStatusBar $vtMain.statusBar 1]
  1368.     VxSetVar $appvals(vtMain) statusBar $statusBar
  1369.     # Connect main screen widget bottom to statusbar
  1370.     VtSetValues $mainList -bottomSide $statusBar
  1371.     # Display the main form and lock it
  1372.     VtShow $vtMain
  1373.     VtLock
  1374. }
  1375. proc UiStop {cb} {
  1376.     global appvals
  1377.     set vtMain $appvals(vtMain)
  1378.     set client $appvals(client)
  1379.     # Store modified preferences
  1380.     # short help
  1381.     set cmd [list SaShortHelpStore $client]
  1382.     if {[ErrorCatch errorStack 0 $cmd dummy] != 0 } {
  1383.         lappend errorStacks $errorStack
  1384.     }
  1385.     # any problems?
  1386.     if [info exists errorStacks] {
  1387.         # present error dialog and enter event-driven Ui loop.
  1388.         # Re-gain procedural control via UiStop2 (part 2) and
  1389.         # eventuall, the caller's cb
  1390.         SaDisplayErrorStacks $vtMain.UIStop $errorStacks {} \
  1391.             [list UiStop2 $cb]
  1392.         VtUnLock
  1393.         VtMainLoop
  1394.     } else {
  1395.         # stop vtcl
  1396.         VtUnLock
  1397.         VtClose
  1398.         # return control to the caller
  1399.         eval $cb
  1400.     }
  1401. }
  1402. proc UiStop2 {cb {cbs {}}} {
  1403.     VtUnLock
  1404.     VtClose
  1405.     # return control to the caller
  1406.     eval $cb
  1407. }
  1408. proc UiBuildMenus {form} {
  1409.     global appvals
  1410.     set helpMenuItemList [list \
  1411.         ON_CONTEXT \
  1412.         ON_WINDOW \
  1413.         ON_KEYS \
  1414.         INDEX \
  1415.         ON_HELP]
  1416.     set menuBar [VtMenuBar $form.menuBar \
  1417.             -helpMenuItemList $helpMenuItemList]
  1418.     VxSetVar $form menuBar $menuBar
  1419.     # Main object menu
  1420.     UiBuildObjectMenu $menuBar
  1421.     # Options menu
  1422.     UiBuildOptionsMenu $menuBar
  1423.     return $menuBar
  1424. }
  1425. proc UiBuildObjectMenu {parent} {
  1426.     global appvals
  1427.     set label $appvals(object) 
  1428.     set mnemonic $appvals(objectmn) 
  1429.     set fileMenu [VtPulldown $parent.fileMenu \
  1430.             -label $label \
  1431.             -mnemonic $mnemonic \
  1432.             ]
  1433.     VxSetVar $parent fileMenu $fileMenu
  1434.     set add [VtPushButton $fileMenu.add \
  1435.         -label [IntlMsg ENTRY_MENU_ADD_LBL] \
  1436.         -mnemonic [IntlMsg ENTRY_MENU_ADD_MN]  \
  1437.         -shortHelpCallback SaShortHelpCB \
  1438.         -shortHelpString [IntlMsg ENTRY_MENU_ADD_SH] \
  1439.         -callback UiAddEntryCB  \
  1440.         -autoLock UiAddEntryCB]
  1441.     VxSetVar $parent add $add
  1442.     set delete [VtPushButton $fileMenu.delete \
  1443.         -label [IntlMsg ENTRY_MENU_DELETE_LBL] \
  1444.         -mnemonic [IntlMsg ENTRY_MENU_DELETE_MN]  \
  1445.         -shortHelpCallback SaShortHelpCB \
  1446.         -shortHelpString [IntlMsg ENTRY_MENU_DELETE_SH] \
  1447.         -callback UiDeleteEntryCB  \
  1448.         -autoLock UiDeleteEntryCB]
  1449.     VxSetVar $parent delete $delete
  1450.     set modify [VtPushButton $fileMenu.modify \
  1451.         -label [IntlMsg ENTRY_MENU_MODIFY_LBL] \
  1452.         -mnemonic [IntlMsg ENTRY_MENU_MODIFY_MN]  \
  1453.         -shortHelpCallback SaShortHelpCB \
  1454.         -shortHelpString [IntlMsg ENTRY_MENU_MODIFY_SH] \
  1455.         -callback UiModifyEntryCB  \
  1456.         -autoLock UiModifyEntryCB]
  1457.     VxSetVar $parent modify $modify
  1458.     VtSeparator $fileMenu.s1
  1459.     set moveUp [VtPushButton $fileMenu.moveUp \
  1460.         -label [IntlMsg ENTRY_MENU_UP_LBL] \
  1461.         -mnemonic [IntlMsg ENTRY_MENU_UP_MN]  \
  1462.         -shortHelpCallback SaShortHelpCB \
  1463.         -shortHelpString [IntlMsg ENTRY_MENU_UP_SH] \
  1464.         -callback UiMoveUpEntryCB  \
  1465.         -autoLock UiMoveUpEntryCB]
  1466.     VxSetVar $parent moveUp $moveUp
  1467.     set moveDown [VtPushButton $fileMenu.moveDown \
  1468.         -label [IntlMsg ENTRY_MENU_DOWN_LBL] \
  1469.         -mnemonic [IntlMsg ENTRY_MENU_DOWN_MN]  \
  1470.         -shortHelpCallback SaShortHelpCB \
  1471.         -shortHelpString [IntlMsg ENTRY_MENU_DOWN_SH] \
  1472.         -callback UiMoveDownEntryCB  \
  1473.         -autoLock UiMoveDownEntryCB]
  1474.     VxSetVar $parent moveDown $moveDown
  1475.     VtSeparator $fileMenu.s2
  1476.     set save [VtPushButton $fileMenu.save \
  1477.         -label [IntlMsg ENTRY_MENU_SAVE_LBL] \
  1478.         -mnemonic [IntlMsg ENTRY_MENU_SAVE_MN]  \
  1479.         -shortHelpCallback SaShortHelpCB \
  1480.         -shortHelpString [IntlMsg ENTRY_MENU_SAVE_SH] \
  1481.         -callback UiSaveCB  \
  1482.         -autoLock UiSaveCB]
  1483.     VxSetVar $parent save $save
  1484.     VtSeparator $fileMenu.s3
  1485.     set exit [VtPushButton $fileMenu.exit \
  1486.         -label [IntlMsg ENTRY_MENU_EXIT_LBL] \
  1487.         -mnemonic [IntlMsg ENTRY_MENU_EXIT_MN]  \
  1488.         -shortHelpCallback SaShortHelpCB \
  1489.         -shortHelpString \
  1490.             [IntlMsg ENTRY_MENU_EXIT_SH \
  1491.                 [list $appvals(title)]] \
  1492.         -callback UiCloseCB  \
  1493.         -autoLock UiCloseCB]
  1494.     VxSetVar $parent exit $exit
  1495. }
  1496. proc UiBuildOptionsMenu {form} {
  1497.     global appvals 
  1498.     # Define the Pulldown itself
  1499.     set optionMenu [VtPulldown $form.optionMenu \
  1500.         -label  [IntlMsg OPTIONS_MENU] \
  1501.         -mnemonic [IntlMsg OPTIONS_MN] \
  1502.         ] 
  1503.     # menu items
  1504.     # short help
  1505.     SaShortHelpLoad $appvals(client)
  1506.     SaShortHelpMenuOptions $optionMenu
  1507.     # toolbar
  1508.     if {$appvals(toolbar) && ![VtInfo -charm]} {
  1509.         UiToolBarBuildMenuOptions $optionMenu
  1510.     }
  1511.     VxSetVar $form optionMenu $optionMenu
  1512.     return $optionMenu
  1513. }
  1514. proc UiToolBarSetVisibilityCB {{cbs {}}} {
  1515.     global appvals
  1516.     set menuBar [VxGetVar $appvals(vtMain) menuBar]
  1517.     set optionMenu [VxGetVar $menuBar optionMenu]
  1518.     set toolBarToggle [VxGetVar $optionMenu toolBarToggle]
  1519.     set visible [VtGetValues $toolBarToggle -value]
  1520.     set toolBar [VxGetVar $appvals(vtMain) toolBar]
  1521.     set toolBarFrame [VxGetVar $appvals(vtMain) toolBarFrame]
  1522.     if {$visible} {
  1523.         # We *must* show the frame first, then the form
  1524.         VtShow $toolBarFrame
  1525.         VtShow $toolBar
  1526.     } else {
  1527.         # We *must* hide the form first, then the frame, in order
  1528.         # to obtain same re-drawing behaviour we get with Sa functions
  1529.         VtHide $toolBar
  1530.         VtHide $toolBarFrame
  1531.     }
  1532.     SaScreenPolicySet $appvals(client) toolbarVisibility $visible
  1533. }
  1534. proc UiToolBarBuildMenuOptions {menu} {
  1535.     global appvals
  1536.     set toolBarToggle [VtToggleButton $menu.toolBarToggle \
  1537.         -label [IntlMsg OPTIONS_TOOLBAR] \
  1538.         -callback UiToolBarSetVisibilityCB \
  1539.         -shortHelpCallback SaShortHelpCB \
  1540.         -shortHelpString [IntlMsg OPTIONS_TOOLBAR_SH] \
  1541.         -value 1]
  1542.     VxSetVar $menu toolBarToggle $toolBarToggle
  1543. }
  1544. proc UiBuildToolBar {form top} {
  1545.     global appvals
  1546.     set toolBarFrame [VtFrame $form.toolBarFrame \
  1547.             -topSide $top \
  1548.             -topOffset 2 \
  1549.             -leftSide FORM \
  1550.             -rightSide FORM \
  1551.             -marginHeight 0 \
  1552.             -marginWidth 0 \
  1553.             -horizontalSpacing 0 \
  1554.             -verticalSpacing 0 \
  1555.             -shadowType IN]
  1556.     set toolBarForm [VtForm $toolBarFrame.toolBarForm \
  1557.             -leftSide FORM \
  1558.             -rightSide FORM \
  1559.             -borderWidth 0 \
  1560.             -marginHeight 0 \
  1561.             -marginWidth 0 \
  1562.             -horizontalSpacing 0 \
  1563.             -verticalSpacing 0]
  1564.     set addTB [VtPushButton $toolBarForm.addTB \
  1565.             -label [IntlMsg TB_ADD] \
  1566.             -topSide FORM \
  1567.             -topOffset 0 \
  1568.             -leftSide FORM \
  1569.             -leftOffset 0 \
  1570.             -rightOffset 0 \
  1571.             -bottomSide FORM \
  1572.             -bottomOffset 0 \
  1573.             -shortHelpCallback SaShortHelpCB \
  1574.             -shortHelpString [IntlMsg ENTRY_MENU_ADD_SH] \
  1575.             -callback UiAddEntryCB \
  1576.             -autoLock UiAddEntryCB]
  1577.     VxSetVar $toolBarForm addTB $addTB
  1578.     set deleteTB [VtPushButton $toolBarForm.deleteTB \
  1579.             -label [IntlMsg TB_DELETE] \
  1580.             -topSide FORM \
  1581.             -leftSide $addTB \
  1582.             -leftOffset 0 \
  1583.             -bottomSide FORM \
  1584.             -bottomOffset 0 \
  1585.             -shortHelpCallback SaShortHelpCB \
  1586.             -shortHelpString [IntlMsg ENTRY_MENU_DELETE_SH] \
  1587.             -callback UiDeleteEntryCB \
  1588.             -autoLock UiDeleteEntryCB]
  1589.     VxSetVar $toolBarForm deleteTB $deleteTB
  1590.     set modifyTB [VtPushButton $toolBarForm.modifyTB \
  1591.             -label [IntlMsg TB_MODIFY] \
  1592.             -topSide FORM \
  1593.             -leftSide $deleteTB \
  1594.             -leftOffset 10 \
  1595.             -bottomSide FORM \
  1596.             -bottomOffset 0 \
  1597.             -shortHelpCallback SaShortHelpCB \
  1598.             -shortHelpString [IntlMsg ENTRY_MENU_MODIFY_SH] \
  1599.             -callback UiModifyEntryCB \
  1600.             -autoLock UiModifyEntryCB]
  1601.     VxSetVar $toolBarForm modifyTB $modifyTB
  1602.     set upTB [VtPushButton $toolBarForm.upTB \
  1603.             -pixmap [IntlMsg BTN_UP_PX] \
  1604.             -topSide FORM \
  1605.             -leftSide $modifyTB \
  1606.             -leftOffset 10 \
  1607.             -bottomSide FORM \
  1608.             -bottomOffset 0 \
  1609.             -shortHelpCallback SaShortHelpCB \
  1610.             -shortHelpString [IntlMsg ENTRY_MENU_UP_SH] \
  1611.             -callback UiMoveUpEntryCB \
  1612.             -autoLock UiMoveUpEntryCB]
  1613.     VxSetVar $toolBarForm upTB $upTB
  1614.     set downTB [VtPushButton $toolBarForm.downTB \
  1615.             -pixmap [IntlMsg BTN_DOWN_PX] \
  1616.             -topSide FORM \
  1617.             -leftSide $upTB \
  1618.             -leftOffset 0 \
  1619.             -rightSide NONE \
  1620.             -bottomSide FORM \
  1621.             -bottomOffset 0 \
  1622.             -shortHelpCallback SaShortHelpCB \
  1623.             -shortHelpString [IntlMsg ENTRY_MENU_DOWN_SH] \
  1624.             -callback UiMoveDownEntryCB \
  1625.             -autoLock UiMoveDownEntryCB]
  1626.     VxSetVar $toolBarForm downTB $downTB
  1627.     VxSetVar $appvals(vtMain) toolBar $toolBarForm
  1628.     VxSetVar $appvals(vtMain) toolBarFrame $toolBarFrame
  1629.     return $toolBarFrame
  1630. }
  1631. proc ChannelGetData {} {
  1632.     global appvals
  1633.     set data {}
  1634.     set maxLength 0
  1635.     foreach key [Map:List $appvals(fileid)] {
  1636.         set hostName $key
  1637.         set hostNameLength [clength $hostName]
  1638.         if {$hostNameLength > $maxLength} {
  1639.             set maxLength $hostNameLength
  1640.         }
  1641.         set value [Map:Get $appvals(fileid) $key]
  1642.         set realName [lvarpop value]
  1643.         keylset entry hostName $hostName
  1644.         keylset entry realName $realName
  1645.         lappend data $entry
  1646.     }
  1647.     set mainList [VxGetVar $appvals(vtMain) mainList]
  1648.     if {$maxLength < 30} {
  1649.         set maxLength 30
  1650.     }
  1651.     VxSetVar $mainList maxLength $maxLength
  1652.     return $data
  1653. }
  1654. proc ChannelDelete {entries} {
  1655.     global appvals
  1656.     foreach entry $entries {
  1657.         set hostName ""
  1658.         keylget entry hostName hostName
  1659.         Map:Unset $appvals(fileid) $hostName
  1660.     }
  1661. }
  1662. proc ChannelAdd {beforeEntry newEntry} {
  1663.     global appvals
  1664.     set newKey ""
  1665.     set newData ""
  1666.     keylget newEntry hostName newKey
  1667.     keylget newEntry realName newData
  1668.     if {$beforeEntry == ""} {
  1669.         # the file was empty !
  1670.         Map:Set $appvals(fileid) $newKey $newData
  1671.     } else {
  1672.         set beforeKey ""
  1673.         keylget beforeEntry hostName beforeKey
  1674.         Map:Insert $appvals(fileid) $newKey $newData $beforeKey
  1675.     }
  1676. }
  1677. proc ChannelModify {oldEntry newEntry} {
  1678.     global appvals
  1679.     keylget newEntry hostName newKey
  1680.     keylget newEntry realName newData
  1681.     keylget oldEntry hostName oldKey
  1682.     if {[cequal $newKey $oldKey]} {
  1683.         Map:Set $appvals(fileid) $newKey $newData
  1684.     } else {
  1685.         Map:Insert $appvals(fileid) $newKey $newData $oldKey
  1686.         Map:Unset $appvals(fileid) $oldKey
  1687.     }
  1688. }
  1689. proc ChannelSwapPosition {entry1 entry2} {
  1690.     global appvals
  1691.     set key1 ""
  1692.     keylget entry1 hostName key1
  1693.     set data1 [Map:Get $appvals(fileid) $key1]
  1694.     set key2 ""
  1695.     keylget entry2 hostName key2
  1696.     Map:Unset $appvals(fileid) $key1
  1697.     Map:Insert $appvals(fileid) $key1 $data1 $key2
  1698. }
  1699. proc ChannelIsModified {} {
  1700.     global appvals
  1701.     if {$appvals(fileid) != -1} {
  1702.         return [Map:Modified $appvals(fileid)]
  1703.     } else {
  1704.         return 0
  1705.     }
  1706. }
  1707. proc ChannelEntryExists {hostname} {
  1708.     global appvals
  1709.     set allKeys [string tolower [Map:List $appvals(fileid)]]
  1710.     if {[lsearch -exact $allKeys [string tolower $hostname]] == -1} {
  1711.         return 0
  1712.     } else {
  1713.         return 1
  1714.     }
  1715. }
  1716. proc ChannelSetMainListLabel {maxHostNameLength} {
  1717.     global appvals
  1718.     set mainList [VxGetVar $appvals(vtMain) mainList]
  1719.     set labelList [list \
  1720.         [IntlMsg COLUMN_HOST_LBL] \
  1721.         [IntlMsg COLUMN_FORWARD_LBL]]
  1722.     if {[VtInfo -charm]} {
  1723.         # add 2 for the right margin width
  1724.         set fieldLength [expr $maxHostNameLength + 2]
  1725.         # For charm, we can't really go beyond 60 chars for the
  1726.                 # hostname portion of the label
  1727.         if {$fieldLength > 60} {
  1728.             set fieldLength 60
  1729.         }
  1730.         set labelFormat "%-${fieldLength}s%-20s"
  1731.         set label [format $labelFormat \
  1732.                         [lindex $labelList 0] \
  1733.                         [lindex $labelList 1]]
  1734.         set header [VxGetVar $appvals(vtMain) header]
  1735.         VtSetValues $header -label $label
  1736.         }
  1737.     # adjust host name length, then add 1 for right margin width
  1738.     set fieldLength [expr [AdjustFieldLength $maxHostNameLength] + 1]
  1739.     set formatList [list \
  1740.         [list STRING $fieldLength 5] \
  1741.         [list STRING 20]]
  1742.     VtSetValues $mainList -labelFormatList $formatList
  1743.     VtSetValues $mainList -labelList $labelList
  1744. }
  1745. proc ChannelBuildMainList {form top} {
  1746.     global appvals
  1747.     if {[VtInfo -charm]} {
  1748.         set labelList [list \
  1749.             [IntlMsg COLUMN_HOST_LBL] \
  1750.             [IntlMsg COLUMN_FORWARD_LBL]]
  1751.         set label [format "%-20s%-20s" \
  1752.             [lindex $labelList 0] \
  1753.             [lindex $labelList 1]]
  1754.         set header [VtLabel $form.header \
  1755.                 -topOffset 1 \
  1756.                 -labelLeft \
  1757.                 -leftSide FORM -leftOffset 1 \
  1758.                 -rightSide FORM \
  1759.                 -topSide $top \
  1760.                 -bottomSide NONE \
  1761.                 -label $label]
  1762.         VxSetVar $form header $header
  1763.         set top $header
  1764.     }
  1765.     set mainList [VtDrawnList $form.mainList \
  1766.             -MOTIF_rows 10 -CHARM_rows 25 \
  1767.             -MOTIF_columns 60 -CHARM_columns 20 \
  1768.             -horizontalScrollBar TRUE \
  1769.             -leftSide FORM \
  1770.             -MOTIF_leftOffset 5 -CHARM_leftOffset 0 \
  1771.             -rightSide FORM \
  1772.             -MOTIF_rightOffset 5 -CHARM_rightOffset 0 \
  1773.             -topSide $top \
  1774.             -MOTIF_topOffset 10 -CHARM_topOffset 0 \
  1775.             -bottomSide NONE \
  1776.             -selection MULTIPLE \
  1777.             -callback ChannelMainListCB \
  1778.             -defaultCallback ChannelMainListDoubleCB \
  1779.             -autoLock {ChannelMainListDoubleCB}]
  1780.     VxSetVar $form mainList $mainList
  1781.     ChannelSetMainListLabel 30
  1782.     return $mainList
  1783. }
  1784. proc ChannelMainListCB {cbs} {
  1785.     UiMainListCB $cbs
  1786. }
  1787. proc ChannelMainListDoubleCB {cbs} {
  1788.     UiMainListDoubleCB $cbs
  1789. }
  1790. proc ChannelInit {} {
  1791.     global appvals
  1792.     set appvals(title)     [IntlMsg TITLE $appvals(filename)]
  1793.     set appvals(object)     [IntlMsg OBJECT]    
  1794.     set appvals(objectmn)    [IntlMsg OBJECT_MN]    
  1795.     set appvals(itemname)    [IntlMsg ITEMS]    
  1796. }
  1797. proc ChannelWrite {} {
  1798.     global appvals
  1799.     global errorInfo
  1800.     #
  1801.     # commit the changes to file
  1802.     #
  1803.     # force a write since Map:Write will only write if modifications
  1804.     # were made
  1805.     Map:ForceWrites $appvals(fileid)
  1806.     if {[ErrorCatch errStack 0 "Map:Write $appvals(fileid)" result]} {
  1807.         ErrorPush errStack 0 [IntlErrId NONSTDCMD] [list $errorInfo]
  1808.         ErrorPush errStack 1 [IntlErrId WRITE] $appvals(filename)
  1809.     }
  1810.     # compile the database
  1811.     set cmd [list exec /etc/mail/makemap hash $appvals(filename) \
  1812.             < $appvals(filename) >& /dev/null]
  1813.     if {[ErrorCatch errStack 0 $cmd result]} {
  1814.         ErrorPush errStack 0 [IntlErrId NONSTDCMD] [list $errorInfo]
  1815.         ErrorPush errStack 1 [IntlErrId DATABASE] $appvals(filename).db
  1816.     }
  1817. }
  1818. set appvals(script) [file tail [info script]]    ;# argv[0]: UNIX command name 
  1819. set appvals(client) $appvals(script)        ;# widget strings, preferences
  1820. set appvals(filename) {}            ;# filename of channel table
  1821. set appvals(fileid) -1                ;# backend file id of table
  1822. set appvals(hostname) localhost            ;# name of host being managed
  1823. proc Exit {{code 0}} {
  1824.     # Final exit tasks
  1825.     exit $code
  1826. }
  1827. proc Usage {} {
  1828.     global appvals
  1829.     set usage [IntlErr USAGE $appvals(script)]
  1830.     puts stderr $usage
  1831. }
  1832. proc ParseCommandLine {} {
  1833.     global argv argc optarg opterr optind appvals
  1834.     # scan for commandline flags
  1835.     set optString    "f:h:"
  1836.     set argc [llength $argv]
  1837.     if {$argc == 0} {
  1838.         Usage; Exit 1
  1839.     }
  1840.     set opterr 0
  1841.     while {[set opt [getopt $argc $argv $optString]] != -1} {
  1842.         switch $opt {
  1843.             {f} {
  1844.                 set appvals(filename) $optarg
  1845.             }
  1846.             {h} {
  1847.                 set appvals(hostname) $optarg
  1848.             }
  1849.             {?} {
  1850.                 Usage; Exit 1
  1851.             }
  1852.         }
  1853.     }
  1854.     set optCount [expr "$argc - $optind"]
  1855.     if {$optCount > 0} {
  1856.         Usage; Exit 1
  1857.     }
  1858.     if {"$appvals(filename)" == ""} {
  1859.         Usage; Exit 1
  1860.     }
  1861. }
  1862. proc Main {} {
  1863.     global appvals errorInfo
  1864.     # Collect command line options
  1865.     ParseCommandLine
  1866.     # Initialize UI, build main form, present initial view
  1867.     # Init a few globals first
  1868.     ChannelInit
  1869.     UiStart
  1870.     # Main UI is now presented and Locked
  1871.     # Time-consuming startup operations can now take place with
  1872.     # optional status messages 
  1873.     #
  1874.     # + collect data to populate main form widgets
  1875.     # + populate main form widgets with live data
  1876.     SaStatusBarSet \
  1877.         [VxGetVar $appvals(vtMain) statusBar] [IntlMsg INIT] 
  1878.     # Show/hide the toolbar, depending on screen policy
  1879.     if {! [VtInfo -charm]} {
  1880.         set cmd "set visibility \[SaScreenPolicyGet $appvals(client) toolbarVisibility\]"
  1881.         if {[ErrorCatch errStack 0 $cmd errMsg] != 0} {
  1882.             set visibility 1
  1883.         }
  1884.         set menuBar [VxGetVar $appvals(vtMain) menuBar]
  1885.         set optionMenu [VxGetVar $menuBar optionMenu]
  1886.         set toolBarToggle [VxGetVar $optionMenu toolBarToggle]
  1887.         set toolBar [VxGetVar $appvals(vtMain) toolBar]
  1888.         set toolBarFrame [VxGetVar $appvals(vtMain) toolBarFrame]
  1889.         VtSetValues $toolBarToggle -value $visibility
  1890.         UiToolBarSetVisibilityCB
  1891.         }
  1892.     # if file does not exist, let the user know
  1893.     if {![file exists $appvals(filename)]} {
  1894.         set main $appvals(vtMain)
  1895.         set dialog [VtInformationDialog $main.exist \
  1896.             -message [IntlMsg FILE_DOESNT_EXIST] \
  1897.             -ok]
  1898.         VtShow $dialog
  1899.     }
  1900.     # if file is a directory, show error and exit
  1901.     if {[file isdirectory $appvals(filename)]} {
  1902.         set main $appvals(vtMain)
  1903.         set dialog [VtErrorDialog $main.error \
  1904.             -message [IntlErr DIRECTORY $appvals(filename)] \
  1905.             -ok -okCallback UiCloseCB -wmCloseCallback UiCloseCB]
  1906.         VtShow $dialog
  1907.         VtUnLock
  1908.         VtMainLoop
  1909.         return
  1910.     }
  1911.     # Open the file and read in the data to back end structures
  1912.     if {[ErrorCatch errStack 0 "Map:Open $appvals(filename)" result]} {
  1913.         ErrorPush errStack 0 [IntlErrId NONSTDCMD] [list $errorInfo]
  1914.         ErrorPush errStack 0 [IntlErrId LOAD] $appvals(filename)
  1915.         VtUnLock
  1916.         UiDisplayErrorStacks Main $errStack UiCloseCB
  1917.     } else {
  1918.         set appvals(fileid) $result
  1919.     }
  1920.     # Refresh main form data
  1921.     UiRefreshCB
  1922.     # Select first item, if exists
  1923.     set mainList [VxGetVar $appvals(vtMain) mainList]
  1924.     if {![lempty [VtDrawnListGetItem $mainList -all]]} {
  1925.         VtDrawnListSelectItem $mainList -position 1
  1926.     }
  1927.     # update the count label
  1928.     UiUpdateCountLabel
  1929.     # Set initial focus (list or menu bar)
  1930.     UiSetAppFocus
  1931.     # Set sensitivity of all main screen ui selection devices
  1932.     UiSensitizeMainFunctions
  1933.     # Setup complete
  1934.     # Wait for user events
  1935.     SaStatusBarClear [VxGetVar $appvals(vtMain) statusBar]
  1936.     VtUnLock
  1937.     VtMainLoop
  1938. }
  1939. proc CloseWithUi {} {
  1940.     set saveConfirmDlg [UiBuildSaveConfirmDialog]
  1941.     VtShow $saveConfirmDlg
  1942. }
  1943. proc CloseAfterUi {} {
  1944.     Exit
  1945. }
  1946. proc Refresh {} {
  1947.     global appvals
  1948.     # Populate main form data here
  1949.     set data {}
  1950.     # TODO
  1951.     # Setup simple example using the "who" module
  1952.     # Except for the following line, Refresh should be generic
  1953.     # and usable as is.
  1954.     # load Ui
  1955.     set data [ChannelGetData]
  1956.     UiMainListSetItems $data
  1957. }
  1958. ErrorTopLevelCatch {Main} $appvals(script)
  1959.