1#!./tclsh
2# $Id: cmdfunc.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $
3# ========================================================================
4# Copyright 2006 University of Washington
5#
6# Licensed under the Apache License, Version 2.0 (the "License");
7# you may not use this file except in compliance with the License.
8# You may obtain a copy of the License at
9#
10#     http://www.apache.org/licenses/LICENSE-2.0
11#
12# ========================================================================
13
14#  cmdfunc.tcl
15#
16#  Purpose:  CGI script to serve as single location for menu/command
17#	     function definitions
18#
19#   OPTIMIZE: have servlet interpreter grok/exec these?
20#
21#  Input:
22
23#  Output:
24#
25
26proc WPTFTitle {{context {some page}} {newmail {}} {nologo 0} {aboutcancel {}}} {
27  global _wp
28
29  cgi_table border=0 cellspacing=0 cellpadding=0 width="100%" class=title  {
30    cgi_table_row {
31      if {!$nologo} {
32	cgi_table_data valign=top align=left height=$_wp(titleheight) {
33
34	  if {[string length $aboutcancel]} {
35	    cgi_put [cgi_url [cgi_imglink smalllogo] wp.tcl?page=help&topic=about&oncancel=$aboutcancel class=navbar target=_top]
36	  } else {
37	    cgi_put [cgi_imglink smalllogo]
38	  }
39	}
40      }
41
42      # work in new mail here
43      if {[llength $newmail]} {
44	cgi_table_data align=center {
45	  WPTFStatusTable $newmail
46	}
47      }
48
49      cgi_table_data align=right valign=middle height=$_wp(titleheight) {
50	cgi_put [cgi_span "style=margin-right: 8; color: $_wp(titlecolor)" "$context"]
51      }
52    }
53  }
54}
55
56proc WPTFStatusTable {msgs {iconlink {0}} {style {}}} {
57  global _wp
58
59  cgi_table width=100% border=0 cellpadding=0 cellspacing=0 $style {
60    cgi_table_row align=right {
61
62      if {[info exists _wp(statusicons)] && $_wp(statusicons)} {
63	set img [cgi_imglink bang]
64	set snd ""
65	foreach m $msgs {
66	  if {[string length [lindex $m 1]]} {
67	    set img [cgi_imglink [lindex $m 1]]
68	    if {$iconlink && [string length [lindex $m 2]]} {
69	      set img [cgi_url $img wp.tcl?page=view&uid=[lindex $m 2] target=body]
70	    }
71
72	    set snd [lindex $m 3]
73	    break
74	  }
75	}
76
77	cgi_table_data {
78	  cgi_puts ${img}${snd}
79	}
80      }
81
82      cgi_table_data align=center class="statustext" {
83	set i 0
84
85	foreach m $msgs {
86
87	  if {[array exists lastmsg] && [info exists lastmsg([lindex $m 0])]} {
88	    incr lastmsg([lindex $m 0])
89	    continue
90	  }
91
92	  if {0 == [string compare [string range [lindex $m 0] 0 20] "Alert received while "]} {
93	    set style "style=border: 1px solid red ; background-color: pink; padding: 2; width: 80%;"
94	  } elseif {!([info exists _wp(statusicons)] && $_wp(statusicons))} {
95	    set style "style=color: white ; background-color: $_wp(menucolor); padding-left:8px; padding-right:8px; white-space: nowrap;"
96	  } else {
97	    set style
98	  }
99
100	  if {$iconlink && [string length [lindex $m 2]] && !([info exists _wp(statusicons)] && $_wp(statusicons))} {
101	    set txt [cgi_url [lindex $m 0] wp.tcl?page=fr_view&uid=[lindex $m 2] target=body "style=text-decoration: none; color: white"]
102	  } else {
103	    set txt [lindex $m 0]
104	  }
105
106	  cgi_division "style=\"padding-bottom: 1px\"" {
107	    cgi_puts [cgi_span $style $txt]
108	  }
109
110	  set lastmsg([lindex $m 0]) 1
111	}
112      }
113
114      if {[info exists _wp(statusicons)] && $_wp(statusicons)} {
115	cgi_table_data align=left {
116	  cgi_puts $img
117	}
118      }
119    }
120  }
121}
122
123
124proc WPTFImageButton {args} {
125  return [cgi_buffer {eval cgi_image_button $args border=0}]
126}
127
128proc WPTFCommandMenu {s_menu c_menu} {
129  global _wp
130
131  set clist {}
132  if {[string length $s_menu]} {
133    upvar $s_menu specificmenu
134    if {[llength $specificmenu]} {
135      lappend clist $specificmenu
136    }
137  }
138
139  if {[string length $c_menu]} {
140    upvar $c_menu commonmenu
141    if {[llength $commonmenu]} {
142      if {[llength $clist]} {
143	lappend clist {}
144      }
145      lappend clist $commonmenu
146    }
147  }
148
149  cgi_table border=0 bgcolor=$_wp(menucolor) cellpadding=0 cellspacing=0 width=112 "style=\"padding: 8 0 8 4\"" {
150    foreach menulist $clist {
151      switch [llength $menulist] {
152	0 {
153	  cgi_table_row {
154	    cgi_table_data {
155	      cgi_hr "width=75%"
156	    }
157	  }
158	}
159	default {
160	  foreach item $menulist {
161	    if {[llength $item] == 0} {
162	      cgi_table_row {
163		cgi_table_data {
164		  cgi_hr "width=75%"
165		}
166	      }
167	      continue
168	    }
169	    if {[llength $item] == 1} {
170	      cgi_table_row {
171		cgi_table_data {
172		  eval [lindex $item 0]
173		}
174	      }
175	      continue
176	    }
177	    if {[string length [lindex $item 0]]} {
178	      if {[uplevel [lindex $item 0]] == 0} {
179		continue
180	      }
181	    }
182
183	    cgi_table_row {
184	      foreach l [lindex $item 1] {
185		cgi_table_data align=left valign=middle class=navbar {
186		  uplevel $l
187		}
188	      }
189	    }
190	  }
191	}
192      }
193    }
194  }
195}
196
197proc WPTFScript {scrpt {dflt ""}} {
198  global _wp
199
200  switch -- $scrpt {
201    main {
202      set src main.tcl
203    }
204    index {
205      set src index.tcl
206      WPCmd PEInfo set wp_body_script $src
207    }
208    view {
209      set src view.tcl
210      WPCmd PEInfo set wp_body_script $src
211    }
212    body {
213      if {[catch {WPCmd PEInfo set wp_body_script} src]} {
214	set src index.tcl
215	catch {WPCmd PEInfo set wp_body_script $src}
216      }
217    }
218    fr_view {
219      set src do_view.tcl
220    }
221    quit {
222      set src fr_queryquit.tcl
223    }
224    folders {
225      set src folders.tcl
226    }
227    fldrbrowse {
228      set src fldrbrowse.tcl
229    }
230    fldrsavenew {
231      set src fldrsavenew.tcl
232    }
233    fldrdel {
234      set src fr_querydelfldr.tcl
235    }
236    compose {
237      set src fr_compose.tcl
238    }
239    addrbrowse {
240      set src fr_addrbrowse.tcl
241    }
242    savebrowse {
243      set src fr_fldrbrowse.tcl
244    }
245    savecreate {
246      set src fr_fldrsavenew.tcl
247    }
248    take {
249      set src fr_take.tcl
250    }
251    takeedit {
252      set src fr_takeedit.tcl
253    }
254    takesame {
255      set src fr_takesame.tcl
256    }
257    ldapbrowse {
258      set src fr_ldapbrowse.tcl
259    }
260    addrbook {
261      set src addrbook.tcl
262    }
263    tconfig {
264      set src tconfig.tcl
265    }
266    cledit {
267      set src cledit.tcl
268    }
269    filtedit {
270      set src filtedit.tcl
271    }
272    conf_process {
273      set src conf_process.tcl
274    }
275    resume {
276      set src fr_resume.tcl
277    }
278    spell {
279      set src fr_spellcheck.tcl
280    }
281    auth {
282      set src fr_queryauth.tcl
283    }
284    expunge {
285      set src fr_queryexpunge.tcl
286    }
287    askattach {
288      set src fr_queryattach.tcl
289    }
290    ldapquery {
291      set src fr_ldapquery.tcl
292    }
293    querycreate {
294      set src fr_querycreate.tcl
295    }
296    queryprune {
297      set src fr_queryprune.tcl
298    }
299    attach {
300      set src attach.tcl
301    }
302    dosend {
303      set src dosend.tcl
304    }
305    docancel {
306      set src docancel.tcl
307    }
308    help {
309      set src fr_help.tcl
310    }
311    split {
312      set src fr_split.tcl
313    }
314    default {
315      if {[regexp {.*\.tcl$} $scrpt s]} {
316	set src $scrpt
317      } elseif {[string length $dflt]} {
318	set src $dflt
319      } else {
320	error "Unrecognized script abbreviation: $scrpt"
321      }
322    }
323  }
324
325  return [file join $_wp(cgipath) $_wp(appdir) $_wp(ui1dir) $src]
326}
327
328proc WPTFSaveDefault {{uid 0}} {
329  # "size" rather than "number" to work around temporary alpined bug
330  if {$uid == 0
331      || [catch {WPCmd PEMessage $uid size} n]
332      || $n == 0
333      || [catch {WPCmd PEMessage $uid savedefault} savedefault]} {
334    if {[WPCmd PEFolder isincoming 0]} {
335      set colid 1
336    } else {
337      set colid 0
338    }
339
340    return [list $colid "saved-messages"]
341  }
342
343  return $savedefault
344}
345
346if {$_wp(keybindings)} {
347  proc WPTFKeyEquiv {kl {exclusions {}} {frame window}} {
348    if {[llength $kl] > 0} {
349      WPStdScripts
350
351      append js "function bindListener(o,f)\{"
352      if {[isW3C]} {
353	append js "o.addEventListener('keypress',f, false);\n"
354	set cancelkeystroke "e.preventDefault(); return false;"
355      } elseif {[isIE]} {
356	append js  "o.onkeydown = f;\n"
357	set cancelkeystroke "return false;"
358      } else {
359	append js  "o.onkeydown = f;"
360	append js  "o.captureEvents(Event.KEYDOWN);\n"
361	set cancelkeystroke "return false;"
362      }
363      append js "\}\n"
364
365      append js "function nobubble(e)\{"
366      if {[isW3C]} {
367	append js " e.stopPropagation();"
368      } elseif {[isIE]} {
369	append js " event.cancelBubble = true;"
370      }
371      append js "\}\n"
372
373      append js  "function keyed(e)\{"
374      if {[isW3C] && [llength $exclusions]} {
375	set ex ""
376	foreach o $exclusions {
377	  if {[string length $ex]} {
378	    append ex " || "
379	  }
380
381	  append ex "e.target == $o"
382	}
383	append js "if (e.target && ($ex)) return true;"
384      }
385      append js  " var c = getKeyStr(e);"
386      append js  " if(getControlKey(e))\{"
387      append js  "  switch(c)\{"
388      append js  "   case 'n' : window.status = 'New window creation disabled in WebPine.' ; $cancelkeystroke"
389      append js  "  \}"
390      append js  " \}"
391      append js  " else"
392      append js  "  switch(c)\{"
393      foreach kb $kl {
394	append js  "  case '[lindex $kb 0]' : ${frame}.webpinelink = 1; [lindex $kb 1] ; $cancelkeystroke"
395      }
396
397      append js  "  \}\}\n"
398
399      set onload "bindListener(document,keyed);"
400
401      if {![isW3C]} {
402	foreach o $exclusions {
403	  append onload "bindListener($o,nobubble);"
404	}
405      }
406
407      cgi_javascript {
408	cgi_puts $js
409      }
410
411      return $onload
412    }
413  }
414}
415
416# add given folder name to the cache of saved-to folders
417proc WPTFAddSaveCache {f_name} {
418  global _wp
419
420  if {[catch {WPSessionState save_cache} flist] == 0} {
421    if {[set i [lsearch -exact $flist $f_name]] < 0} {
422      set flist [lrange $flist 0 [expr {$_wp(save_cache_max) - 2}]]
423    } else {
424      set flist [lreplace $flist $i $i]
425    }
426
427    set flist [linsert $flist 0 $f_name]
428  } else {
429    set flist [list $f_name]
430  }
431
432  catch {WPSessionState save_cache $flist}
433}
434
435# return the list of cached saved-to folders and make sure given
436# default is somewhere in the list
437proc WPTFGetSaveCache {{def_name ""}} {
438
439  if {![string length $def_name]} {
440    set savedef [WPTFSaveDefault 0]
441    set def_name [lindex $savedef 1]
442  }
443
444  set seen ""
445
446  if {[catch {WPSessionState save_cache} flist] == 0} {
447    foreach f $flist {
448      if {[string compare $def_name $f] == 0} {
449	set def_listed 1
450      }
451
452      if {[string length $f] && [lsearch -exact $seen $f] < 0} {
453	lappend options $f
454	lappend options $f
455	lappend seen $f
456      }
457    }
458  }
459
460  if {!([info exists options] && [info exists def_listed])} {
461    lappend options $def_name
462    lappend options $def_name
463  }
464
465  if {[catch {WPCmd set wp_cache_folder} wp_cache_folder]
466      || [string compare $wp_cache_folder [WPCmd PEMailbox mailboxname]]} {
467    # move default to top on new folder
468    switch -- [set x [lsearch -exact $options $def_name]] {
469      0 { }
470      default {
471	if {$x > 0} {
472	  set options [lreplace $options $x [expr {$x + 1}]]
473	}
474
475	set options [linsert $options 0 $def_name]
476	set options [linsert $options 0 $def_name]
477      }
478    }
479
480    catch {WPCmd set wp_cache_folder [WPCmd PEMailbox mailboxname]}
481  }
482
483  lappend options "\[ folder I type in \]"
484  lappend options "__folder__prompt__"
485
486  lappend options "\[ folder in my folder list \]"
487  lappend options "__folder__list__"
488
489  return $options
490}
491
492# add given folder name to the visited folder cache
493proc WPTFAddFolderCache {f_col f_name} {
494  global _wp
495
496  if {$f_col != 0 || [string compare [string tolower $f_name] inbox]} {
497    if {0 == [catch {WPSessionState folder_cache} flist]} {
498
499      if {[catch {WPSessionState left_column_folders} fln]} {
500	set fln $_wp(fldr_cache_def)
501      }
502
503      for {set i 0} {$i < [llength $flist]} {incr i} {
504	set f [lindex $flist $i]
505	if {$f_col == [lindex $f 0] && 0 == [string compare [lindex $f 1] $f_name]} {
506	  break
507	}
508      }
509
510      if {$i >= [llength $flist]} {
511	set flist [lrange $flist 0 $fln]
512      } else {
513	set flist [lreplace $flist $i $i]
514      }
515
516      set flist [linsert $flist 0 [list $f_col $f_name]]
517      # let users of data know it's changed (cheaper than hash)
518      WPScriptVersion common 1
519    } else {
520      catch {unset flist}
521      lappend flist [list $f_col $f_name] [list [WPTFSaveDefault 0]]
522      # ditto
523      WPScriptVersion common 1
524    }
525
526    catch {WPSessionState folder_cache $flist}
527  }
528}
529
530# return the list of cached visited folders and make sure given
531# default is somewhere in the list
532proc WPTFGetFolderCache {} {
533  if {[catch {WPSessionState folder_cache} flist]} {
534    catch {unset flist}
535    lappend flist [WPTFSaveDefault 0]
536    catch {WPSessionState folder_cache $flist}
537  }
538
539  return $flist
540}
541
542proc WPExitOnClose {{frame window}} {
543  global _wp
544
545  cgi_script  type="text/javascript" language="JavaScript" {
546    cgi_put  "function wpLink(){"
547    cgi_put  " ${frame}.webpinelink = 1;"
548    cgi_put  " return true;"
549    cgi_puts "}"
550    cgi_put  "function wpLoad(){"
551    cgi_put  " ${frame}.webpinelink = 0;"
552    cgi_puts "}"
553    cgi_put  "function wpUnLoad(){"
554    cgi_put  " if(!${frame}.webpinelink){"
555    cgi_put  "  window.open('[cgi_root]/$_wp(appdir)/$_wp(ui1dir)/ripcord.tcl?t=10&cid=[WPCmd PEInfo key]','Depart','width=350,height=200');"
556    cgi_put  " }"
557    cgi_puts "}"
558  }
559
560  uplevel 1 {
561
562    # tweak some cgi_* procs for global effect
563    if {0 == [catch {rename cgi_url _wp_orig_cgi_url}]} {
564      proc cgi_url {args} {
565	lappend newargs [lindex $args 0]
566	foreach a [lrange $args 1 end] {
567	  if {[regexp "^(onClick)=(.*)" $a dummy attr str]} {
568	    set onclicked 1
569	    lappend newargs "${attr}=wpLink();${str}"
570	  } else {
571	    lappend newargs $a
572	  }
573	}
574
575	if {![info exists onclicked]} {
576	  lappend newargs "onClick=wpLink();"
577	}
578
579	return [eval "_wp_orig_cgi_url $newargs"]
580      }
581    }
582
583    if {0 == [catch {rename cgi_area _wp_orig_cgi_area}]} {
584      proc cgi_area {args} {
585	lappend newargs [lindex $args 0]
586	foreach a [lrange $args 1 end] {
587	  if {[regexp "^(onClick)=(.*)" $a dummy attr str]} {
588	    set onclicked 1
589	    lappend newargs "${attr}=\"wpLink();${str}\""
590	  } else {
591	    lappend newargs $a
592	  }
593	}
594
595	if {![info exists onclicked]} {
596	  lappend newargs "onClick=\"return wpLink();\""
597	}
598
599	return [eval "_wp_orig_cgi_area $newargs"]
600      }
601    }
602
603    if {0 == [catch {rename cgi_form _wp_orig_cgi_form}]} {
604      proc cgi_form {args} {
605	foreach a [lrange $args 0 [expr [llength $args]-2]] {
606	  if {[regexp "^onSubmit=(.*)" $a dummy str]} {
607	    set onsubmitted 1
608	    lappend newargs "onSubmit=wpLink(); ${str}"
609	  } else {
610	    lappend newargs $a
611	  }
612	}
613
614	if {![info exists onsubmitted]} {
615	  lappend newargs "onSubmit=return wpLink();"
616	}
617
618	lappend newargs [lindex $args end]
619
620	uplevel 1 "_wp_orig_cgi_form $newargs"
621      }
622    }
623  }
624}
625
626proc WPTFIndexWidthRatio {fields field} {
627  # should be formula based on total fields
628  # and number of "wider" fields
629  switch [string toupper $field] {
630    TO			-
631    FROM		-
632    FROMORTO		-
633    FROMORTONOTNEWS	-
634    RECIPS		-
635    SENDER		-
636    SUBJECT		{ return 1.25 }
637    default		{ return 1 }
638  }
639}
640