/usr/lib/exmh/editor.tcl is in exmh 1:2.8.0-5.
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 | #
# editor.tcl --
# Editor interactions
#
# Copyright (c) 1993 Xerox Corporation.
# Use and copying of this software and preparation of derivative works based
# upon this software are permitted. Any distribution of this software or
# derivative works must comply with all applicable United States export
# control laws. This software is made available AS IS, and Xerox Corporation
# makes no warranty about the software, its performance or its conformity to
# any specification.
# Message composing and editor interaction
proc Edit_Init {} {
global mhProfile editor
case $mhProfile(editor) {
{*mxedit* sedit} {set prog $mhProfile(editor)}
default {set prog sedit}
}
Preferences_Add "Editor Support" \
"Exmh has a built-in editor for composing messages, named \"sedit\".
It can also interface to other editors. For non-TK editors like vi
or emacs, preface the editor command with \"exmh-async\" so the editor
runs as a detached process. For TK-aware applications, suffix the
command with an & so your editor detaches into the background. In
this case the first argument to the editor is the name of the exmh
interpreter, and the second argument is the draft file name.
If your editor knows how to post a message directly, preface
the command with \"give-away\". The emacsclient and gnuclient
cases listed in the examples below are special cases of this.
If you want to pass a -geo argument to your program, you need to
wrap it up to prevent exmh-async from grabbing it. See the last
example below.
Example commands include:
sedit
mxedit
emacsclient &
give-away emacsclient
gnuclient &
give-away gnuclient
exmh-async emacs
exmh-async emacsclient
exmh-async xterm -e vi
exmh-async xterm {-geom 80x44+0+0} -e vi" \
[list \
[list editor(prog) editCmd $prog {Editor command} \
"The editor command used to compose mail messages.
The filename will be appended to the command."] \
[list editor(alternate) edit2Cmd {exmh-async emacs} {2nd Editor command} \
"This is an alternate editor command. For example, if your default
editor is sedit, you might want to drop into emacs for a particular
message. The filename will be appended to the command."] \
[list editor(autowhom) autoWhom ON {Auto Whom} \
"Enabling this causes whom to be invoked automatically whenever a
What Now? dialog is displayed."] \
[list editor(sedit!) seditOverride OFF {Sedit override} \
"Use this to override the regular editor command and
use the built-in editor instead. This parameter is set
initially by the command line -sedit switch."] \
[list editor(async_sedit) seditAfterAsync OFF {Use Sedit after Async} \
"If enabled, after editing with external editor, exmh will bring the message
up in sedit. This is so you can initially create the message with your
favorite editor, and then pop into to sedit for richtext or attachments."] \
[list editor(mhn) mhnCmd "mhn" {MHN command} \
"The mhn command specifies a program used to reformat
a message with the MH mhn program.
The filename will be appended to the command."] \
]
set editor(sedit) sedit
}
proc Edit_Draft {} {
global mhProfile exmh
# Run the editor on the current draft
set draftID [Mh_Cur $mhProfile(draft-folder)]
if {$draftID == {}} {
Exmh_Status "No current message in Draft-Folder $mhProfile(draft-folder)" error
return
}
EditWhatNow $draftID prog
}
proc Edit_DraftID { id } {
global exmh
# No mucking with context. We normally get here by-passing the
# standard draft creation process. Hence we need to set exmh($id,action)
set exmh($id,action) auto
EditWhatNow $id prog
}
proc EditDraftFolderHook { f what } {
# Called when we change to the drafts folder
Buttons_DraftMode 1
}
proc EditDraftFolderCleanup { f what } {
Buttons_DraftMode 0
}
# Throw up a dialog asking whether user wants to
# send, re-edit, save as draft, abort.
# As with the command line whatnowproc, this also starts up the
# editor on the draft.
proc EditWhatNow {draftID {edittype prog}} {
global mhProfile editor
if {([string compare $edittype prog] == 0) && $editor(sedit!)} {
set edittype sedit ;# sedit override
}
Exmh_Debug EditWhatNow $draftID $edittype
if ![regexp {^[0-9]+$} $draftID] {
# Must be a message in a non-drafts folder
set path $mhProfile(path)/$draftID
} else {
# Delete ".orig" file if it exists, Mhn_* thanks to Colm Buckley
Mhn_DeleteOrig $draftID
set path [Mh_Path $mhProfile(draft-folder) $draftID]
}
if [EditStart $path $edittype] {
# Editor has run synchronously, so we go right into the dialog
Edit_Dialog $draftID
}
global exmh
if {[string compare $exmh(folder) $mhProfile(draft-folder)] == 0} {
# It isn't safe to leave a current message active in the drafts
# folder because a second edit can loose changes in the first.
# User saves a draft.
# User changes to draft folder.
# The "Send" button uses the saved draft, and they make edits.
# Another "Send" button hit resets the draft to their last save,
# but they probably expected to start a new draft.
Msg_ClearCurrent
}
}
# The following can be invoked by remote editor interpreters
proc Edit_Dialog {draftID} {
global exmh mhProfile editor
Exmh_Debug Edit_Dialog $draftID
if {$editor(async_sedit)} {
Sedit_Start $mhProfile(path)/$mhProfile(draft-folder)/$draftID
} else {
EditShowDialog $draftID "What should I do with draft $draftID?"
}
}
# For compatibility with old versions of mxedit
proc EditDialog {draftID} {
Edit_Dialog $draftID
}
# Turn passphrase pane ON/OFF/disabled depending on pgp(seditpgp) and
# pgp(keeppass)
proc EditMaybeAddPhrasePane {id w} {
global pgp
if {!$pgp(enabled)} {
return
}
set dismsg "Disabled since passphrases are not being kept."
if {$pgp(seditpgp)} {
# Need to add pane
if {[lsearch [pack slaves $w] $w.pgp] < 0} {
EditAddPassPhrasePane $id $w
}
# Just in case the user is playing with pgp(keeppass) value
if {$pgp(echopass)} {
$w.pgp.e configure -show * -state normal
} else {
$w.pgp.e configure -show {} -state normal
}
if {![string compare $pgp(cur,pass,$id) $dismsg]} {
set pgp(cur,pass,$id) {}
}
} else {
# Need to take away the pane (if it is there)
if {[lsearch [pack slaves $w] $w.pgp] >= 0} {
destroy $w.pgp
}
}
if {!$pgp(keeppass) && [lsearch [pack slaves $w] $w.pgp] >= 0} {
# Need to disable the pane (if it is there)
set pgp(cur,pass,$id) $dismsg
$w.pgp.e configure -show {} -state disabled
}
}
proc EditAddPassPhrasePane {id w} {
global pgp
if {$pgp(enabled) && $pgp(seditpgp)} {
# seditpgp main area
Pgp_SetSeditPgpName $pgp($pgp(version,$id),myname,$id) $id
set pgp(fullName,$id) $pgp($pgp(version,$id),fullName)
if {![winfo exists $w.pgp]} {
pack [frame $w.pgp] -side bottom -fill x -ipady 2
}
if {![winfo exists $w.pgp.l1]} {
pack [label $w.pgp.l1 -text "Passphrase for "] \
-side left
}
if {![winfo exists $w.pgp.b]} {
pack [button $w.pgp.b -textvariable pgp(sedit_label,$id) \
-command "Pgp_SetMyName \$pgp(version,$id) $id"] \
-side left -ipady 2
}
if {![winfo exists $w.pgp.l2]} {
pack [label $w.pgp.l2 -text ": "] \
-side left
}
if {![winfo exists $w.pgp.e]} {
pack [entry $w.pgp.e -textvariable pgp(cur,pass,$id)] \
-side left -expand yes -fill x -ipady 2
if {$pgp(echopass)} {
$w.pgp.e configure -show *
}
}
# Add extras if requested
if {$pgp(seditpgpextras)} {
if {![winfo exists $w.pgp2]} {
pack [frame $w.pgp2] -side bottom -fill x
}
if {![winfo exists $w.pgp2.l1]} {
pack [label $w.pgp2.l1 -textvariable pgp(sedit_label2,$id)] -side left
}
}
}
}
proc EditShowDialog {id text} {
global exwin editor pgp
# Create the buttons and arrange them from left to right in the RH
# frame. Embed the left button in an additional sunken frame to indicate
# that it is the default button.
if [Exwin_Toplevel .edit$id "What Now?" WhatNow nomenu] {
set d .edit$id
wm transient $d
$d config -relief raised -borderwidth 2
# PGP version-setting moved out from seditpgp code
if {$pgp(enabled)} {
if {![info exists pgp($pgp(version,$id),myname,$id)]} {
set pgp($pgp(version,$id),myname,$id) $pgp($pgp(version,$id),myname)
}
EditMaybeAddPhrasePane $id $d
}
foreach but [Widget_GetButDef $d] {
Widget_AddButDef $d $but {right}
Widget_ReEvalCmd $d.$but ;# expand $id variable now
}
catch {pack $d.abort -padx 15}
catch {pack $d.send -ipady 5 -ipadx 5 -padx 5}
foreach M [Widget_GetMenuBDef $d] {
set menu [Widget_AddMenuBDef $d $M {right padx 1}]
ButtonMenuInner $menu ;# This also expands variables
}
# Make sure only valid entries are enabled in version submenu
# otherwise things may fail in post-processing.
# We don't have to take care of the active entry since
# preferences only allows valid entries as initial version
if {$pgp(enabled)} {
set submenu $d.more.m.encrypt.version
for {set sm 0} {$sm<=[$submenu index last]} {incr sm} {
if [catch {$submenu entrycget $sm -value} v] {
continue
}
if {[info exists pgp($v,enabled)] && \
!$pgp($v,enabled) } {
$submenu entryconfigure $sm -state disabled
}
}
}
Widget_Message $d msg -text "$text\nReturn for Send\nControl-c for Kill" -aspect 400
focus $d
bind $d <Return> [list $d.send invoke]
bind $d <Control-c> [list $d.abort invoke]
Visibility_Wait .edit$id
Exmh_Focus
} else {
set d .edit$id
catch {destroy $d.f} ;# Whom results
EditMaybeAddPhrasePane $id $d
}
if $editor(autowhom) {
EditDialogDone whom $id nohide
}
}
proc EditDialogMsg {id msg} {
set d .edit$id
catch {destroy $d.f}
Widget_Frame $d f
pack $d.f -before [lindex [pack slaves $d] 0] -side bottom
set lines [llength [split $msg \n]]
Widget_Text $d.f [expr {$lines > 8 ? 8 : $lines}]
$d.f.t insert 1.0 $msg
$d.f.t config -state disabled -width 40
}
proc EditDialogDone {act id {hide hide}} {
if [string match hide $hide] {
Exwin_Dismiss .edit$id nosize
}
Edit_Done $act $id {}
}
proc EditStart { draft {type prog} } {
# Start the editor, reusing an existing session if possible
global editor exmh mhProfile pgp install
Exmh_Debug EditStart $draft $type
if $pgp(enabled) {
# Copy the default PGP values into this window only if they
# don't already exists. This way, we preserve values between
# re-edit sessions. Edit_Done takes care of resetting to
# preference values when we send or abort (ie. get done draft).
set id [SeditId $draft]
foreach var {encrypt sign format version} {
if ![info exists pgp($var,$id)] {
set pgp($var,$id) $pgp($var)
}
}
}
switch -glob -- $editor($type) {
*mxedit* {
if ![info exists exmh(editInterp)] {
set exmh(editInterp) "mxedit"
}
if ![info exists exmh(mxeditVersion)] {
if ![catch {send $exmh(editInterp) {set mxVersion}} vers] {
set exmh(mxeditVersion) $vers
}
}
set id "$exmh(editInterp) $draft"
if [info exists exmh(mxeditVersion)] {
if {$exmh(mxeditVersion) >= 2.4} {
global env
if [regsub $env(HOME) $draft ~ newpath] {
set id "$exmh(editInterp) $newpath"
}
}
}
Exmh_Debug mxReset $id
if [catch {send $id mxReset}] {
if [catch {send $exmh(editInterp) {set mxVersion}}] {
Exmh_Status "Starting mxedit..." warn
# Start the editor and tell it to make a callback
# that identifies the TCL interpreter in the editor
eval exec $editor($type) {-globalCmd [list mxSendInterpName [winfo name .] Edit_Ident] $draft &}
} else {
Exmh_Status "Opening mxedit..." warn
catch {send $exmh(editInterp) [list mxOpen $draft]}
}
} else {
Exmh_Status "Reopening mxedit..." warn
catch {send $id {wm deiconify .}}
}
return 0 ;# Asynchronous edit
}
sedit {
Sedit_Start $draft
return 0 ;# Asynchronous edit
}
exmh-async* {
global wish argv0
Exmh_Status "Starting ASYNC $editor($type) ..." warn
eval {exec $wish -f $install(dir,bin)/exmh-async -- [winfo name .]} \
[lrange $editor($type) 1 end] {$draft &}
return 0 ;# Asynchronous edit
}
give-away* -
gnuclient*& -
emacsclient*& {
set cmd $editor($type) ;# Tcl 7.0 bug in regsub
regsub ^give-away $cmd {} cmd
set cmd [string trimright $cmd "& \t"]
Exmh_Status "Starting $cmd ..." warn
if [catch {eval exec $cmd $draft &} err] {
Exmh_Status $err error
}
return 0 ;# Asynchronous edit
}
*& {
Exmh_Status "Starting TK $editor($type) ..." warn
set cmd [string trimright $editor($type) "& \t"]
if [catch {eval exec $cmd \"[winfo name .]\" $draft &} err] {
Exmh_Status $err error
}
return 0 ;# Asynchronous edit
}
default {
Exmh_Status "Starting $editor($type) ..." warn
if [catch {eval exec $editor($type) $draft} err] {
Exmh_Status $err error
}
return 1 ;# Synchronous edit
}
}
}
# The following is invoked via "send" by mxedit when it
# starts up the first time in order to identify itself to us.
proc Edit_Ident { interpName } {
global exmh
set exmh(editInterp) $interpName
}
# The following is invoked by remote editor interpreters
proc EditDone {act msg argu} {
Edit_Done $act $msg $argu
}
proc Edit_Done {act {msg cur} argu} {
# Commit or abort an edit session
global mhProfile exmh env editor pgp
if {$msg == "cur"} {
set msg [Mh_Cur $mhProfile(draft-folder)]
if {$msg == {}} {
Exmh_Status "No current draft"
return
}
}
Exmh_Debug Edit_Done action = $act msg = $msg
if ![regexp {^[0-9]+$} $msg] {
# Message not in the drafts folder
set path $mhProfile(path)/$msg
}
case $act in {
send {
Aliases_CheckPoint
if [info exists path] {
# Copy message to drafts folder
set id [file tail [Mh_Path $mhProfile(draft-folder) new]]
Exmh_Status "Copying $msg to draft $id"
MhExec comp +[file dirname $msg] [file tail $msg] -nowhatnowproc
set msg $id
}
set anno [Mh_AnnoEnviron $msg]
Exmh_Debug Edit_Done send: anno=$anno
Exmh_Debug "Mh_Send [time {set code [catch {Mh_Send $msg $argu} err2]}]"
if $code {
# move the orig message back to the draft if it exists
Mhn_RenameOrig $msg
Exmh_Status $err2 error
Send_Error $err2 $msg
return
}
if {$exmh(folder) == $mhProfile(draft-folder)} {
# Clean up scan listing
if [catch {Msg_RemoveById $msg} err] {
Exmh_Debug Msg_RemoveById $msg $err
}
}
Exmh_Status "Draft $msg sent" normal
# Delete "orig" message if it exists
Mhn_DeleteOrig $msg
Quote_Cleanup
if {$anno} {
if {[string compare $exmh($msg,folder) $exmh(folder)] == 0} {
foreach lineno [Ftoc_FindMsgs $exmh($msg,mhmessages)] {
Exmh_Debug Edit_Done lineno=$lineno
if {$lineno != {}} {
Ftoc_RescanLine $lineno dash
}
}
}
}
Mh_AnnoCleanup $msg
if $pgp(enabled) {
# Done with this draft, set PGP defaults for next call
set id [SeditId $msg]
foreach var {encrypt sign format version} {
set pgp($var,$id) $pgp($var)
}
}
}
reedit {
Exmh_Status " "
# Rename the orig message back to the draft
Mhn_RenameOrig $msg
EditWhatNow $msg prog
}
sedit {
Exmh_Status " "
EditWhatNow $msg sedit
}
alternate {
Exmh_Status " "
EditWhatNow $msg alternate
}
spell {
Exmh_Status " "
EditWhatNow $msg spell
}
mhn {
# If the orig file exists, move it back to the draft
Mhn_RenameOrig $msg
if [info exists path] {
set env(mhdraft) $path
} else {
set env(mhdraft) [Mh_Path $mhProfile(draft-folder) $msg]
}
if [catch {exec $editor(mhn) $env(mhdraft)} err] {
EditDialogMsg $msg "MHN failed: $err"
} else {
EditDialogMsg $msg "MHN returned a-o.k."
}
}
abort {
if ![info exists path] {
catch {Mh_Rmm $mhProfile(draft-folder) $msg}
Mhn_DeleteOrig $msg
if {$exmh(folder) == $mhProfile(draft-folder)} {
# Clean up scan listing
if [catch {Msg_RemoveById $msg} err] {
Exmh_Debug Msg_RemoveById $msg $err
}
}
Exmh_Status "Draft $msg aborted" error
Quote_Cleanup
Mh_AnnoCleanup $msg
if $pgp(enabled) {
# Done with this draft, set PGP defaults for next call
set id [SeditId $msg]
foreach var {encrypt sign format version} {
set pgp($var,$id) $pgp($var)
}
}
}
}
dismiss {
Exmh_Status "Draft $msg dismissed" normal
Quote_Cleanup
Mhn_RenameOrig $msg
Mh_AnnoCleanup $msg
}
whom {
Mh_AnnoEnviron $msg
if [info exists path] {
catch {Mh_Whom $path} result
} else {
catch {Mh_Whom $msg} result
}
EditDialogMsg $msg $result
}
default {
Exmh_Error "Unknown action in Edit_Done"
}
}
}
|